From 2b522cfe722ac58e6b130df1d7dbae8d1ca3a8d4 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Thu, 18 Apr 2024 18:21:48 +0300 Subject: [PATCH 01/43] move tests into folders --- .../java/{ => subsystem_tests/arm_tests}/IntakeTests.java | 4 +++- .../wrapper_tests}/ColorSensorV3WrapperTests.java | 2 ++ .../wrapper_tests}/SparkMAXWrapperTest.java | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) rename src/test/java/{ => subsystem_tests/arm_tests}/IntakeTests.java (96%) rename src/test/java/{ => subsystem_tests/wrapper_tests}/ColorSensorV3WrapperTests.java (96%) rename src/test/java/{ => subsystem_tests/wrapper_tests}/SparkMAXWrapperTest.java (94%) diff --git a/src/test/java/IntakeTests.java b/src/test/java/subsystem_tests/arm_tests/IntakeTests.java similarity index 96% rename from src/test/java/IntakeTests.java rename to src/test/java/subsystem_tests/arm_tests/IntakeTests.java index ad8b5bc..10714e0 100644 --- a/src/test/java/IntakeTests.java +++ b/src/test/java/subsystem_tests/arm_tests/IntakeTests.java @@ -1,3 +1,5 @@ +package subsystem_tests.arm_tests; + import static org.junit.jupiter.api.Assertions.assertEquals; import com.revrobotics.CANSparkMax; @@ -61,7 +63,7 @@ void testIntakeForcePushes() { ColorSensorV3Wrapped.setRGBD(2500, 0, 0, 900); intakeSubsystem.setIntakeSpeed(0.5, 0, true); // force push note out assertEquals(0.5, intakeMotor.get(), 0.001, "Intake Motor Should Run when force pushed"); - Timer.delay(0.1); + Timer.delay(0.15); // if broken, increase this assertEquals(0.5, intakeMotor.get(), 0.001, "Intake motor should continue to run when forced"); } diff --git a/src/test/java/ColorSensorV3WrapperTests.java b/src/test/java/subsystem_tests/wrapper_tests/ColorSensorV3WrapperTests.java similarity index 96% rename from src/test/java/ColorSensorV3WrapperTests.java rename to src/test/java/subsystem_tests/wrapper_tests/ColorSensorV3WrapperTests.java index 9053ff8..6cac260 100644 --- a/src/test/java/ColorSensorV3WrapperTests.java +++ b/src/test/java/subsystem_tests/wrapper_tests/ColorSensorV3WrapperTests.java @@ -1,3 +1,5 @@ +package subsystem_tests.wrapper_tests; + import static org.junit.jupiter.api.Assertions.assertEquals; import edu.wpi.first.hal.HAL; diff --git a/src/test/java/SparkMAXWrapperTest.java b/src/test/java/subsystem_tests/wrapper_tests/SparkMAXWrapperTest.java similarity index 94% rename from src/test/java/SparkMAXWrapperTest.java rename to src/test/java/subsystem_tests/wrapper_tests/SparkMAXWrapperTest.java index b099f97..74ed670 100644 --- a/src/test/java/SparkMAXWrapperTest.java +++ b/src/test/java/subsystem_tests/wrapper_tests/SparkMAXWrapperTest.java @@ -1,3 +1,5 @@ +package subsystem_tests.wrapper_tests; + import static org.junit.jupiter.api.Assertions.assertEquals; import edu.wpi.first.hal.HAL; From a825852806b96f8c752e016f9e91842a59de6ace Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Thu, 18 Apr 2024 18:54:06 +0300 Subject: [PATCH 02/43] add led tests --- .../led_integration_tests/LedTests.java | 133 ++++++++++++++++++ src/test/java/utils/LEDTestUtils.java | 19 +++ 2 files changed, 152 insertions(+) create mode 100644 src/test/java/subsystem_tests/led_integration_tests/LedTests.java create mode 100644 src/test/java/utils/LEDTestUtils.java diff --git a/src/test/java/subsystem_tests/led_integration_tests/LedTests.java b/src/test/java/subsystem_tests/led_integration_tests/LedTests.java new file mode 100644 index 0000000..bbcc079 --- /dev/null +++ b/src/test/java/subsystem_tests/led_integration_tests/LedTests.java @@ -0,0 +1,133 @@ +package subsystem_tests.led_integration_tests; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static utils.LEDTestUtils.checkForColorInAll; +import static utils.LEDTestUtils.getColorAtIndex; + +import edu.wpi.first.hal.HAL; +import edu.wpi.first.wpilibj.Timer; +import edu.wpi.first.wpilibj.util.Color; +import frc.robot.subsystems.LEDSubsystem; +import frc.robot.subsystems.LEDSystem; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class LedTests { + private LEDSubsystem ledSubsystem; + + @BeforeEach + public void setUp() { + HAL.initialize(500, 0); + ledSubsystem = LEDSystem.getInstance(); + } + + @AfterEach + public void tearDown() { + // ledSubsystem is closed by `LEDSystem.resetLEDSubsystem()` + LEDSystem.resetLEDSubsystem(); + } + + private void testUntilPercentage(double percentage) { + ledSubsystem.fillPercentageWithColor(percentage, Color.kWhite); + Timer.delay(0.1); // wait until command gets executed + for (int i = 0; i < ledSubsystem.getLedCount(); i++) { + if (i < (int) (ledSubsystem.getLedCount() * percentage)) { + assertEquals( + Color.kWhite, + getColorAtIndex(ledSubsystem, i), + "Color Should be the specified one until " + percentage); + } else { + assertEquals( + Color.kBlack, + getColorAtIndex(ledSubsystem, i), + "Color Should be Black after the specified percentage"); + } + } + } + + @Test + void testFill() { + ledSubsystem.fill(Color.kWhite); + Timer.delay(0.05); // let the loop change all the colors + for (int i = 0; i < ledSubsystem.getStrip().getLedCount(); i++) { + assertEquals( + Color.kWhite, + getColorAtIndex(ledSubsystem, i), + "Color Should be the same as filled color at led " + i); + } + } + + @Test + void testBlink() { + ledSubsystem.blink(Color.kWhite, 0.5); + Timer.delay(0.1); + checkForColorInAll( + ledSubsystem, Color.kWhite, "Starting color should have been the the color specified"); + Timer.delay(0.5); // wait for led's to close back down + checkForColorInAll( + ledSubsystem, Color.kBlack, "Color should have turned to black in blinking sequence"); + Timer.delay(0.5); + checkForColorInAll( + ledSubsystem, Color.kWhite, "Color should have turned back to the color specified"); + } + + @Test + void testBlinkRed() { + ledSubsystem.blinkRed(); + Timer.delay(0.1); + checkForColorInAll(ledSubsystem, Color.kRed, "Color should be red before blink"); + Timer.delay(0.2); + checkForColorInAll( + ledSubsystem, Color.kBlack, "Color should have turned to black in blinking sequence"); + Timer.delay(0.2); + checkForColorInAll(ledSubsystem, Color.kRed, "Color should have turned back to red"); + } + + @Test + void testFillPercentage() { + testUntilPercentage(0.1); + tearDown(); + + setUp(); + testUntilPercentage(0.2); + tearDown(); + + setUp(); + testUntilPercentage(0.3); + tearDown(); + + setUp(); + testUntilPercentage(0.4); + tearDown(); + + setUp(); + testUntilPercentage(0.6); + tearDown(); + + setUp(); + testUntilPercentage(0.7); + tearDown(); + + setUp(); + testUntilPercentage(0.8); + tearDown(); + + setUp(); + testUntilPercentage(0.9); + // Auto Teardown + } + + @Test + void testStatusFills() { + ledSubsystem.setStatusColor(false); + Timer.delay(0.1); + checkForColorInAll(ledSubsystem, Color.kRed, "Color Should be red when status is false"); + tearDown(); + + setUp(); + ledSubsystem.setStatusColor(true); + Timer.delay(0.1); + checkForColorInAll(ledSubsystem, Color.kGreen, "Color should be green when status is true"); + } +} diff --git a/src/test/java/utils/LEDTestUtils.java b/src/test/java/utils/LEDTestUtils.java new file mode 100644 index 0000000..e6c949b --- /dev/null +++ b/src/test/java/utils/LEDTestUtils.java @@ -0,0 +1,19 @@ +package utils; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import edu.wpi.first.wpilibj.util.Color; +import frc.robot.subsystems.LEDSubsystem; + +public class LEDTestUtils { + public static void checkForColorInAll( + LEDSubsystem ledSubsystem, Color colorItShouldBe, String message) { + for (int i = 0; i < ledSubsystem.getLedCount(); i++) { + assertEquals(colorItShouldBe, getColorAtIndex(ledSubsystem, i), message); + } + } + + public static Color getColorAtIndex(LEDSubsystem ledSubsystem, int index) { + return ledSubsystem.getStrip().getBuffer().getLED(index); + } +} From b3d156f9f1f2480fa25fb6b3f4c50e8c4dd81110 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Thu, 18 Apr 2024 18:55:24 +0300 Subject: [PATCH 03/43] update ledsubsystem to work with tests --- .../frc/robot/subsystems/LEDSubsystem.java | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/main/java/frc/robot/subsystems/LEDSubsystem.java b/src/main/java/frc/robot/subsystems/LEDSubsystem.java index 43e4b6e..159f9a7 100644 --- a/src/main/java/frc/robot/subsystems/LEDSubsystem.java +++ b/src/main/java/frc/robot/subsystems/LEDSubsystem.java @@ -7,7 +7,7 @@ import frc.robot.Constants.LEDConstants; import frc.utils.BetterLED; -public class LEDSubsystem extends SubsystemBase { +public class LEDSubsystem extends SubsystemBase implements AutoCloseable { BetterLED strip; Color lastSetColor = new Color(); Color lastSetBlinkingColor = new Color(); @@ -22,6 +22,15 @@ public void periodic() { SmartDashboard.putString("LED Currently Running", strip.getCurrentCommandName()); } + @Override + public void close() { + strip.close(); + } + + public int getLedCount() { + return strip.getLedCount(); + } + public void fill(Color color) { if (lastSetColor.equals(color)) { return; @@ -68,13 +77,17 @@ public void setStatusColor(boolean status) { } } - public void blink(Color color) { + public void blink(Color color, double delaySeconds) { if (lastSetBlinkingColor.equals(color)) { return; } lastSetColor = new Color(); // Reset back to 0 lastSetBlinkingColor = color; - strip.blink(color); + strip.blink(color, delaySeconds); + } + + public void blink(Color color) { + blink(color, 0.2); } public void blinkRed() { From 83f56d798565bb0cfecea32b79fc08f82be8303c Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Thu, 18 Apr 2024 18:55:50 +0300 Subject: [PATCH 04/43] add extra features to ledsystem for unit tests --- src/main/java/frc/robot/subsystems/LEDSystem.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/main/java/frc/robot/subsystems/LEDSystem.java b/src/main/java/frc/robot/subsystems/LEDSystem.java index ec07193..c31cb17 100644 --- a/src/main/java/frc/robot/subsystems/LEDSystem.java +++ b/src/main/java/frc/robot/subsystems/LEDSystem.java @@ -3,7 +3,7 @@ import edu.wpi.first.wpilibj2.command.Command; public final class LEDSystem { - private static final LEDSubsystem ledSubsystemInstance = new LEDSubsystem(); + private static LEDSubsystem ledSubsystemInstance = new LEDSubsystem(); private LEDSystem() {} @@ -18,4 +18,17 @@ public static Command run(Runnable toRun) { public static Command getBlinkRedCommand() { return ledSubsystemInstance.getRedBlinkCommand(); } + + public static void resetLEDSubsystem() { + if (ledSubsystemInstance == null) { + ledSubsystemInstance = new LEDSubsystem(); + return; + } + ledSubsystemInstance.close(); + ledSubsystemInstance = new LEDSubsystem(); + } + + public static void changeLEDSubsystemInstance(LEDSubsystem ledSubsystem) { + ledSubsystemInstance = ledSubsystem; + } } From a87f5afad347bd770d9b92564c5cbc14c016fe55 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Thu, 18 Apr 2024 20:22:17 +0300 Subject: [PATCH 05/43] add a mutex for led thread system Concurrency is now correctly impemented, this should improve the systems. For the Boolean that kills the thread, I just made it volatile because it will not be changed by the thread in any situation, it will only be read by it. Also even if it reads it at the same time, its fine cause it can read it in the next iteration of the infinite for loop. --- src/main/java/frc/utils/BetterLED.java | 76 +++++++++++++++++++++++--- 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/src/main/java/frc/utils/BetterLED.java b/src/main/java/frc/utils/BetterLED.java index d7d7976..76f6c6c 100644 --- a/src/main/java/frc/utils/BetterLED.java +++ b/src/main/java/frc/utils/BetterLED.java @@ -6,6 +6,7 @@ import edu.wpi.first.wpilibj.Timer; import edu.wpi.first.wpilibj.util.Color; import java.util.ArrayList; +import java.util.concurrent.locks.ReentrantLock; public class BetterLED extends AddressableLED { public enum AnimationType { // Is already static. @@ -20,6 +21,9 @@ public enum AnimationType { // Is already static. private int rainbowFirstPixelHue = 0; private int currentAnimationIndex = 0; + private ReentrantLock ledMutex = new ReentrantLock(true); + private volatile boolean isThreadKilled = false; + // The call list will have all animation calls in it, // This will run like a scheduler, just on a smaller scale. // it will probably have only a single function, but is a an Arraylist just in case. @@ -40,20 +44,59 @@ public BetterLED(int port, int ledCount) { } private void setupThread() { + isThreadKilled = false; // Reset the kill flag on setup of thread ledUpdateThread = new Thread( () -> { for (; ; ) { // Infinity call periodic, - periodic(); + ledMutex.lock(); + try { + periodic(); + } finally { + ledMutex.unlock(); + } Timer.delay(0.015); - // Maybe add a delay? - // or should the delay be handled by the respective functions? + + // Kill the thread if it has ben set to kill. + if (isThreadKilled) { + break; + } } }, "LED Control Thread"); + ledUpdateThread.setDaemon(true); ledUpdateThread.start(); } + @Override + public void close() { + isThreadKilled = true; + super.close(); + } + + /** + * Check if the thread is alive and if not, restart it. + * + * @return thread got restarted + *
true if restarted, false if not + */ + public boolean checkThreadStatus() { + if (!ledUpdateThread.isAlive()) { + setupThread(); // restart thread + return true; + } + return false; + } + + /** + * Returns the buffer thats used. You should never need to use this except debugging or similar. + * + * @return The main buffer used by the LED instance. + */ + public AddressableLEDBuffer getBuffer() { + return mainBuffer; + } + public int getLedCount() { return ledCount; } @@ -186,19 +229,34 @@ public void setLength(int length) { } private void changeLoopTo(LEDCommand func) { - commandList.clear(); // Clear the list first - commandList.add(func); // then add the runnable + ledMutex.lock(); + try { + commandList.clear(); // Clear the list first + commandList.add(func); // then add the runnable + } finally { + ledMutex.unlock(); + } } public void addToLoop(LEDCommand command) { - commandList.add(command); + ledMutex.lock(); + try { + commandList.add(command); + } finally { + ledMutex.unlock(); + } } public void removeFromLoop(int amount) { - for (int i = 0; i < amount; i++) { - if (!commandList.isEmpty()) { - commandList.remove(0); + ledMutex.lock(); + try { + for (int i = 0; i < amount; i++) { + if (!commandList.isEmpty()) { + commandList.remove(0); + } } + } finally { + ledMutex.unlock(); } } From e737eb2c5bc02027a4d6f76d7a3adc6aa0a863bf Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Thu, 18 Apr 2024 20:23:18 +0300 Subject: [PATCH 06/43] make the color checking thread closable. --- .../java/frc/robot/subsystems/IntakeSubsystem.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/main/java/frc/robot/subsystems/IntakeSubsystem.java b/src/main/java/frc/robot/subsystems/IntakeSubsystem.java index 8d71e87..e2ad597 100644 --- a/src/main/java/frc/robot/subsystems/IntakeSubsystem.java +++ b/src/main/java/frc/robot/subsystems/IntakeSubsystem.java @@ -20,6 +20,7 @@ public class IntakeSubsystem extends SubsystemBase implements AutoCloseable { private final CANSparkMAXWrapped armIntake; private final CANSparkMAXWrapped groundIntake; private final ColorSensorV3Wrapped colorSensor; + private final Thread fastColorCheckThread; private boolean isForced = false; public IntakeSubsystem() { @@ -29,14 +30,16 @@ public IntakeSubsystem() { setupIntakeMotors(); colorSensor = new ColorSensorV3Wrapped(ColorSensorConstants.kColorSensorPort); - new Thread( + fastColorCheckThread = + new Thread( () -> { while (true) { fastPeriodic(); } }, - "Fast Color Check Loop") - .start(); + "Fast Color Check Loop"); + fastColorCheckThread.setDaemon(true); + fastColorCheckThread.start(); } private void setupIntakeMotors() { @@ -57,6 +60,7 @@ private void setupIntakeMotors() { @Override public void close() { + fastColorCheckThread.interrupt(); armIntake.close(); groundIntake.close(); colorSensor.close(); From 8f8c516e26e8bde410eb44d48ea5e43c92b04f95 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Thu, 18 Apr 2024 20:23:49 +0300 Subject: [PATCH 07/43] don't check note on periodic cause it breaks the unit tests for SOME UNKOWN GODDAMN REASON --- src/main/java/frc/robot/subsystems/IntakeSubsystem.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/frc/robot/subsystems/IntakeSubsystem.java b/src/main/java/frc/robot/subsystems/IntakeSubsystem.java index e2ad597..9d371f1 100644 --- a/src/main/java/frc/robot/subsystems/IntakeSubsystem.java +++ b/src/main/java/frc/robot/subsystems/IntakeSubsystem.java @@ -131,7 +131,7 @@ public void periodic() { SmartDashboard.putNumber("ColorSensor - Blue", colorSensor.getBlue()); SmartDashboard.putNumber("ColorSensor - IR", colorSensor.getIR()); SmartDashboard.putBoolean("Note Detected", hasNote()); - checkIfHasNote(); + // don't check for a note here cause it breaks the unit tests SOMEHOW! } private void fastPeriodic() { From 72880077426c7561174b7a6ea946cba589ae28cf Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Thu, 18 Apr 2024 20:24:02 +0300 Subject: [PATCH 08/43] minor changes --- src/main/java/frc/utils/sim_utils/CANSparkMAXWrapped.java | 4 ++++ src/main/java/frc/utils/sim_utils/ColorSensorV3Wrapped.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/frc/utils/sim_utils/CANSparkMAXWrapped.java b/src/main/java/frc/utils/sim_utils/CANSparkMAXWrapped.java index 9c4db6b..da19271 100644 --- a/src/main/java/frc/utils/sim_utils/CANSparkMAXWrapped.java +++ b/src/main/java/frc/utils/sim_utils/CANSparkMAXWrapped.java @@ -18,4 +18,8 @@ public void close() { } super.close(); } + + public boolean isThisClosed() { + return isClosed.get(); + } } diff --git a/src/main/java/frc/utils/sim_utils/ColorSensorV3Wrapped.java b/src/main/java/frc/utils/sim_utils/ColorSensorV3Wrapped.java index 89480c7..37bcfa1 100644 --- a/src/main/java/frc/utils/sim_utils/ColorSensorV3Wrapped.java +++ b/src/main/java/frc/utils/sim_utils/ColorSensorV3Wrapped.java @@ -5,7 +5,7 @@ import edu.wpi.first.wpilibj.RobotBase; public class ColorSensorV3Wrapped extends ColorSensorV3 implements AutoCloseable { - private static ColorSensorV3 colorSensor = null; + private static ColorSensorV3 colorSensor; private static final int[] rgbd = new int[4]; // Red, Green, Blue, and Distance public ColorSensorV3Wrapped(I2C.Port port) { From a8ea6dbad4915366348e0c89521215085cfeebe6 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Thu, 18 Apr 2024 20:24:40 +0300 Subject: [PATCH 09/43] bump photonlib dependency to 3.1 --- vendordeps/photonlib.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vendordeps/photonlib.json b/vendordeps/photonlib.json index e024f06..0e80a16 100644 --- a/vendordeps/photonlib.json +++ b/vendordeps/photonlib.json @@ -1,7 +1,7 @@ { "fileName": "photonlib.json", "name": "photonlib", - "version": "v2024.2.10", + "version": "v2024.3.1", "uuid": "515fe07e-bfc6-11fa-b3de-0242ac130004", "frcYear": "2024", "mavenUrls": [ @@ -14,7 +14,7 @@ { "groupId": "org.photonvision", "artifactId": "photonlib-cpp", - "version": "v2024.2.10", + "version": "v2024.3.1", "libName": "photonlib", "headerClassifier": "headers", "sharedLibrary": true, @@ -29,7 +29,7 @@ { "groupId": "org.photonvision", "artifactId": "photontargeting-cpp", - "version": "v2024.2.10", + "version": "v2024.3.1", "libName": "photontargeting", "headerClassifier": "headers", "sharedLibrary": true, @@ -46,12 +46,12 @@ { "groupId": "org.photonvision", "artifactId": "photonlib-java", - "version": "v2024.2.10" + "version": "v2024.3.1" }, { "groupId": "org.photonvision", "artifactId": "photontargeting-java", - "version": "v2024.2.10" + "version": "v2024.3.1" } ] } \ No newline at end of file From ca8b460192138186141418a4fc464a34def192cb Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Thu, 18 Apr 2024 20:25:03 +0300 Subject: [PATCH 10/43] add command tests in progress, will add a test for most commands avaliable. --- .../java/command_tests/BasicIntakeTest.java | 66 +++++++++++++++++ .../command_tests/LEDIdleCommandTest.java | 72 +++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 src/test/java/command_tests/BasicIntakeTest.java create mode 100644 src/test/java/command_tests/LEDIdleCommandTest.java diff --git a/src/test/java/command_tests/BasicIntakeTest.java b/src/test/java/command_tests/BasicIntakeTest.java new file mode 100644 index 0000000..589ef08 --- /dev/null +++ b/src/test/java/command_tests/BasicIntakeTest.java @@ -0,0 +1,66 @@ +package command_tests; + +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static utils.LEDTestUtils.checkForColorInAll; + +import com.revrobotics.CANSparkMax; +import edu.wpi.first.wpilibj.Timer; +import edu.wpi.first.wpilibj.simulation.DriverStationSim; +import edu.wpi.first.wpilibj.util.Color; +import edu.wpi.first.wpilibj2.command.CommandScheduler; +import frc.robot.Constants.IntakeConstants; +import frc.robot.commands.BasicIntakeCommand; +import frc.robot.subsystems.IntakeSubsystem; +import frc.robot.subsystems.LEDSubsystem; +import frc.robot.subsystems.LEDSystem; +import frc.utils.sim_utils.SparkMAXSimAddon; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class BasicIntakeTest { + private IntakeSubsystem intakeSubsystem; + private CANSparkMax intakeMotor; + private LEDSubsystem ledSubsystem; + private BasicIntakeCommand intakeCommand; + private CommandScheduler commandScheduler; + + @BeforeEach + public void setUp() { + intakeSubsystem = new IntakeSubsystem(); + intakeMotor = SparkMAXSimAddon.getSparkMAX(IntakeConstants.kArmIntakeMotorCanID); + ledSubsystem = LEDSystem.getInstance(); + intakeCommand = new BasicIntakeCommand(intakeSubsystem); + + // Enable robot for commands to run + DriverStationSim.setEnabled(true); + DriverStationSim.setDsAttached(true); + DriverStationSim.notifyNewData(); // ! Breaks without this + commandScheduler = CommandScheduler.getInstance(); + commandScheduler.schedule(intakeCommand); + } + + @AfterEach + public void tearDown() { + LEDSystem.resetLEDSubsystem(); + intakeSubsystem.close(); + intakeCommand.cancel(); + commandScheduler.close(); + } + + @Test + void testSpeed() { + commandScheduler.run(); + // Motor shouldn't be 0 when intaking + assertNotEquals(0, intakeMotor.get()); + } + + @Test + void testLEDBlinking() { + commandScheduler.run(); + Timer.delay(0.2); // let led loop do its thing + checkForColorInAll(ledSubsystem, Color.kRed, "Color should be red when started"); + Timer.delay(0.2); + checkForColorInAll(ledSubsystem, Color.kBlack, "Color should be closed when blinking red"); + } +} diff --git a/src/test/java/command_tests/LEDIdleCommandTest.java b/src/test/java/command_tests/LEDIdleCommandTest.java new file mode 100644 index 0000000..5a4c669 --- /dev/null +++ b/src/test/java/command_tests/LEDIdleCommandTest.java @@ -0,0 +1,72 @@ +package command_tests; + +import static utils.LEDTestUtils.checkForColorInAll; + +import edu.wpi.first.hal.HAL; +import edu.wpi.first.wpilibj.Timer; +import edu.wpi.first.wpilibj.simulation.DriverStationSim; +import edu.wpi.first.wpilibj.util.Color; +import edu.wpi.first.wpilibj2.command.CommandScheduler; +import frc.robot.commands.led_commands.LEDIdleCommand; +import frc.robot.subsystems.IntakeSubsystem; +import frc.robot.subsystems.LEDSubsystem; +import frc.robot.subsystems.LEDSystem; +import frc.utils.sim_utils.ColorSensorV3Wrapped; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class LEDIdleCommandTest { + private LEDSubsystem ledSubsystem; + private IntakeSubsystem intakeSubsystem; + private CommandScheduler commandScheduler; + + @BeforeEach + public void setUp() { + HAL.initialize(500, 0); + ledSubsystem = LEDSystem.getInstance(); + intakeSubsystem = new IntakeSubsystem(); + commandScheduler = CommandScheduler.getInstance(); + } + + @AfterEach + public void tearDown() { + intakeSubsystem.close(); + LEDSystem.resetLEDSubsystem(); // closes and re init's ledSubsystem + commandScheduler.close(); + } + + @Test + void colorOnDisabled() { + DriverStationSim.setEnabled(false); + DriverStationSim.setDsAttached(true); + DriverStationSim.notifyNewData(); // ! Breaks without this + commandScheduler.schedule( + new LEDIdleCommand(ledSubsystem, intakeSubsystem).ignoringDisable(true)); + commandScheduler.run(); + Timer.delay(0.1); // let led thread do its thing + checkForColorInAll(ledSubsystem, Color.kOrangeRed, "Color Should be orange when disabled"); + } + + @Test + void colorOnEnabled() { + DriverStationSim.setDsAttached(true); + DriverStationSim.setEnabled(true); + DriverStationSim.notifyNewData(); // ! Breaks without this + commandScheduler.run(); + commandScheduler.schedule( + new LEDIdleCommand(ledSubsystem, intakeSubsystem).ignoringDisable(true)); + + // * check without Note + ColorSensorV3Wrapped.setRGBD(0, 0, 0, 0); + commandScheduler.run(); + Timer.delay(0.1); // let led thread do its thing + checkForColorInAll(ledSubsystem, Color.kRed, "Color should be red when no Note is detected"); + + // * check with Note + ColorSensorV3Wrapped.setRGBD(2500, 0, 0, 900); + commandScheduler.run(); + Timer.delay(0.1); // let led thread do its thing + checkForColorInAll(ledSubsystem, Color.kGreen, "Color should be green when Note is detected"); + } +} From dc578be84798b97c8f3b2f0f7f8a392dab35ee42 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Fri, 19 Apr 2024 01:05:29 +0300 Subject: [PATCH 11/43] move wrapper tests to another folder and update them Added more code coverage this way. and its more organized as well --- .../wrapper_tests/SparkMAXWrapperTest.java | 26 ---------- .../ColorSensorV3WrapperTests.java | 8 +++- .../wrapper_tests/SparkMAXWrapperTest.java | 48 +++++++++++++++++++ 3 files changed, 55 insertions(+), 27 deletions(-) delete mode 100644 src/test/java/subsystem_tests/wrapper_tests/SparkMAXWrapperTest.java rename src/test/java/{subsystem_tests => }/wrapper_tests/ColorSensorV3WrapperTests.java (85%) create mode 100644 src/test/java/wrapper_tests/SparkMAXWrapperTest.java diff --git a/src/test/java/subsystem_tests/wrapper_tests/SparkMAXWrapperTest.java b/src/test/java/subsystem_tests/wrapper_tests/SparkMAXWrapperTest.java deleted file mode 100644 index 74ed670..0000000 --- a/src/test/java/subsystem_tests/wrapper_tests/SparkMAXWrapperTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package subsystem_tests.wrapper_tests; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import edu.wpi.first.hal.HAL; -import frc.utils.sim_utils.CANSparkMAXWrapped; -import frc.utils.sim_utils.SparkMAXSimAddon; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -class SparkMAXWrapperTest { - @BeforeEach - public void setUp() { - HAL.initialize(500, 0); // init HAL just in case - } - - @Test - void testSparkMAXWrapper() { - for (int i = 0; i < 50; i++) { - CANSparkMAXWrapped sparkMAX = - new CANSparkMAXWrapped(i, CANSparkMAXWrapped.MotorType.kBrushless); - assertEquals(sparkMAX, SparkMAXSimAddon.getSparkMAX(i)); - sparkMAX.close(); - } - } -} diff --git a/src/test/java/subsystem_tests/wrapper_tests/ColorSensorV3WrapperTests.java b/src/test/java/wrapper_tests/ColorSensorV3WrapperTests.java similarity index 85% rename from src/test/java/subsystem_tests/wrapper_tests/ColorSensorV3WrapperTests.java rename to src/test/java/wrapper_tests/ColorSensorV3WrapperTests.java index 6cac260..4867421 100644 --- a/src/test/java/subsystem_tests/wrapper_tests/ColorSensorV3WrapperTests.java +++ b/src/test/java/wrapper_tests/ColorSensorV3WrapperTests.java @@ -1,4 +1,4 @@ -package subsystem_tests.wrapper_tests; +package wrapper_tests; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -25,6 +25,12 @@ public void tearDown() { @Test void testColorSensorV3Wrapping() { + assertEquals( + colorSensor, ColorSensorV3Wrapped.getColorSensor(), "ColorSensorV3 should be wrapped"); + } + + @Test + void testColorSensorV3ValueChanging() { ColorSensorV3Wrapped.setRGBD(2500, 300, 100, 900); assertEquals(2500, colorSensor.getRed()); assertEquals(300, colorSensor.getGreen()); diff --git a/src/test/java/wrapper_tests/SparkMAXWrapperTest.java b/src/test/java/wrapper_tests/SparkMAXWrapperTest.java new file mode 100644 index 0000000..71132f4 --- /dev/null +++ b/src/test/java/wrapper_tests/SparkMAXWrapperTest.java @@ -0,0 +1,48 @@ +package wrapper_tests; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import edu.wpi.first.hal.HAL; +import frc.utils.sim_utils.CANSparkMAXWrapped; +import frc.utils.sim_utils.SparkMAXSimAddon; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class SparkMAXWrapperTest { + @BeforeEach + public void setUp() { + HAL.initialize(500, 0); // init HAL just in case + } + + @Test + void testSparkMAXWrapper() { + for (int i = 0; i < 50; i++) { + CANSparkMAXWrapped sparkMAX = + new CANSparkMAXWrapped(i, CANSparkMAXWrapped.MotorType.kBrushless); + assertEquals(sparkMAX, SparkMAXSimAddon.getSparkMAX(i)); + sparkMAX.close(); + } + } + + @Test + void testSparkMAXisClosed() { + CANSparkMAXWrapped sparkMAX = + new CANSparkMAXWrapped(1, CANSparkMAXWrapped.MotorType.kBrushless); + sparkMAX.close(); + assertEquals(true, sparkMAX.isThisClosed()); + } + + @Test + void testSparkMAXClear() { + CANSparkMAXWrapped sparkMAX = + new CANSparkMAXWrapped(1, CANSparkMAXWrapped.MotorType.kBrushless); + SparkMAXSimAddon.resetData(); + try { + SparkMAXSimAddon.getSparkMAX(1); + assert false; // should not reach here + sparkMAX.close(); // just so the linter doesn't complain + } catch (IllegalArgumentException e) { + assertEquals("SparkMAX with deviceID 1 does not exist", e.getMessage()); + } + } +} From 5216b24aa9a130ebe71425140a01bc83aac79958 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Fri, 19 Apr 2024 01:08:26 +0300 Subject: [PATCH 12/43] better error on check for color in all function --- src/test/java/utils/LEDTestUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/utils/LEDTestUtils.java b/src/test/java/utils/LEDTestUtils.java index e6c949b..874ba2a 100644 --- a/src/test/java/utils/LEDTestUtils.java +++ b/src/test/java/utils/LEDTestUtils.java @@ -9,7 +9,7 @@ public class LEDTestUtils { public static void checkForColorInAll( LEDSubsystem ledSubsystem, Color colorItShouldBe, String message) { for (int i = 0; i < ledSubsystem.getLedCount(); i++) { - assertEquals(colorItShouldBe, getColorAtIndex(ledSubsystem, i), message); + assertEquals(colorItShouldBe, getColorAtIndex(ledSubsystem, i), message + " at index: " + i); } } From 58c65f9396946c1db7a49b0430dedde935ae0e22 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Fri, 19 Apr 2024 01:08:53 +0300 Subject: [PATCH 13/43] move basic intake test to arm_tests folder --- .../{ => arm_tests}/BasicIntakeTest.java | 23 +++++-------------- 1 file changed, 6 insertions(+), 17 deletions(-) rename src/test/java/command_tests/{ => arm_tests}/BasicIntakeTest.java (67%) diff --git a/src/test/java/command_tests/BasicIntakeTest.java b/src/test/java/command_tests/arm_tests/BasicIntakeTest.java similarity index 67% rename from src/test/java/command_tests/BasicIntakeTest.java rename to src/test/java/command_tests/arm_tests/BasicIntakeTest.java index 589ef08..0c22aed 100644 --- a/src/test/java/command_tests/BasicIntakeTest.java +++ b/src/test/java/command_tests/arm_tests/BasicIntakeTest.java @@ -1,51 +1,40 @@ -package command_tests; +package command_tests.arm_tests; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static utils.LEDTestUtils.checkForColorInAll; import com.revrobotics.CANSparkMax; +import command_tests.utils.CommandTestBase; import edu.wpi.first.wpilibj.Timer; -import edu.wpi.first.wpilibj.simulation.DriverStationSim; import edu.wpi.first.wpilibj.util.Color; -import edu.wpi.first.wpilibj2.command.CommandScheduler; import frc.robot.Constants.IntakeConstants; import frc.robot.commands.BasicIntakeCommand; import frc.robot.subsystems.IntakeSubsystem; -import frc.robot.subsystems.LEDSubsystem; -import frc.robot.subsystems.LEDSystem; import frc.utils.sim_utils.SparkMAXSimAddon; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -class BasicIntakeTest { +class BasicIntakeTest extends CommandTestBase { private IntakeSubsystem intakeSubsystem; + private CANSparkMax intakeMotor; - private LEDSubsystem ledSubsystem; private BasicIntakeCommand intakeCommand; - private CommandScheduler commandScheduler; @BeforeEach public void setUp() { + super.setUp(); intakeSubsystem = new IntakeSubsystem(); intakeMotor = SparkMAXSimAddon.getSparkMAX(IntakeConstants.kArmIntakeMotorCanID); - ledSubsystem = LEDSystem.getInstance(); intakeCommand = new BasicIntakeCommand(intakeSubsystem); - // Enable robot for commands to run - DriverStationSim.setEnabled(true); - DriverStationSim.setDsAttached(true); - DriverStationSim.notifyNewData(); // ! Breaks without this - commandScheduler = CommandScheduler.getInstance(); commandScheduler.schedule(intakeCommand); } @AfterEach public void tearDown() { - LEDSystem.resetLEDSubsystem(); intakeSubsystem.close(); - intakeCommand.cancel(); - commandScheduler.close(); + super.tearDown(); } @Test From e47ac9703e846db7d5218c0962137b0fb063dd47 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Fri, 19 Apr 2024 01:09:18 +0300 Subject: [PATCH 14/43] create basic shooter tests there will be more tests added into this. --- .../arm_tests/BasicShooterTest.java | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 src/test/java/command_tests/arm_tests/BasicShooterTest.java diff --git a/src/test/java/command_tests/arm_tests/BasicShooterTest.java b/src/test/java/command_tests/arm_tests/BasicShooterTest.java new file mode 100644 index 0000000..a02f679 --- /dev/null +++ b/src/test/java/command_tests/arm_tests/BasicShooterTest.java @@ -0,0 +1,64 @@ +package command_tests.arm_tests; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import command_tests.utils.CommandTestBase; +import edu.wpi.first.wpilibj.Timer; +import edu.wpi.first.wpilibj.simulation.PWMSim; +import frc.robot.Constants.ShooterConstants; +import frc.robot.commands.BasicRunShooterCommand; +import frc.robot.subsystems.ShooterSubsystem; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class BasicShooterTest extends CommandTestBase { + private ShooterSubsystem shooterSubsystem; + private PWMSim shooterMotor; + private BasicRunShooterCommand basicShooterCommand; + private static final double waitTime = 2; + + @BeforeEach + public void setUp() { + super.setUp(); + shooterSubsystem = new ShooterSubsystem(); + shooterMotor = new PWMSim(ShooterConstants.kShooterMotorPwmID); + basicShooterCommand = new BasicRunShooterCommand(shooterSubsystem, waitTime); + + commandScheduler.schedule(basicShooterCommand); + } + + @AfterEach + public void tearDown() { + super.tearDown(); + shooterSubsystem.close(); + } + + @Test + void testSetSpeed() { + commandScheduler.run(); + // Motor should be at the set speed + assertEquals( + ShooterConstants.kShooterSpeed, + shooterMotor.getSpeed(), + "Shooter motor should be at shooter speed"); + Timer.delay(waitTime); + commandScheduler.run(); + // Motor should be at 0 after waitTime + assertEquals( + 0, + shooterMotor.getSpeed(), + "Shooter motor should be at 0 after %s seconds".formatted(waitTime)); + } + + // @Test + // void testLEDLoading() { + // commandScheduler.run(); + // Timer.delay(waitTime - 0.2); // let led loop do its thing + // commandScheduler.run(); + // // LED should be green after waitTime + // checkForColorInAll( + // ledSubsystem, LEDLoadingWaitCommand.DEFAULT_COLOR, "Color should be green after + // waitTime"); + // } +} From cb09e1ca1f2b380802de9c82f22017b8889dc750 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Fri, 19 Apr 2024 01:12:32 +0300 Subject: [PATCH 15/43] improve basic run shooter command make it more verbose and also stop the shooter when its done shooting. --- .../frc/robot/commands/BasicRunShooterCommand.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/frc/robot/commands/BasicRunShooterCommand.java b/src/main/java/frc/robot/commands/BasicRunShooterCommand.java index b571506..10576b3 100644 --- a/src/main/java/frc/robot/commands/BasicRunShooterCommand.java +++ b/src/main/java/frc/robot/commands/BasicRunShooterCommand.java @@ -1,21 +1,25 @@ package frc.robot.commands; +import edu.wpi.first.wpilibj2.command.ParallelRaceGroup; import edu.wpi.first.wpilibj2.command.SequentialCommandGroup; import frc.robot.Constants.ShooterConstants; import frc.robot.commands.led_commands.LEDLoadingWaitCommand; import frc.robot.subsystems.ShooterSubsystem; public class BasicRunShooterCommand extends SequentialCommandGroup { - BasicRunShooterCommand(ShooterSubsystem shooterSubsystem) { + public BasicRunShooterCommand(ShooterSubsystem shooterSubsystem) { super( shooterSubsystem.run( () -> shooterSubsystem.setShooterSpeed(ShooterConstants.kShooterSpeed))); } - BasicRunShooterCommand(ShooterSubsystem shooterSubsystem, double untilTimeSeconds) { + public BasicRunShooterCommand(ShooterSubsystem shooterSubsystem, double untilTimeSeconds) { super( - shooterSubsystem - .run(() -> shooterSubsystem.setShooterSpeed(ShooterConstants.kShooterSpeed)) - .raceWith(new LEDLoadingWaitCommand(untilTimeSeconds))); + new ParallelRaceGroup( + new BasicRunShooterCommand(shooterSubsystem), // Run the shooter + new LEDLoadingWaitCommand(untilTimeSeconds)), + shooterSubsystem.runOnce( + () -> shooterSubsystem.setShooterSpeed(0) // Stop the shooter after the wait + )); } } From ff39457957b51ec6278deef4dc17819bbcee7ca3 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Fri, 19 Apr 2024 01:12:50 +0300 Subject: [PATCH 16/43] make shooterSubsystem closeable --- src/main/java/frc/robot/subsystems/ShooterSubsystem.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/frc/robot/subsystems/ShooterSubsystem.java b/src/main/java/frc/robot/subsystems/ShooterSubsystem.java index 28c20fc..7116e7e 100644 --- a/src/main/java/frc/robot/subsystems/ShooterSubsystem.java +++ b/src/main/java/frc/robot/subsystems/ShooterSubsystem.java @@ -3,13 +3,18 @@ import edu.wpi.first.wpilibj.motorcontrol.Spark; import edu.wpi.first.wpilibj2.command.SubsystemBase; -public class ShooterSubsystem extends SubsystemBase { +public class ShooterSubsystem extends SubsystemBase implements AutoCloseable { private final Spark shooterMotor; public ShooterSubsystem() { shooterMotor = new Spark(0); } + @Override + public void close() { + shooterMotor.close(); + } + public void setShooterSpeed(double speed) { shooterMotor.set(speed); } From 1cc00d6a5f93afc207942e4b339a7065c378200e Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Fri, 19 Apr 2024 01:14:08 +0300 Subject: [PATCH 17/43] create commandTestBase This is the base for most command tests, as it will at least remove a bit of boiler plate like enabling the robot, resetting the command scheduler, initializing HAL, and resetting led subsystem. --- .../command_tests/utils/CommandTestBase.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/test/java/command_tests/utils/CommandTestBase.java diff --git a/src/test/java/command_tests/utils/CommandTestBase.java b/src/test/java/command_tests/utils/CommandTestBase.java new file mode 100644 index 0000000..9a004d1 --- /dev/null +++ b/src/test/java/command_tests/utils/CommandTestBase.java @@ -0,0 +1,33 @@ +package command_tests.utils; + +import edu.wpi.first.hal.HAL; +import edu.wpi.first.wpilibj.simulation.DriverStationSim; +import edu.wpi.first.wpilibj2.command.CommandScheduler; +import frc.robot.subsystems.LEDSubsystem; +import frc.robot.subsystems.LEDSystem; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; + +public class CommandTestBase { + protected CommandScheduler commandScheduler; + protected LEDSubsystem ledSubsystem; + + @BeforeEach + protected void setUp() { + assert HAL.initialize(500, 0); + commandScheduler = CommandScheduler.getInstance(); + ledSubsystem = LEDSystem.getInstance(); + + // Enable robot for commands to run + DriverStationSim.setEnabled(true); + DriverStationSim.setDsAttached(true); + DriverStationSim.notifyNewData(); // ! Breaks without this + } + + @AfterEach + protected void tearDown() { + LEDSystem.resetLEDSubsystem(); + commandScheduler.cancelAll(); + commandScheduler.close(); + } +} From 6ec5e84a3fe97e9cb506b05c4f36a44a32d18ae7 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Fri, 19 Apr 2024 01:14:53 +0300 Subject: [PATCH 18/43] move the LEDLoadingWaitCommands color to a constant This will in future be moved into constants.java, but for now it can stay here i guess. --- .../frc/robot/commands/led_commands/LEDLoadingWaitCommand.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/frc/robot/commands/led_commands/LEDLoadingWaitCommand.java b/src/main/java/frc/robot/commands/led_commands/LEDLoadingWaitCommand.java index 7b35078..b275cc4 100644 --- a/src/main/java/frc/robot/commands/led_commands/LEDLoadingWaitCommand.java +++ b/src/main/java/frc/robot/commands/led_commands/LEDLoadingWaitCommand.java @@ -7,6 +7,7 @@ public class LEDLoadingWaitCommand extends WaitCommand { private double seconds; private Color colorToFill; + public static final Color DEFAULT_COLOR = new Color(0, 200, 255); public LEDLoadingWaitCommand(double seconds, Color colorToFill) { super(seconds); @@ -16,7 +17,7 @@ public LEDLoadingWaitCommand(double seconds, Color colorToFill) { } public LEDLoadingWaitCommand(double seconds) { - this(seconds, new Color(0, 200, 255)); + this(seconds, DEFAULT_COLOR); } @Override From 45408dadf7a446f7c46ced4b0c47476c01f191c6 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Fri, 19 Apr 2024 01:15:09 +0300 Subject: [PATCH 19/43] remove the useless extra run on led idle command test --- src/test/java/command_tests/LEDIdleCommandTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/command_tests/LEDIdleCommandTest.java b/src/test/java/command_tests/LEDIdleCommandTest.java index 5a4c669..74e0116 100644 --- a/src/test/java/command_tests/LEDIdleCommandTest.java +++ b/src/test/java/command_tests/LEDIdleCommandTest.java @@ -53,7 +53,6 @@ void colorOnEnabled() { DriverStationSim.setDsAttached(true); DriverStationSim.setEnabled(true); DriverStationSim.notifyNewData(); // ! Breaks without this - commandScheduler.run(); commandScheduler.schedule( new LEDIdleCommand(ledSubsystem, intakeSubsystem).ignoringDisable(true)); From 2cf4946d7a0d453ea05a218573cfdaa12db3a469 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Fri, 19 Apr 2024 01:34:19 +0300 Subject: [PATCH 20/43] add code covarage reports now with jococo The reports can be found on logs/jococoHtml --- build.gradle | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/build.gradle b/build.gradle index 7a8b96b..d754ad3 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,6 @@ plugins { id "java" + id "jacoco" id "edu.wpi.first.GradleRIO" version "2024.2.1" id "com.diffplug.spotless" version "6.23.3" } @@ -25,6 +26,19 @@ java { targetCompatibility = JavaVersion.VERSION_17 } +jacoco { + toolVersion = "0.8.11" + reportsDirectory = layout.projectDirectory.dir("logs/jacoco") +} + +jacocoTestReport { + reports { + xml.required = false + csv.required = false + html.outputLocation = layout.projectDirectory.dir("logs/jacocoHtml") + } +} + def ROBOT_MAIN_CLASS = "frc.robot.Main" // Define my targets (RoboRIO) and artifacts (deployable files) @@ -91,6 +105,11 @@ dependencies { test { useJUnitPlatform() systemProperty 'junit.jupiter.extensions.autodetection.enabled', 'true' + finalizedBy jacocoTestReport // report is always generated after tests run +} + +jacocoTestReport { + dependsOn test // tests are required to run before generating the report } // Simulation configuration (e.g. environment variables). From 4c44426d75ca82eb61825084a0b271a4fe878c7c Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Fri, 19 Apr 2024 22:05:03 +0300 Subject: [PATCH 21/43] update led idle command test to use command test base --- .../java/command_tests/LEDIdleCommandTest.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/test/java/command_tests/LEDIdleCommandTest.java b/src/test/java/command_tests/LEDIdleCommandTest.java index 74e0116..29d668b 100644 --- a/src/test/java/command_tests/LEDIdleCommandTest.java +++ b/src/test/java/command_tests/LEDIdleCommandTest.java @@ -2,38 +2,32 @@ import static utils.LEDTestUtils.checkForColorInAll; +import command_tests.utils.CommandTestBase; import edu.wpi.first.hal.HAL; import edu.wpi.first.wpilibj.Timer; import edu.wpi.first.wpilibj.simulation.DriverStationSim; import edu.wpi.first.wpilibj.util.Color; -import edu.wpi.first.wpilibj2.command.CommandScheduler; import frc.robot.commands.led_commands.LEDIdleCommand; import frc.robot.subsystems.IntakeSubsystem; -import frc.robot.subsystems.LEDSubsystem; -import frc.robot.subsystems.LEDSystem; import frc.utils.sim_utils.ColorSensorV3Wrapped; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -class LEDIdleCommandTest { - private LEDSubsystem ledSubsystem; +class LEDIdleCommandTest extends CommandTestBase { private IntakeSubsystem intakeSubsystem; - private CommandScheduler commandScheduler; @BeforeEach public void setUp() { + super.setUp(); HAL.initialize(500, 0); - ledSubsystem = LEDSystem.getInstance(); intakeSubsystem = new IntakeSubsystem(); - commandScheduler = CommandScheduler.getInstance(); } @AfterEach public void tearDown() { + super.tearDown(); intakeSubsystem.close(); - LEDSystem.resetLEDSubsystem(); // closes and re init's ledSubsystem - commandScheduler.close(); } @Test From 9fd91539d06ff5f8c0fe3b4d143431dc8296aa50 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Sat, 20 Apr 2024 21:55:35 +0300 Subject: [PATCH 22/43] rename to ledTests folder --- .../{led_integration_tests => led_tests}/LedTests.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/test/java/subsystem_tests/{led_integration_tests => led_tests}/LedTests.java (100%) diff --git a/src/test/java/subsystem_tests/led_integration_tests/LedTests.java b/src/test/java/subsystem_tests/led_tests/LedTests.java similarity index 100% rename from src/test/java/subsystem_tests/led_integration_tests/LedTests.java rename to src/test/java/subsystem_tests/led_tests/LedTests.java From a9302f18cc571733d99c17f0504b44bfbbd4b745 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Sat, 20 Apr 2024 21:58:45 +0300 Subject: [PATCH 23/43] improve LEDTestUtils added multiple new features: - give an untilIndex to checkForColorInAll, that checks only till given index - test at time function, automatically handling what "LedLoadingwaitCommand" would do and checking for those values. a huge QoL feature --- src/test/java/utils/LEDTestUtils.java | 29 +++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/src/test/java/utils/LEDTestUtils.java b/src/test/java/utils/LEDTestUtils.java index 874ba2a..801c6df 100644 --- a/src/test/java/utils/LEDTestUtils.java +++ b/src/test/java/utils/LEDTestUtils.java @@ -2,17 +2,42 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import edu.wpi.first.wpilibj.Timer; import edu.wpi.first.wpilibj.util.Color; +import frc.robot.commands.led_commands.LEDLoadingWaitCommand; import frc.robot.subsystems.LEDSubsystem; public class LEDTestUtils { public static void checkForColorInAll( - LEDSubsystem ledSubsystem, Color colorItShouldBe, String message) { - for (int i = 0; i < ledSubsystem.getLedCount(); i++) { + LEDSubsystem ledSubsystem, Color colorItShouldBe, int untilIndex, String message) { + for (int i = 0; i < untilIndex; i++) { assertEquals(colorItShouldBe, getColorAtIndex(ledSubsystem, i), message + " at index: " + i); } } + public static void checkForColorInAll( + LEDSubsystem ledSubsystem, Color colorItShouldBe, String message) { + checkForColorInAll(ledSubsystem, colorItShouldBe, ledSubsystem.getLedCount(), message); + } + + /** + * Auto Calculates the end time + * + * @param ledSubsystem + * @param startTime + * @param waitTime + */ + public static void testAtTime(LEDSubsystem ledSubsystem, double startTime, double waitTime) { + double endTime = Timer.getFPGATimestamp(); + int untilIndex = (int) (ledSubsystem.getLedCount() * ((endTime - startTime) / waitTime)); + Timer.delay(0.1); // let led loop do its thing + checkForColorInAll( + ledSubsystem, + LEDLoadingWaitCommand.DEFAULT_COLOR, + untilIndex, + "Color should be default color until %s".formatted(untilIndex)); + } + public static Color getColorAtIndex(LEDSubsystem ledSubsystem, int index) { return ledSubsystem.getStrip().getBuffer().getLED(index); } From a2e3a17fa0c584f884540fc1da1f476c79ed7dd1 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Sat, 20 Apr 2024 22:45:20 +0300 Subject: [PATCH 24/43] add a check for command ending to basic intake command --- .../java/command_tests/arm_tests/BasicIntakeTest.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/test/java/command_tests/arm_tests/BasicIntakeTest.java b/src/test/java/command_tests/arm_tests/BasicIntakeTest.java index 0c22aed..653a0cf 100644 --- a/src/test/java/command_tests/arm_tests/BasicIntakeTest.java +++ b/src/test/java/command_tests/arm_tests/BasicIntakeTest.java @@ -1,5 +1,6 @@ package command_tests.arm_tests; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; import static utils.LEDTestUtils.checkForColorInAll; @@ -10,6 +11,7 @@ import frc.robot.Constants.IntakeConstants; import frc.robot.commands.BasicIntakeCommand; import frc.robot.subsystems.IntakeSubsystem; +import frc.utils.sim_utils.ColorSensorV3Wrapped; import frc.utils.sim_utils.SparkMAXSimAddon; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -52,4 +54,13 @@ void testLEDBlinking() { Timer.delay(0.2); checkForColorInAll(ledSubsystem, Color.kBlack, "Color should be closed when blinking red"); } + + @Test + void testCommandEnds() { + commandScheduler.run(); + ColorSensorV3Wrapped.setRGBD(2500, 0, 0, 900); + commandScheduler.run(); + assertEquals(true, intakeCommand.isFinished(), "Command should be finished when ending"); + assertEquals(0, intakeMotor.get(), "Motor should stop after detecting color"); + } } From 9773045377703c9be98acc3b43c15cec8b48061a Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Sat, 20 Apr 2024 23:23:48 +0300 Subject: [PATCH 25/43] add more tests to basic shooter command tests --- .../arm_tests/BasicShooterTest.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/test/java/command_tests/arm_tests/BasicShooterTest.java b/src/test/java/command_tests/arm_tests/BasicShooterTest.java index a02f679..b117a2b 100644 --- a/src/test/java/command_tests/arm_tests/BasicShooterTest.java +++ b/src/test/java/command_tests/arm_tests/BasicShooterTest.java @@ -1,6 +1,7 @@ package command_tests.arm_tests; import static org.junit.jupiter.api.Assertions.assertEquals; +import static utils.LEDTestUtils.testAtTime; import command_tests.utils.CommandTestBase; import edu.wpi.first.wpilibj.Timer; @@ -15,15 +16,16 @@ class BasicShooterTest extends CommandTestBase { private ShooterSubsystem shooterSubsystem; private PWMSim shooterMotor; - private BasicRunShooterCommand basicShooterCommand; - private static final double waitTime = 2; + + private static final double kWaitTime = 2; @BeforeEach public void setUp() { super.setUp(); shooterSubsystem = new ShooterSubsystem(); shooterMotor = new PWMSim(ShooterConstants.kShooterMotorPwmID); - basicShooterCommand = new BasicRunShooterCommand(shooterSubsystem, waitTime); + BasicRunShooterCommand basicShooterCommand = + new BasicRunShooterCommand(shooterSubsystem, kWaitTime); commandScheduler.schedule(basicShooterCommand); } @@ -42,23 +44,21 @@ void testSetSpeed() { ShooterConstants.kShooterSpeed, shooterMotor.getSpeed(), "Shooter motor should be at shooter speed"); - Timer.delay(waitTime); + Timer.delay(kWaitTime); commandScheduler.run(); // Motor should be at 0 after waitTime assertEquals( 0, shooterMotor.getSpeed(), - "Shooter motor should be at 0 after %s seconds".formatted(waitTime)); + "Shooter motor should be at 0 after %s seconds".formatted(kWaitTime)); } - // @Test - // void testLEDLoading() { - // commandScheduler.run(); - // Timer.delay(waitTime - 0.2); // let led loop do its thing - // commandScheduler.run(); - // // LED should be green after waitTime - // checkForColorInAll( - // ledSubsystem, LEDLoadingWaitCommand.DEFAULT_COLOR, "Color should be green after - // waitTime"); - // } + @Test + void testLEDLoading() { + double startTime = Timer.getFPGATimestamp(); + commandScheduler.run(); + Timer.delay(kWaitTime); // load waitTime + commandScheduler.run(); + testAtTime(ledSubsystem, startTime, kWaitTime); + } } From 0e8c5318d3f528f207cd29b08afb1faa8cedc711 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Sat, 20 Apr 2024 23:25:38 +0300 Subject: [PATCH 26/43] rename led tests --- src/test/java/subsystem_tests/led_tests/LedTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/subsystem_tests/led_tests/LedTests.java b/src/test/java/subsystem_tests/led_tests/LedTests.java index bbcc079..48420bc 100644 --- a/src/test/java/subsystem_tests/led_tests/LedTests.java +++ b/src/test/java/subsystem_tests/led_tests/LedTests.java @@ -1,4 +1,4 @@ -package subsystem_tests.led_integration_tests; +package subsystem_tests.led_tests; import static org.junit.jupiter.api.Assertions.assertEquals; import static utils.LEDTestUtils.checkForColorInAll; From e578a4537ab0e96f12d417d1d22309d4f9fdd1ba Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Mon, 22 Apr 2024 18:07:13 +0300 Subject: [PATCH 27/43] move LedTestUtils to led_tests folder --- src/test/java/subsystem_tests/led_tests/LedTests.java | 4 ++-- .../{ => subsystem_tests/led_tests}/utils/LEDTestUtils.java | 0 2 files changed, 2 insertions(+), 2 deletions(-) rename src/test/java/{ => subsystem_tests/led_tests}/utils/LEDTestUtils.java (100%) diff --git a/src/test/java/subsystem_tests/led_tests/LedTests.java b/src/test/java/subsystem_tests/led_tests/LedTests.java index 48420bc..e99a3aa 100644 --- a/src/test/java/subsystem_tests/led_tests/LedTests.java +++ b/src/test/java/subsystem_tests/led_tests/LedTests.java @@ -1,8 +1,8 @@ package subsystem_tests.led_tests; import static org.junit.jupiter.api.Assertions.assertEquals; -import static utils.LEDTestUtils.checkForColorInAll; -import static utils.LEDTestUtils.getColorAtIndex; +import static subsystem_tests.led_tests.utils.LEDTestUtils.checkForColorInAll; +import static subsystem_tests.led_tests.utils.LEDTestUtils.getColorAtIndex; import edu.wpi.first.hal.HAL; import edu.wpi.first.wpilibj.Timer; diff --git a/src/test/java/utils/LEDTestUtils.java b/src/test/java/subsystem_tests/led_tests/utils/LEDTestUtils.java similarity index 100% rename from src/test/java/utils/LEDTestUtils.java rename to src/test/java/subsystem_tests/led_tests/utils/LEDTestUtils.java From 4ab56b51d552541cd28ca1bbab13e90032deb505 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Mon, 22 Apr 2024 18:07:49 +0300 Subject: [PATCH 28/43] make MoveArmToAmp public --- src/main/java/frc/robot/commands/MoveArmToAmp.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/frc/robot/commands/MoveArmToAmp.java b/src/main/java/frc/robot/commands/MoveArmToAmp.java index b0c6383..3f64182 100644 --- a/src/main/java/frc/robot/commands/MoveArmToAmp.java +++ b/src/main/java/frc/robot/commands/MoveArmToAmp.java @@ -4,7 +4,7 @@ import frc.robot.subsystems.ArmSubsystem; public class MoveArmToAmp extends SequentialCommandGroup { - MoveArmToAmp(ArmSubsystem armSubsystem) { + public MoveArmToAmp(ArmSubsystem armSubsystem) { super( armSubsystem .run(() -> armSubsystem.setArmToPosition(0.5)) From f83becbf959e2643cc8bf7557e69db84f6b03791 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Mon, 22 Apr 2024 18:08:33 +0300 Subject: [PATCH 29/43] Remove Really Simple Auto --- src/main/java/frc/robot/RobotContainer.java | 4 ---- .../frc/robot/commands/ReallySimpleAuto.java | 20 ------------------- 2 files changed, 24 deletions(-) delete mode 100644 src/main/java/frc/robot/commands/ReallySimpleAuto.java diff --git a/src/main/java/frc/robot/RobotContainer.java b/src/main/java/frc/robot/RobotContainer.java index 530e0bc..2621e96 100644 --- a/src/main/java/frc/robot/RobotContainer.java +++ b/src/main/java/frc/robot/RobotContainer.java @@ -20,7 +20,6 @@ import frc.robot.Constants.IntakeConstants; import frc.robot.commands.ArmIdleCommand; import frc.robot.commands.BasicIntakeCommand; -import frc.robot.commands.ReallySimpleAuto; import frc.robot.commands.ShootToAmpCommand; import frc.robot.commands.SmartIntakeCommand; import frc.robot.commands.SmartShootCommand; @@ -58,9 +57,6 @@ public RobotContainer() { "Shoot To Shooter", new SmartShootCommand(shooterSubsystem, intakeSubsystem, armSubsystem, driveSubsystem)); PhotonCameraSystem.getAprilTagWithID(0); // Load the class before enable. - autoChooser.addOption( - "Shoot & Back", - new ReallySimpleAuto(armSubsystem, intakeSubsystem, shooterSubsystem, driveSubsystem)); SmartDashboard.putData("Auto Chooser", autoChooser); if (RobotBase.isSimulation()) { simInit(); diff --git a/src/main/java/frc/robot/commands/ReallySimpleAuto.java b/src/main/java/frc/robot/commands/ReallySimpleAuto.java deleted file mode 100644 index efc747b..0000000 --- a/src/main/java/frc/robot/commands/ReallySimpleAuto.java +++ /dev/null @@ -1,20 +0,0 @@ -package frc.robot.commands; - -import edu.wpi.first.wpilibj2.command.SequentialCommandGroup; -import edu.wpi.first.wpilibj2.command.WaitCommand; -import frc.robot.subsystems.ArmSubsystem; -import frc.robot.subsystems.DriveSubsystem; -import frc.robot.subsystems.IntakeSubsystem; -import frc.robot.subsystems.ShooterSubsystem; - -public class ReallySimpleAuto extends SequentialCommandGroup { - public ReallySimpleAuto( - ArmSubsystem armSubsystem, - IntakeSubsystem intakeSubsystem, - ShooterSubsystem shooterSubsystem, - DriveSubsystem driveSubsystem) { - super( - new SmartShootCommand(shooterSubsystem, intakeSubsystem, armSubsystem, driveSubsystem), - driveSubsystem.run(() -> driveSubsystem.drive(-0.25, 0, 0)).raceWith(new WaitCommand(2.5))); - } -} From 899ef8d3a35c047223ebfad957bf57c457f3bab3 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Mon, 22 Apr 2024 18:12:28 +0300 Subject: [PATCH 30/43] move LEDTestUtils to led_tests folder (fix imports) --- src/test/java/command_tests/LEDIdleCommandTest.java | 2 +- src/test/java/command_tests/arm_tests/BasicIntakeTest.java | 2 +- src/test/java/command_tests/arm_tests/BasicShooterTest.java | 2 +- src/test/java/subsystem_tests/led_tests/utils/LEDTestUtils.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/command_tests/LEDIdleCommandTest.java b/src/test/java/command_tests/LEDIdleCommandTest.java index 29d668b..754da1f 100644 --- a/src/test/java/command_tests/LEDIdleCommandTest.java +++ b/src/test/java/command_tests/LEDIdleCommandTest.java @@ -1,6 +1,6 @@ package command_tests; -import static utils.LEDTestUtils.checkForColorInAll; +import static subsystem_tests.led_tests.utils.LEDTestUtils.checkForColorInAll; import command_tests.utils.CommandTestBase; import edu.wpi.first.hal.HAL; diff --git a/src/test/java/command_tests/arm_tests/BasicIntakeTest.java b/src/test/java/command_tests/arm_tests/BasicIntakeTest.java index 653a0cf..e73f538 100644 --- a/src/test/java/command_tests/arm_tests/BasicIntakeTest.java +++ b/src/test/java/command_tests/arm_tests/BasicIntakeTest.java @@ -2,7 +2,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static utils.LEDTestUtils.checkForColorInAll; +import static subsystem_tests.led_tests.utils.LEDTestUtils.checkForColorInAll; import com.revrobotics.CANSparkMax; import command_tests.utils.CommandTestBase; diff --git a/src/test/java/command_tests/arm_tests/BasicShooterTest.java b/src/test/java/command_tests/arm_tests/BasicShooterTest.java index b117a2b..0f704bf 100644 --- a/src/test/java/command_tests/arm_tests/BasicShooterTest.java +++ b/src/test/java/command_tests/arm_tests/BasicShooterTest.java @@ -1,7 +1,7 @@ package command_tests.arm_tests; import static org.junit.jupiter.api.Assertions.assertEquals; -import static utils.LEDTestUtils.testAtTime; +import static subsystem_tests.led_tests.utils.LEDTestUtils.testAtTime; import command_tests.utils.CommandTestBase; import edu.wpi.first.wpilibj.Timer; diff --git a/src/test/java/subsystem_tests/led_tests/utils/LEDTestUtils.java b/src/test/java/subsystem_tests/led_tests/utils/LEDTestUtils.java index 801c6df..ba3593b 100644 --- a/src/test/java/subsystem_tests/led_tests/utils/LEDTestUtils.java +++ b/src/test/java/subsystem_tests/led_tests/utils/LEDTestUtils.java @@ -1,4 +1,4 @@ -package utils; +package subsystem_tests.led_tests.utils; import static org.junit.jupiter.api.Assertions.assertEquals; From c808b79ff14fcea3ab6783d03cc7414b3ccf49c7 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Mon, 22 Apr 2024 18:13:04 +0300 Subject: [PATCH 31/43] make ArmSubsystem Closable --- src/main/java/frc/robot/subsystems/ArmSubsystem.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/frc/robot/subsystems/ArmSubsystem.java b/src/main/java/frc/robot/subsystems/ArmSubsystem.java index be10b1b..1c55235 100644 --- a/src/main/java/frc/robot/subsystems/ArmSubsystem.java +++ b/src/main/java/frc/robot/subsystems/ArmSubsystem.java @@ -16,7 +16,7 @@ import frc.utils.ExtraFunctions; import frc.utils.sim_utils.CANSparkMAXWrapped; -public class ArmSubsystem extends SubsystemBase { +public class ArmSubsystem extends SubsystemBase implements AutoCloseable { // We only have RelativeEncoder for now. Its better than nothing. private final CANSparkMAXWrapped arm; private final CANSparkMAXWrapped armFollower; @@ -63,6 +63,12 @@ private void setupSparkMax() { arm.burnFlash(); } + @Override + public void close() { + arm.close(); + armFollower.close(); + } + /** * Sets the arm to a position. This is a wrapper for the Spark Max's set method. * From b662fb64d2bb8a1f251b5b967ab6046ed9c5bdf2 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Mon, 22 Apr 2024 18:13:18 +0300 Subject: [PATCH 32/43] add docs to LEDSubsystem --- src/main/java/frc/robot/subsystems/LEDSubsystem.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/frc/robot/subsystems/LEDSubsystem.java b/src/main/java/frc/robot/subsystems/LEDSubsystem.java index 159f9a7..9b22f41 100644 --- a/src/main/java/frc/robot/subsystems/LEDSubsystem.java +++ b/src/main/java/frc/robot/subsystems/LEDSubsystem.java @@ -97,6 +97,12 @@ public void blinkRed() { blink(new Color(255, 0, 0)); } + /** + * Fills the led's until the given percentage. + * + * @param percentage a value between 0 and 1 + * @param color the color to fill with + */ public void fillPercentageWithColor(double percentage, Color color) { fill(color, (int) (strip.getLedCount() * percentage), true); } From c7f3985e4687f27dfc1f73042cb28c63f9e70cbb Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Thu, 25 Apr 2024 00:49:45 +0300 Subject: [PATCH 33/43] Slightly improve vibrate controller command I know that this still has multiple wait commands for no reason, and we create a lot of commands for no reason. But it should still work for now, I will optimize this command in the future tho --- .../robot/commands/VibrateControllerCommand.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/frc/robot/commands/VibrateControllerCommand.java b/src/main/java/frc/robot/commands/VibrateControllerCommand.java index 91821e8..d718023 100644 --- a/src/main/java/frc/robot/commands/VibrateControllerCommand.java +++ b/src/main/java/frc/robot/commands/VibrateControllerCommand.java @@ -24,15 +24,15 @@ public VibrateControllerCommand(XboxController controller, int repetitions) { private static Command createVibrateControllerCommand( XboxController controller, int repetitions, double intensity, double duration) { - Command command = - new InstantCommand(() -> controller.setRumble(RumbleType.kBothRumble, intensity)); + SequentialCommandGroup command = + new SequentialCommandGroup( + new InstantCommand(() -> controller.setRumble(RumbleType.kBothRumble, intensity))); for (int i = 0; i < repetitions; i++) { - command = - command - .andThen(new WaitCommand(duration)) - .andThen(() -> controller.setRumble(RumbleType.kBothRumble, 0)) - .andThen(new WaitCommand(duration)) - .andThen(() -> controller.setRumble(RumbleType.kBothRumble, intensity)); + command.addCommands( + new WaitCommand(duration), + new InstantCommand(() -> controller.setRumble(RumbleType.kBothRumble, 0)), + new WaitCommand(duration), + new InstantCommand(() -> controller.setRumble(RumbleType.kBothRumble, intensity))); } return command.finallyDo(() -> controller.setRumble(RumbleType.kBothRumble, 0)); } From f6af74b1bad6a76186527559d052bc72728bf4f6 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Thu, 25 Apr 2024 00:51:10 +0300 Subject: [PATCH 34/43] unregister subsystems after each test I should have realized this is why intake subsystem was causing problems LMAO... --- src/test/java/command_tests/utils/CommandTestBase.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/java/command_tests/utils/CommandTestBase.java b/src/test/java/command_tests/utils/CommandTestBase.java index 9a004d1..ad1c49d 100644 --- a/src/test/java/command_tests/utils/CommandTestBase.java +++ b/src/test/java/command_tests/utils/CommandTestBase.java @@ -28,6 +28,8 @@ protected void setUp() { protected void tearDown() { LEDSystem.resetLEDSubsystem(); commandScheduler.cancelAll(); + commandScheduler.unregisterAllSubsystems(); // ! breaks all test tests if not done commandScheduler.close(); + HAL.shutdown(); } } From 927db0a2d028472f552b526809b8056c70949ee9 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Fri, 26 Apr 2024 00:39:37 +0300 Subject: [PATCH 35/43] Create WaitANDConditionCommandTest.java --- .../WaitANDConditionCommandTest.java | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 src/test/java/command_tests/simple_command_tests/WaitANDConditionCommandTest.java diff --git a/src/test/java/command_tests/simple_command_tests/WaitANDConditionCommandTest.java b/src/test/java/command_tests/simple_command_tests/WaitANDConditionCommandTest.java new file mode 100644 index 0000000..210018c --- /dev/null +++ b/src/test/java/command_tests/simple_command_tests/WaitANDConditionCommandTest.java @@ -0,0 +1,61 @@ +package command_tests.simple_command_tests; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import command_tests.utils.CommandTestBase; +import edu.wpi.first.wpilibj.Timer; +import frc.robot.commands.WaitANDConditionCommand; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class WaitANDConditionCommandTest extends CommandTestBase { + private WaitANDConditionCommand waitConditionCommand; + private static double kWaitTime = 2.0; + private boolean condition; + + @BeforeEach + public void setUp() { + super.setUp(); + + condition = false; + + waitConditionCommand = new WaitANDConditionCommand(kWaitTime, () -> condition); + commandScheduler.schedule(waitConditionCommand); + } + + @AfterEach + public void tearDown() { + super.tearDown(); + } + + @Test + void testItCompletesOnCondition() { + commandScheduler.run(); + condition = true; + commandScheduler.run(); + assertFalse( + waitConditionCommand.isFinished(), + "command should not finish after condition true without time finish"); + } + + @Test + void testItCompletesAfterTime() { + commandScheduler.run(); + Timer.delay(kWaitTime); + commandScheduler.run(); + assertFalse( + waitConditionCommand.isFinished(), + "Command should not finish after time finishes without condition"); + } + + @Test + void testItFinishesAfterAll() { + commandScheduler.run(); + condition = true; + Timer.delay(kWaitTime); + commandScheduler.run(); + assertTrue(waitConditionCommand.isFinished(), "Command should finish after time and condition"); + } +} From f484f753ad9438be7384b8b7a26c7af507663c3d Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Fri, 26 Apr 2024 00:39:47 +0300 Subject: [PATCH 36/43] Create MoveArmToAmpTest.java --- .../arm_tests/MoveArmToAmpTest.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/test/java/command_tests/arm_tests/MoveArmToAmpTest.java diff --git a/src/test/java/command_tests/arm_tests/MoveArmToAmpTest.java b/src/test/java/command_tests/arm_tests/MoveArmToAmpTest.java new file mode 100644 index 0000000..72442da --- /dev/null +++ b/src/test/java/command_tests/arm_tests/MoveArmToAmpTest.java @@ -0,0 +1,40 @@ +package command_tests.arm_tests; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import command_tests.utils.CommandTestBase; +import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard; +import frc.robot.commands.MoveArmToAmp; +import frc.robot.subsystems.ArmSubsystem; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class MoveArmToAmpTest extends CommandTestBase { + private MoveArmToAmp moveArmToAmpCommand; + private ArmSubsystem armSubsystem; + + @BeforeEach + public void setUp() { + super.setUp(); + + armSubsystem = new ArmSubsystem(); + moveArmToAmpCommand = new MoveArmToAmp(armSubsystem); + commandScheduler.schedule(moveArmToAmpCommand); + } + + @AfterEach + public void tearDown() { + super.tearDown(); + armSubsystem.close(); + } + + @Test + void testArmSetpointIsTrue() { + commandScheduler.run(); + double setpoint = SmartDashboard.getNumber("Setpoint", -1); + + // !if this value 0.5 is changed or moved to a constant instead (it should be) change this + assertEquals(0.5, setpoint, "Arm should have been on 0.5 (meaning the amp)"); + } +} From 1398ba8d4aed70fd80b2ba42a04c946b760b241e Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Fri, 26 Apr 2024 00:39:53 +0300 Subject: [PATCH 37/43] Create VibrateControllerCommandTest.java --- .../VibrateControllerCommandTest.java | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 src/test/java/command_tests/controller_commands/VibrateControllerCommandTest.java diff --git a/src/test/java/command_tests/controller_commands/VibrateControllerCommandTest.java b/src/test/java/command_tests/controller_commands/VibrateControllerCommandTest.java new file mode 100644 index 0000000..2e4f5d2 --- /dev/null +++ b/src/test/java/command_tests/controller_commands/VibrateControllerCommandTest.java @@ -0,0 +1,80 @@ +package command_tests.controller_commands; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import command_tests.utils.CommandTestBase; +import edu.wpi.first.wpilibj.GenericHID.RumbleType; +import edu.wpi.first.wpilibj.Timer; +import edu.wpi.first.wpilibj.XboxController; +import edu.wpi.first.wpilibj.simulation.XboxControllerSim; +import frc.robot.commands.VibrateControllerCommand; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class VibrateControllerCommandTest extends CommandTestBase { + private VibrateControllerCommand vibrateControllerCommand; + private XboxController controller; + private XboxControllerSim controllerSim; + + private static final double kDelta = 0.01; + + private static final int kRepetitions = 3; + private static final double kIntensity = 0.5; // 0.5 due to a bug in the simulator + private static final double kWaitTime = 1.5; + + @BeforeEach + public void setUp() { + super.setUp(); + + controller = new XboxController(1); + controllerSim = new XboxControllerSim(1); + vibrateControllerCommand = + new VibrateControllerCommand(controller, kRepetitions, kIntensity, kWaitTime); + commandScheduler.schedule(vibrateControllerCommand); + } + + @AfterEach + public void tearDown() { + super.tearDown(); + } + + @Test + void testItVibrates() { + commandScheduler.run(); + assertEquals(kIntensity, controllerSim.getRumble(RumbleType.kLeftRumble), kDelta); + } + + @Test + void testItStopsVibrating() { + commandScheduler.run(); + Timer.delay(kWaitTime); + commandScheduler.run(); + assertEquals(0, controllerSim.getRumble(RumbleType.kLeftRumble), kDelta); + } + + @Test + void testItRepeats() { + // run command scheduler twice to end wait command and start vibration + for (int i = 0; i < kRepetitions; i++) { + commandScheduler.run(); + commandScheduler.run(); + assertEquals( + kIntensity, + controllerSim.getRumble(RumbleType.kLeftRumble), + kDelta, + "controller should vibrate at index: " + i); + Timer.delay(kWaitTime + 0.1); + commandScheduler.run(); + commandScheduler.run(); + assertEquals( + 0, + controllerSim.getRumble(RumbleType.kLeftRumble), + kDelta, + "controller should stop vibrating at index: " + i); + Timer.delay(kWaitTime + 0.1); + commandScheduler.run(); + commandScheduler.run(); + } + } +} From 88fd7fdef8985c2f26f9554e6be72a502f8012c4 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Fri, 26 Apr 2024 00:39:57 +0300 Subject: [PATCH 38/43] Create LEDWaitingCommandTest.java --- .../LEDWaitingCommandTest.java | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 src/test/java/command_tests/simple_command_tests/LEDWaitingCommandTest.java diff --git a/src/test/java/command_tests/simple_command_tests/LEDWaitingCommandTest.java b/src/test/java/command_tests/simple_command_tests/LEDWaitingCommandTest.java new file mode 100644 index 0000000..0fff8fc --- /dev/null +++ b/src/test/java/command_tests/simple_command_tests/LEDWaitingCommandTest.java @@ -0,0 +1,64 @@ +package command_tests.simple_command_tests; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static subsystem_tests.led_tests.utils.LEDTestUtils.testAtTime; + +import command_tests.utils.CommandTestBase; +import edu.wpi.first.wpilibj.Timer; +import frc.robot.commands.led_commands.LEDLoadingWaitCommand; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class LEDWaitingCommandTest extends CommandTestBase { + private static final double kWaitTime = 2.0; + private LEDLoadingWaitCommand ledLoadingWaitCommand; + + @BeforeEach + public void setUp() { + super.setUp(); + ledLoadingWaitCommand = new LEDLoadingWaitCommand(kWaitTime); + commandScheduler.schedule(ledLoadingWaitCommand); + } + + @AfterEach + public void tearDown() { + super.tearDown(); + } + + void testLEDLoading(double waitTime) { + double startTime = Timer.getFPGATimestamp(); + for (double i = 0.1; Timer.getFPGATimestamp() - startTime + i < waitTime; i += 0.1) { + Timer.delay(i); + commandScheduler.run(); + testAtTime(ledSubsystem, startTime, waitTime); + } + } + + /** + * This test takes a lot of time as it tries a lot of differently timed {@link + * LEDLoadingWaitCommand}s + */ + @Test + void testLEDLoading() { + // try multiple wait times, just so we can do it + for (double i = 0.0; i <= 6; i += 1.2) { + commandScheduler.cancelAll(); + commandScheduler.schedule(new LEDLoadingWaitCommand(i)); + commandScheduler.run(); + testLEDLoading(i); + } + } + + @Test + void itActuallyEnds() { + commandScheduler.run(); + assertEquals( + false, + ledLoadingWaitCommand.isFinished(), + "led wait command shouldn't finish before wait time"); + Timer.delay(kWaitTime); // just in case add a little bit extra time + assertEquals( + true, ledLoadingWaitCommand.isFinished(), "led wait command should finish after wait time"); + } +} From 6b443fb79089db81d6613e1885dd73ffc01f2937 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Fri, 26 Apr 2024 00:42:24 +0300 Subject: [PATCH 39/43] exclude logs from being formatted Opps, should have done this before ngl... --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index d754ad3..1d18eb8 100644 --- a/build.gradle +++ b/build.gradle @@ -9,7 +9,7 @@ spotless { java { target fileTree('.') { include '**/*.java' - exclude '**/build/**', '**/build-*/**' + exclude '**/build/**', '**/build-*/**', '**/logs/**' } toggleOffOn() googleJavaFormat('1.19.1') From 697a810391a35fdf1ebeb1f14e6dfe76cf73a373 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Fri, 26 Apr 2024 01:26:35 +0300 Subject: [PATCH 40/43] improve comment in vibrate controller command's test --- .../controller_commands/VibrateControllerCommandTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/command_tests/controller_commands/VibrateControllerCommandTest.java b/src/test/java/command_tests/controller_commands/VibrateControllerCommandTest.java index 2e4f5d2..e9b2ecd 100644 --- a/src/test/java/command_tests/controller_commands/VibrateControllerCommandTest.java +++ b/src/test/java/command_tests/controller_commands/VibrateControllerCommandTest.java @@ -55,7 +55,7 @@ void testItStopsVibrating() { @Test void testItRepeats() { - // run command scheduler twice to end wait command and start vibration + // run command scheduler twice to end wait command and start vibration command for (int i = 0; i < kRepetitions; i++) { commandScheduler.run(); commandScheduler.run(); From 14ba01a0fd24078365f87eee4408964980edd268 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Fri, 26 Apr 2024 01:27:04 +0300 Subject: [PATCH 41/43] make controller a local scope variable in vibrate controller test --- .../controller_commands/VibrateControllerCommandTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/java/command_tests/controller_commands/VibrateControllerCommandTest.java b/src/test/java/command_tests/controller_commands/VibrateControllerCommandTest.java index e9b2ecd..5ac6954 100644 --- a/src/test/java/command_tests/controller_commands/VibrateControllerCommandTest.java +++ b/src/test/java/command_tests/controller_commands/VibrateControllerCommandTest.java @@ -14,7 +14,6 @@ class VibrateControllerCommandTest extends CommandTestBase { private VibrateControllerCommand vibrateControllerCommand; - private XboxController controller; private XboxControllerSim controllerSim; private static final double kDelta = 0.01; @@ -27,7 +26,7 @@ class VibrateControllerCommandTest extends CommandTestBase { public void setUp() { super.setUp(); - controller = new XboxController(1); + XboxController controller = new XboxController(1); controllerSim = new XboxControllerSim(1); vibrateControllerCommand = new VibrateControllerCommand(controller, kRepetitions, kIntensity, kWaitTime); From c2581c4382b35b9d8738d2a97d8b46f2059a7e14 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Fri, 26 Apr 2024 01:28:13 +0300 Subject: [PATCH 42/43] create a new RepeatForCommand class This extends the RepeatCommand to make it repeat for a given amount of times. This is very cool in my opinion and is very easy to implement, I should just implement this in wpilib itself, with an extra variable count --- .../util_commands/RepeatForCommand.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/main/java/frc/robot/commands/util_commands/RepeatForCommand.java diff --git a/src/main/java/frc/robot/commands/util_commands/RepeatForCommand.java b/src/main/java/frc/robot/commands/util_commands/RepeatForCommand.java new file mode 100644 index 0000000..07f8636 --- /dev/null +++ b/src/main/java/frc/robot/commands/util_commands/RepeatForCommand.java @@ -0,0 +1,35 @@ +package frc.robot.commands.util_commands; + +import edu.wpi.first.wpilibj2.command.Command; +import edu.wpi.first.wpilibj2.command.RepeatCommand; + +public class RepeatForCommand extends RepeatCommand { + private double count; + private Command command; + + /** + * Repeats a command for a specified number of times + * + * @param command The command to repeat + * @param count The number of times to repeat the command + */ + public RepeatForCommand(Command command, int count) { + super(command); + this.command = command; + this.count = count; + } + + @Override + public void execute() { + // only decrement the count if the command has finished + if (command.isFinished()) { + count--; + } + super.execute(); + } + + @Override + public boolean isFinished() { + return count <= 0; + } +} From a9e3a3af73e67e920e2196ad852b194c9a615772 Mon Sep 17 00:00:00 2001 From: Kaya <95276965+kytpbs@users.noreply.github.com> Date: Fri, 26 Apr 2024 01:28:38 +0300 Subject: [PATCH 43/43] Change Vibrate Controller Command to use the new RepeatFor command --- .../commands/VibrateControllerCommand.java | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/main/java/frc/robot/commands/VibrateControllerCommand.java b/src/main/java/frc/robot/commands/VibrateControllerCommand.java index d718023..818a952 100644 --- a/src/main/java/frc/robot/commands/VibrateControllerCommand.java +++ b/src/main/java/frc/robot/commands/VibrateControllerCommand.java @@ -6,6 +6,7 @@ import edu.wpi.first.wpilibj2.command.InstantCommand; import edu.wpi.first.wpilibj2.command.SequentialCommandGroup; import edu.wpi.first.wpilibj2.command.WaitCommand; +import frc.robot.commands.util_commands.RepeatForCommand; public class VibrateControllerCommand extends SequentialCommandGroup { public VibrateControllerCommand( @@ -24,16 +25,13 @@ public VibrateControllerCommand(XboxController controller, int repetitions) { private static Command createVibrateControllerCommand( XboxController controller, int repetitions, double intensity, double duration) { - SequentialCommandGroup command = + SequentialCommandGroup toRepeatCommand = new SequentialCommandGroup( - new InstantCommand(() -> controller.setRumble(RumbleType.kBothRumble, intensity))); - for (int i = 0; i < repetitions; i++) { - command.addCommands( - new WaitCommand(duration), - new InstantCommand(() -> controller.setRumble(RumbleType.kBothRumble, 0)), - new WaitCommand(duration), - new InstantCommand(() -> controller.setRumble(RumbleType.kBothRumble, intensity))); - } - return command.finallyDo(() -> controller.setRumble(RumbleType.kBothRumble, 0)); + new InstantCommand(() -> controller.setRumble(RumbleType.kBothRumble, intensity)), // + new WaitCommand(duration), + new InstantCommand(() -> controller.setRumble(RumbleType.kBothRumble, 0)), + new WaitCommand(duration)); + + return new RepeatForCommand(toRepeatCommand, repetitions); } }