Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add sound code for mech and driver station #1

Open
wants to merge 21 commits into
base: crol-mechs
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
plugins {
id "java"
id "edu.wpi.first.GradleRIO" version "2023.2.1"
id "edu.wpi.first.GradleRIO" version "2023.4.3"
}

sourceCompatibility = JavaVersion.VERSION_11
Empty file modified gradlew
100644 → 100755
Empty file.
17 changes: 17 additions & 0 deletions src/main/deploy/How_To_Run_DS.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
To run the sound system on the 2023 Haunted House:

1. Plug the 3.5mm audio cable into the speaker and the audio jack on the driverstation computer.
2. Save 'driverstation_script.py' and 'explosion_sound.wav' to a directory on the driverstation computer.
3. If python3 is not installed, install it.
4. If desired (such as if running on non-GRT computer), create a virtual environment (venv) with python3.
5. Install pygame and pynetworktables:
Run 'python3 -m pip install pynetworktables' to install the module needed for networktables comms.
Run 'python3 -m pip install pygame' to install the module needed for sound playback.
6. Once on robot WiFi, trigger the python3 script:
either by entering 'python3 <filepath/driverstation_script.py>
or using the editor's run function (e.g. VSCode run)
7. Script should print an initialization confirmation.
8. When triggered via networktables on robot, code should play audio file.

Troubleshooting:
1. Change 'debug' variable to True in code to print out trigger value constantly (to check if values are being received).
33 changes: 33 additions & 0 deletions src/main/deploy/driverstation_script.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# BEFORE RUNNING THIS:
# run 'python3 -m pip install pynetworktables' to install the module needed for networktables comms
# run 'python3 -m pip install pygame' to install the module needed for sound playback

from networktables import NetworkTables # <--- this will raise an error when in the java env, create a python venv on DS and run this there
import pygame

NetworkTables.initialize(server='10.1.92.2')

audio_table = NetworkTables.getTable("audio")

pygame.mixer.init()
sound = pygame.mixer.Sound('explosion_sound.wav')

old_trigger_value = 0.0
debug = False

print("GRT HH Driverstation script initialized and running.")

while True:
trigger_value = audio_table.getNumber("trigger_audio", -1.0)
if debug:
print("Trigger value received: ", trigger_value)

if old_trigger_value == 0.0 and trigger_value == 1.0:
sound.play()

old_trigger_value = trigger_value





3 changes: 0 additions & 3 deletions src/main/deploy/example.txt

This file was deleted.

Binary file added src/main/deploy/explosion_sound.wav
Binary file not shown.
20 changes: 11 additions & 9 deletions src/main/java/frc/robot/RobotContainer.java
Original file line number Diff line number Diff line change
@@ -4,6 +4,8 @@

package frc.robot;

import frc.robot.subsystems.AryaMech;
import frc.robot.subsystems.LukeMech;
import frc.robot.subsystems.SolenoidMech;
import edu.wpi.first.wpilibj.PneumaticsControlModule;

@@ -21,21 +23,21 @@ public class RobotContainer {
private final SolenoidMech vivienMech;
private final SolenoidMech seanMech;
private final SolenoidMech riyaMech;
private final SolenoidMech christineMech;
private final SolenoidMech gregMech;
private final SolenoidMech williamMech;

private final LukeMech lukeMech;
private final AryaMech aryaMech;


/** The container for the robot. Contains subsystems, OI devices, and commands. */
public RobotContainer() {
christineMech = new SolenoidMech(pcm1.makeSolenoid(0), 5, 5);
gregMech = new SolenoidMech(pcm1.makeSolenoid(4), 5, 5);
williamMech = new SolenoidMech(pcm1.makeSolenoid(5), 5, 5);
seanMech = new SolenoidMech(pcm2.makeSolenoid(0), 5, 5);
riyaMech = new SolenoidMech(pcm2.makeSolenoid(1), 5, 5);
vivienMech = new SolenoidMech(pcm2.makeSolenoid(2), 5, 5);
// Configure the trigger bindings
gregMech = new SolenoidMech(pcm1.makeSolenoid(4), 20, 20);
williamMech = new SolenoidMech(pcm1.makeSolenoid(7), 3, 3, .5);
seanMech = new SolenoidMech(pcm2.makeSolenoid(0), 1.5, 6);
riyaMech = new SolenoidMech(pcm2.makeSolenoid(2), 7.5, 14);
vivienMech = new SolenoidMech(pcm2.makeSolenoid(4), 2, 5);
lukeMech = new LukeMech(pcm1.makeSolenoid(5), pcm1.makeSolenoid(6));
aryaMech = new AryaMech(pcm1.makeSolenoid(0), pcm1.makeSolenoid(1), pcm1.makeSolenoid(2));
}

}
128 changes: 128 additions & 0 deletions src/main/java/frc/robot/subsystems/AryaMech.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package frc.robot.subsystems;

import javax.swing.text.StyledEditorKit.BoldAction;

import edu.wpi.first.wpilibj.Solenoid;
import edu.wpi.first.wpilibj.Timer;
import edu.wpi.first.wpilibj.util.Color;
import edu.wpi.first.wpilibj2.command.SubsystemBase;
import frc.robot.subsystems.leds.LEDLayer;
import frc.robot.subsystems.leds.LEDStrip;
import edu.wpi.first.networktables.DoublePublisher;
import edu.wpi.first.networktables.NetworkTable;
import edu.wpi.first.networktables.NetworkTableInstance;

public class AryaMech extends SubsystemBase{
private Timer timer;
private Solenoid shortSolenoid;
private Solenoid longSolenoid;
private final Solenoid ledStrip;

private double SHORT_OUT = 40;
private double END = SHORT_OUT + 16;
private double FLASH_INTERVAL = 0.15;
private double SHORT_INTERVAL_IN = 0.2;
private double SHORT_INTERVAL_OUT= 2.0;


private boolean out;

NetworkTableInstance inst;
NetworkTable table;
DoublePublisher audioPub;
private Timer audio_timer;
private final double time_to_wait_before_turning_off_audio_signal;
private boolean s40 = false;
private boolean s41 = false;
private boolean s42 = false;
private boolean s46 = false;
private boolean led = false;


private Timer ledTimer;
private Timer pumpTimer;

public AryaMech(Solenoid shortSolenoid, Solenoid longSolenoid, Solenoid ledStrip){
this.shortSolenoid = shortSolenoid;
this.longSolenoid = longSolenoid;
this.ledStrip = ledStrip;

inst = NetworkTableInstance.getDefault();
table = inst.getTable("audio");
audioPub = table.getDoubleTopic("trigger_audio").publish();
audio_timer = new Timer();
audio_timer.start();
pumpTimer = new Timer();
time_to_wait_before_turning_off_audio_signal = 1.0;

ledTimer = new Timer();

timer = new Timer();
timer.start();
pumpTimer.start();

out = true;

}

public void periodic() {
//skeleton pumps thing to set off tnt

if(timer.get() < SHORT_OUT && pumpTimer.advanceIfElapsed(out ? SHORT_INTERVAL_IN : SHORT_INTERVAL_OUT)){
shortSolenoid.set(out);
out = !out;
}

if(timer.hasElapsed(SHORT_OUT) && !s40){
shortSolenoid.set(true);
s40 = true;
}
if(timer.hasElapsed(SHORT_OUT + 1.7) && !s41){
shortSolenoid.set(false);
s41 = true;
}

// audioPub.set(1.0); // this publishes the trigger signal to networktables, which gets picked up by the driverstation python script
if(timer.hasElapsed(SHORT_OUT + 2) && !s42){
audioPub.set(1.0); // Set the value on networktables to zero so we don't restart the audio
ledTimer.reset();
ledTimer.start();
s42 = true;
}

if(timer.hasElapsed(SHORT_OUT + 6) && !s46){
longSolenoid.set(true);
s46 = true;
}

if(timer.hasElapsed(SHORT_OUT + 7) && ledTimer.advanceIfElapsed(FLASH_INTERVAL)){
System.out.println("asdfasdf");
led = !led;
ledStrip.set(led);
} else if (timer.hasElapsed(SHORT_OUT + 4) && ledTimer.advanceIfElapsed(FLASH_INTERVAL * 3)){
System.out.println("asdfasdf");
led = !led;
ledStrip.set(led);
} else if (timer.hasElapsed(SHORT_OUT + 2) && ledTimer.advanceIfElapsed(FLASH_INTERVAL * 5)){
System.out.println("asdfasdf");
led = !led;
ledStrip.set(led);
}

if (timer.advanceIfElapsed(END)){
longSolenoid.set(false);
ledStrip.set(false);
s40 = false;
s41 = false;
s42 = false;
s46 = false;
ledTimer.stop();
audioPub.set(0.0);
}
// if(audio_timer.advanceIfElapsed(.05)){
// System.out.println(((int) (timer.get() * 10)) / 10. + " SHORT: " + shortSolenoid.get() + " LONG: " + longSolenoid.get() + " LED:" + led);
// }

}

}
78 changes: 78 additions & 0 deletions src/main/java/frc/robot/subsystems/LukeMech.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package frc.robot.subsystems;

import edu.wpi.first.hal.FRCNetComm.tInstances;
import edu.wpi.first.wpilibj.Solenoid;
import edu.wpi.first.wpilibj.Timer;
import edu.wpi.first.wpilibj2.command.SubsystemBase;

public class LukeMech extends SubsystemBase{
private Timer timer;
private Solenoid verSolenoid;
private Solenoid horSolenoid;

private double vertUp;
private double vertDown;
private double horOut;
private double horIn;
private int state = 0;
private int oldState = 3;


public LukeMech(Solenoid verSolenoid, Solenoid horSolenoid){
this.verSolenoid = verSolenoid;
this.horSolenoid = horSolenoid;

//ik this looks sus but its for ease of change
vertUp = 7;
horOut = 5;
horIn = 3;
vertDown = 3;

timer= new Timer();
timer.start();

}

public void periodic() {

if((state == 1 || state == 2) && !verSolenoid.get()){
state = 0;
}


if(timer.hasElapsed(vertUp) && state == 0){
verSolenoid.set(true);
state = 1;
timer.reset();
timer.start();
}
else if (timer.hasElapsed(horOut) && state == 1){
if(verSolenoid.get()){
horSolenoid.set(true);
}
state = 2;
timer.reset();
timer.start();
}
else if (timer.hasElapsed(horIn) && state == 2){
if(verSolenoid.get()){
horSolenoid.set(false);
}
state = 3;
timer.reset();
timer.start();
}
else if (timer.hasElapsed(vertDown) && state == 3){
if(!horSolenoid.get()){
verSolenoid.set(false);
}
state = 0;
timer.reset();
timer.start();
}

// System.out.println((((int) (timer.get() * 10)) / 10.) +" " + state + "," + verSolenoid.get() + " , " + horSolenoid.get());


}
}
19 changes: 13 additions & 6 deletions src/main/java/frc/robot/subsystems/SolenoidMech.java
Original file line number Diff line number Diff line change
@@ -4,18 +4,16 @@

package frc.robot.subsystems;

import edu.wpi.first.wpilibj.PneumaticsControlModule;
import edu.wpi.first.wpilibj.PneumaticsModuleType;
import edu.wpi.first.wpilibj.Solenoid;
import edu.wpi.first.wpilibj.Timer;
import edu.wpi.first.wpilibj2.command.CommandBase;
import edu.wpi.first.wpilibj2.command.SubsystemBase;

public class SolenoidMech extends SubsystemBase {

private double uptime;
private double downtime;
private double randomness = 0.0;
private double randomnessUp = 0.0;
private double randomnessDown = 0.0;
private Timer timer;
private Solenoid solenoid;

@@ -30,7 +28,14 @@ public SolenoidMech(Solenoid solenoid, double uptime, double downtime) {

public SolenoidMech(Solenoid solenoid, double uptime, double downtime, double randomness) {
this(solenoid, uptime, downtime);
this.randomness = randomness;
this.randomnessUp = randomness;
this.randomnessDown = randomness;
}

public SolenoidMech(Solenoid solenoid, double uptime, double downtime, double randomnessUp, double randomnessDown) {
this(solenoid, uptime, downtime);
this.randomnessUp = randomnessUp;
this.randomnessDown = randomnessDown;
}


@@ -41,7 +46,9 @@ public SolenoidMech(Solenoid solenoid, double uptime, double downtime, double ra
public void periodic() {
if(timer.advanceIfElapsed(timeUntilNextEvent)){
up = !up;
timeUntilNextEvent = (up ? uptime : downtime) * (1 + (Math.random() * 2 - 1) * randomness);
// Time is random in the range [uptime - uptime * randomnesesUp, uptime + uptime * randomnessUp] if switching to up
// or [downtime - downtime * randomnesesDown, downtime + downtime * randomnessDown] if switching to down
timeUntilNextEvent = (up ? uptime * (1 + (Math.random() * 2 - 1) * randomnessUp) : downtime * (1 + (Math.random() * 2 - 1) * randomnessDown)) ;
}

solenoid.set(up);
76 changes: 76 additions & 0 deletions src/main/java/frc/robot/subsystems/leds/LEDLayer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package frc.robot.subsystems.leds;

import edu.wpi.first.wpilibj.util.Color;

public class LEDLayer {
private final Color[] ledArray;

public LEDLayer(int length) {
ledArray = new Color[length];
}

/**
* Sets an LED at a specified index.
* @param i The LED index to set.
* @param color The color to set the LED at index i to (null is equivalent to transparent).
*/
public void setLED(int i, Color color) {
ledArray[i] = color;
}

/**
* Gets the color of an LED at a specified index.
* @param i The LED index to retrieve.
* @return The color of the LED at index i.
*/
public Color getLED(int i) {
return ledArray[i];
}

/**
* Moves the leds up by an increment
* @param inc the number of leds to move up by
* @param color the color to set at the bottom
*/
public void incrementColors(int inc, Color color) {
for (int i = 0; i < ledArray.length - inc; i++) {
setLED(i, getLED(i + inc));
}
for (int i = ledArray.length - inc; i < ledArray.length; i++) {
setLED(i, color);
}
}

/**
* Fills the layer with a solid color.
* @param color The color to fill the layer with.
*/
public void fillColor(Color color) {
for (int i = 0; i < ledArray.length; i++) {
setLED(i, color);
}
}

/**
* Fills the layer with alternating groups of "on" and "off" LEDs. "off" leds are set to null (transparent).
* @param onGroupLength The length of the "on" group.
* @param offGroupLength The length of the "off" group.
* @param color The color to set the "on" LEDs.
*/
public void fillGrouped(int onGroupLength, int offGroupLength, Color color) {
for (int i = 0; i < ledArray.length; i++) {
if (i % (onGroupLength + offGroupLength) < onGroupLength) {
setLED(i, color);
} else {
setLED(i, null);
}
}
}

/**
* Resets the layer by setting all LEDs to null (transparent).
*/
public void reset() {
fillColor(null);
}
}
38 changes: 38 additions & 0 deletions src/main/java/frc/robot/subsystems/leds/LEDStrip.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package frc.robot.subsystems.leds;

import edu.wpi.first.wpilibj.AddressableLED;
import edu.wpi.first.wpilibj.AddressableLEDBuffer;

public class LEDStrip {
private final AddressableLED led;
private final AddressableLEDBuffer ledBuffer;

private int ledLength;

public LEDStrip(int ledPort, int ledLength) {
this.ledLength = ledLength;
led = new AddressableLED(ledPort);
ledBuffer = new AddressableLEDBuffer(ledLength);
led.setLength(ledBuffer.getLength());
led.start();
}

/**
* Sets the LED data to the current buffer.
*/
public void setBuffer() {
led.setData(ledBuffer);
}

/**
* Applies an `LEDLayer` on top of the LED buffer.
* @param layer The layer to be added on top of the buffer. Null leds are considered transparent and "fall through" to the previous layer's color.
*/
public void addLayer(LEDLayer layer) {
for (int i = 0; i < ledLength; i++) {
if (layer.getLED(i) != null) {
ledBuffer.setLED(i, layer.getLED(i));
}
}
}
}
180 changes: 180 additions & 0 deletions src/main/java/frc/robot/subsystems/leds/LEDSubsystem.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
// package frc.robot.subsystems.leds;

// import edu.wpi.first.math.MathUtil;
// import edu.wpi.first.wpilibj.Timer;
// import edu.wpi.first.wpilibj.util.Color;
// import edu.wpi.first.wpilibj2.command.SubsystemBase;
// import frc.robot.util.TrackingTimer;


// public class LEDSubsystem extends SubsystemBase {
// private final LEDStrip ledStrip;
// private final LEDLayer baseLayer;
// private final LEDLayer manualColorLayer;
// private final LEDLayer aprilDetectedLayer;
// private final LEDLayer colorSensorLayer;
// private final LEDLayer heldPieceLayer;

// private final Timer blinkTimer;
// private static final double BLINK_DURATION_SECONDS = 0.5;
// private static final double BLINK_OFF_TO_ON_RATIO = 4;
// private static final Color BLINK_COLOR = new Color(0, 0, 0);
// private boolean blinking = false;


// private final Timer fadeTimer = new Timer();
// private static final double COLOR_SENSOR_FADE_PERIOD_SECONDS = .5;
// private boolean colorSensorOff = false;

// private static final double BRIGHTNESS_SCALE_FACTOR = 0.25;
// private static final double INPUT_DEADZONE = 0.35;
// private static final int LEDS_PER_SEC = 150;

// private Color manualColor = new Color(0, 0, 0);
// private boolean risingEdge = false;
// private boolean fallingEdge = false;
// private Color RISING_EDGE_COLOR = new Color(0, 0, 255);
// private Color FALLING_EDGE_COLOR = new Color(255, 0, 0);
// private Timer heldPieceTimer = new Timer();

// private boolean manual = false; // If the driver is directly controlling leds
// public boolean pieceGrabbed = false;

// private static final Color APRIL_COLOR = scaleDownColorBrightness(new Color(252, 255, 236));
// private static final Color CUBE_COLOR = scaleDownColorBrightness(new Color(192, 8, 254));
// private static final Color CONE_COLOR = scaleDownColorBrightness(new Color(255, 100, 0));
// private static final Color COLOR_SENSOR_OFF_COLOR = scaleDownColorBrightness(new Color(255, 0, 0));

// private final Timer ledTimer; // TODO: better naming

// private final int LED_LENGTH = 0;
// private final int LED_PWM_PORT = 0;

// public LEDSubsystem() {
// ledStrip = new LEDStrip(LED_PWM_PORT, LED_LENGTH);

// baseLayer = new LEDLayer(LED_LENGTH);
// manualColorLayer = new LEDLayer(LED_LENGTH);
// aprilDetectedLayer = new LEDLayer(LED_LENGTH);
// colorSensorLayer = new LEDLayer(LED_LENGTH);
// heldPieceLayer = new LEDLayer(LED_LENGTH);

// blinkTimer = new Timer();
// ledTimer = new Timer();
// ledTimer.start();
// }

// @Override
// public void periodic() {
// // Start blink timer loop if we are holding a piece
// if (pieceGrabbed) {
// blinkTimer.start();
// } else {
// blinking = false;
// blinkTimer.stop();
// blinkTimer.reset();
// }

// // Toggle the blink boolean every duration to swap the LEDs between the driver piece color
// // and the blink color.
// if (blinkTimer.advanceIfElapsed(BLINK_DURATION_SECONDS)) blinking = !blinking;

// // Number of leds to increment each continuous led layer by
// int inc = Math.min((int) Math.ceil(ledTimer.get() * LEDS_PER_SEC), LED_LENGTH);
// ledTimer.reset();
// ledTimer.start();

// // Update baseLayer - the piece color indicated by the mech driver, or the blink color if a piece
// // is held and we are blinking.
// Color baseColor = blinking ? BLINK_COLOR : pieceColor;
// baseLayer.fillColor(baseColor);

// // Update manualColorLayer - the manual color set by the mech driver in manual mode.
// if (manual) {
// manualColorLayer.incrementColors(inc, manualColor);
// } else {
// manualColorLayer.reset();
// }

// if(fallingEdge){
// heldPieceLayer.fillColor(FALLING_EDGE_COLOR);
// heldPieceTimer.reset();
// heldPieceTimer.start();
// } else if (risingEdge){
// heldPieceLayer.fillColor(RISING_EDGE_COLOR);
// heldPieceTimer.reset();
// heldPieceTimer.start();
// } else if (heldPieceTimer.hasElapsed(1)){
// heldPieceLayer.fillColor(null);
// }

// // Update colorSensorLayer - pulsing red grouped indicators to indicate a color sensor failure.
// if (colorSensorOff) {
// fadeTimer.start();
// colorSensorLayer.fillGrouped(
// 5, 10,
// crossFadeWithTime(COLOR_SENSOR_OFF_COLOR, baseColor, fadeTimer.get(), COLOR_SENSOR_FADE_PERIOD_SECONDS)
// );
// } else {
// fadeTimer.stop();
// fadeTimer.reset();
// colorSensorLayer.reset();
// }

// // Update aprilDetectedLayer - white pulses to indicate an april tag detection.
// if (!aprilBlinkTimer.hasElapsed(APRIL_BLINK_DURATION_SECONDS) && aprilBlinkTimer.hasStarted()) {
// aprilDetectedLayer.incrementColors(inc, APRIL_COLOR);
// } else {
// aprilDetectedLayer.incrementColors(inc, null);
// }

// // Add layers to buffer, set leds
// ledStrip.addLayer(baseLayer);
// ledStrip.addLayer(manualColorLayer);
// ledStrip.addLayer(heldPieceLayer);
// ledStrip.addLayer(colorSensorLayer);
// ledStrip.addLayer(aprilDetectedLayer);
// ledStrip.setBuffer();
// }

// /**
// * Toggles whether drivers are manually controlling the color of the LEDs.
// */
// public void toggleManual() {
// this.manual = !manual;
// }

// /**
// * Cross-fades between two colors using a sinusoidal scaling function.
// * @param color The color to set.
// * @param fadeColor The color to fade into.
// * @param currentTimeSeconds The current elapsed time of fading.
// * @param periodSeconds The period of the fade function, in seconds.
// * @return The scaled and faded color.
// */
// private static Color crossFadeWithTime(Color color, Color fadeColor, double currentTimeSeconds, double periodSeconds) {
// // The [0.0, 1.0] brightness scale to scale the color by. Scale = 1/2 * cos(t) + 1/2 where
// // t is scaled to produce the desired period.
// double scale = 0.5 * Math.cos(currentTimeSeconds * 2 * Math.PI / periodSeconds) + 0.5;

// return new Color(
// color.red * scale + fadeColor.red * (1 - scale),
// color.green * scale + fadeColor.green * (1 - scale),
// color.blue * scale + fadeColor.blue * (1 - scale)
// );
// }

// /**
// * Scales a color's brightness by the BRIGHTNESS_SCALE_FACTOR.
// * @param color The color to scale down.
// * @return The scaled down color.
// */
// private static Color scaleDownColorBrightness(Color color) {
// return new Color(
// color.red * BRIGHTNESS_SCALE_FACTOR,
// color.green * BRIGHTNESS_SCALE_FACTOR,
// color.blue * BRIGHTNESS_SCALE_FACTOR
// );
// }

// }