From 9071d528f981a76392eae60abc681737105cc436 Mon Sep 17 00:00:00 2001 From: SCool62 Date: Thu, 15 Jan 2026 22:30:53 -0800 Subject: [PATCH 01/28] Add tests to sourcePaths (for intellisense etc.) --- .vscode/settings.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 7399d64..90f20de 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -59,5 +59,9 @@ ], "java.dependency.enableDependencyCheckup": false, "wpilib.selectDefaultSimulateExtension": false, - "wpilib.skipSelectSimulateExtension": true + "wpilib.skipSelectSimulateExtension": true, + "java.project.sourcePaths": [ + "src/main", + "src/test" + ] } From b04b92656608ee0fa4851078e9daa43f0e0090ce Mon Sep 17 00:00:00 2001 From: SCool62 Date: Thu, 15 Jan 2026 22:46:22 -0800 Subject: [PATCH 02/28] Impl AutoCloseable where nessesary --- src/main/java/frc/robot/Superstructure.java | 10 +++++++++- .../java/frc/robot/components/camera/Camera.java | 7 ++++++- .../java/frc/robot/components/camera/CameraIO.java | 2 +- .../frc/robot/components/camera/CameraIOReal.java | 5 +++++ .../frc/robot/components/camera/CameraIOSim.java | 6 ++++++ .../java/frc/robot/subsystems/IntakeSubsystem.java | 7 ++++++- .../java/frc/robot/subsystems/RoutingSubsystem.java | 7 ++++++- .../java/frc/robot/subsystems/ShooterSubsystem.java | 9 ++++++++- .../robot/subsystems/swerve/SwerveSubsystem.java | 13 ++++++++++++- .../frc/robot/subsystems/swerve/gyro/GyroIO.java | 2 +- .../robot/subsystems/swerve/gyro/GyroIOReal.java | 5 +++++ .../frc/robot/subsystems/swerve/gyro/GyroIOSim.java | 5 +++++ .../frc/robot/subsystems/swerve/module/Module.java | 7 ++++++- .../subsystems/swerve/module/ModuleIOReal.java | 9 ++++++++- 14 files changed, 84 insertions(+), 10 deletions(-) diff --git a/src/main/java/frc/robot/Superstructure.java b/src/main/java/frc/robot/Superstructure.java index f5da6c0..16b3879 100644 --- a/src/main/java/frc/robot/Superstructure.java +++ b/src/main/java/frc/robot/Superstructure.java @@ -17,7 +17,7 @@ import org.littletonrobotics.junction.AutoLogOutput; import org.littletonrobotics.junction.Logger; -public class Superstructure { +public class Superstructure implements AutoCloseable { /** We should have a state for every single action the robot will perform. */ public enum SuperState { @@ -281,4 +281,12 @@ public static SuperState getState() { public boolean stateIsIdle() { return getState() == SuperState.IDLE; } + + @Override + public void close() throws Exception { + intake.close(); + shooter.close(); + routing.close(); + swerve.close(); + } } diff --git a/src/main/java/frc/robot/components/camera/Camera.java b/src/main/java/frc/robot/components/camera/Camera.java index c26cc50..fd06a1e 100644 --- a/src/main/java/frc/robot/components/camera/Camera.java +++ b/src/main/java/frc/robot/components/camera/Camera.java @@ -30,7 +30,7 @@ import org.photonvision.targeting.PhotonTrackedTarget; /** Add your docs here. */ -public class Camera { +public class Camera implements AutoCloseable{ // The intrinsics and distortion coefficients are only actually used for sim public record CameraConstants( @@ -217,4 +217,9 @@ public CameraConstants getCameraConstants() { public Pose3d getPose() { return pose; } + + @Override + public void close() throws Exception { + io.close(); + } } diff --git a/src/main/java/frc/robot/components/camera/CameraIO.java b/src/main/java/frc/robot/components/camera/CameraIO.java index edf991c..0c2297d 100644 --- a/src/main/java/frc/robot/components/camera/CameraIO.java +++ b/src/main/java/frc/robot/components/camera/CameraIO.java @@ -11,7 +11,7 @@ import org.photonvision.targeting.PhotonPipelineResult; /** Add your docs here. */ -public interface CameraIO { +public interface CameraIO extends AutoCloseable { @AutoLog public static class CameraIOInputs { public PhotonPipelineResult result = new PhotonPipelineResult(); diff --git a/src/main/java/frc/robot/components/camera/CameraIOReal.java b/src/main/java/frc/robot/components/camera/CameraIOReal.java index 6bbf9ed..8c7dc17 100644 --- a/src/main/java/frc/robot/components/camera/CameraIOReal.java +++ b/src/main/java/frc/robot/components/camera/CameraIOReal.java @@ -46,4 +46,9 @@ public void setSimPose(Optional simEst, boolean newResult) { public CameraConstants getCameraConstants() { return constants; } + + @Override + public void close() throws Exception { + camera.close(); + } } diff --git a/src/main/java/frc/robot/components/camera/CameraIOSim.java b/src/main/java/frc/robot/components/camera/CameraIOSim.java index b6a40a6..7f7c270 100644 --- a/src/main/java/frc/robot/components/camera/CameraIOSim.java +++ b/src/main/java/frc/robot/components/camera/CameraIOSim.java @@ -88,4 +88,10 @@ public String getName() { public CameraConstants getCameraConstants() { return constants; } + + @Override + public void close() throws Exception { + camera.close(); + simCamera.close(); + } } diff --git a/src/main/java/frc/robot/subsystems/IntakeSubsystem.java b/src/main/java/frc/robot/subsystems/IntakeSubsystem.java index 80f7af6..be1ac1a 100644 --- a/src/main/java/frc/robot/subsystems/IntakeSubsystem.java +++ b/src/main/java/frc/robot/subsystems/IntakeSubsystem.java @@ -4,7 +4,7 @@ import edu.wpi.first.wpilibj2.command.SubsystemBase; // TODO -public class IntakeSubsystem extends SubsystemBase { +public class IntakeSubsystem extends SubsystemBase implements AutoCloseable { public Command intake() { // TODO return idle(); @@ -20,4 +20,9 @@ public Command spit() { // TODO return idle(); } + + @Override + public void close() throws Exception { + // Currently does nothing bc nothing to close + } } diff --git a/src/main/java/frc/robot/subsystems/RoutingSubsystem.java b/src/main/java/frc/robot/subsystems/RoutingSubsystem.java index 8bd19e0..325a3e6 100644 --- a/src/main/java/frc/robot/subsystems/RoutingSubsystem.java +++ b/src/main/java/frc/robot/subsystems/RoutingSubsystem.java @@ -4,7 +4,7 @@ import edu.wpi.first.wpilibj2.command.SubsystemBase; // TODO!!! -public class RoutingSubsystem extends SubsystemBase { +public class RoutingSubsystem extends SubsystemBase implements AutoCloseable { // TODO: BASE ON ACTUAL SENSOR READINGS private boolean isFull; @@ -33,4 +33,9 @@ public Command reverseIndex() { // TODO return this.run(() -> {}); } + + @Override + public void close() throws Exception { + // Currently nothing to close + } } diff --git a/src/main/java/frc/robot/subsystems/ShooterSubsystem.java b/src/main/java/frc/robot/subsystems/ShooterSubsystem.java index d3fad56..d8af538 100644 --- a/src/main/java/frc/robot/subsystems/ShooterSubsystem.java +++ b/src/main/java/frc/robot/subsystems/ShooterSubsystem.java @@ -1,9 +1,11 @@ package frc.robot.subsystems; +import com.ctre.phoenix6.hardware.TalonFX; + import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.SubsystemBase; -public class ShooterSubsystem extends SubsystemBase { +public class ShooterSubsystem extends SubsystemBase implements AutoCloseable { public Command shoot() { return this.idle(); } @@ -15,4 +17,9 @@ public Command feed() { public Command rest() { return this.idle(); } + + @Override + public void close() throws Exception { + // Currently nothing to close + } } diff --git a/src/main/java/frc/robot/subsystems/swerve/SwerveSubsystem.java b/src/main/java/frc/robot/subsystems/swerve/SwerveSubsystem.java index 933b59f..9cabc3f 100644 --- a/src/main/java/frc/robot/subsystems/swerve/SwerveSubsystem.java +++ b/src/main/java/frc/robot/subsystems/swerve/SwerveSubsystem.java @@ -59,7 +59,7 @@ import org.littletonrobotics.junction.AutoLogOutput; import org.littletonrobotics.junction.Logger; -public class SwerveSubsystem extends SubsystemBase { +public class SwerveSubsystem extends SubsystemBase implements AutoCloseable { public static final SwerveConstants SWERVE_CONSTANTS = new AlphaSwerveConstants(); private final Module[] modules; // Front Left, Front Right, Back Left, Back Right @@ -697,4 +697,15 @@ public void simulationPeriodic() { // Log simulated pose Logger.recordOutput("MapleSim/Pose", swerveSimulation.getSimulatedDriveTrainPose()); } + + @Override + public void close() throws Exception { + for (Module module : modules) { + module.close(); + } + gyroIO.close(); + for (Camera camera : cameras) { + camera.close(); + } + } } diff --git a/src/main/java/frc/robot/subsystems/swerve/gyro/GyroIO.java b/src/main/java/frc/robot/subsystems/swerve/gyro/GyroIO.java index 0a51c1e..e746e95 100644 --- a/src/main/java/frc/robot/subsystems/swerve/gyro/GyroIO.java +++ b/src/main/java/frc/robot/subsystems/swerve/gyro/GyroIO.java @@ -3,7 +3,7 @@ import edu.wpi.first.math.geometry.Rotation2d; import org.littletonrobotics.junction.AutoLog; -public interface GyroIO { +public interface GyroIO extends AutoCloseable { @AutoLog public static class GyroIOInputs { diff --git a/src/main/java/frc/robot/subsystems/swerve/gyro/GyroIOReal.java b/src/main/java/frc/robot/subsystems/swerve/gyro/GyroIOReal.java index 8c4e16d..d5032da 100644 --- a/src/main/java/frc/robot/subsystems/swerve/gyro/GyroIOReal.java +++ b/src/main/java/frc/robot/subsystems/swerve/gyro/GyroIOReal.java @@ -58,4 +58,9 @@ public void updateInputs(GyroIOInputs inputs) { public void setYaw(Rotation2d yaw) { pigeon.setYaw(yaw.getDegrees()); } + + @Override + public void close() throws Exception { + pigeon.close(); + } } diff --git a/src/main/java/frc/robot/subsystems/swerve/gyro/GyroIOSim.java b/src/main/java/frc/robot/subsystems/swerve/gyro/GyroIOSim.java index 512203d..7b17a13 100644 --- a/src/main/java/frc/robot/subsystems/swerve/gyro/GyroIOSim.java +++ b/src/main/java/frc/robot/subsystems/swerve/gyro/GyroIOSim.java @@ -23,4 +23,9 @@ public void updateInputs(GyroIOInputs inputs) { inputs.yaw = simulation.getGyroReading(); inputs.yawVelocityRadPerSec = simulation.getMeasuredAngularVelocity().in(RadiansPerSecond); } + + @Override + public void close() throws Exception { + // Nothing to close + } } diff --git a/src/main/java/frc/robot/subsystems/swerve/module/Module.java b/src/main/java/frc/robot/subsystems/swerve/module/Module.java index cb550c4..62300b1 100644 --- a/src/main/java/frc/robot/subsystems/swerve/module/Module.java +++ b/src/main/java/frc/robot/subsystems/swerve/module/Module.java @@ -10,7 +10,7 @@ import org.littletonrobotics.junction.Logger; // A single module -public class Module { +public class Module implements AutoCloseable { // Represents module specific constants public record ModuleConstants( int id, String prefix, int driveID, int turnID, int cancoderID, Rotation2d cancoderOffset) {} @@ -144,4 +144,9 @@ public SwerveModuleState getState() { public void setTurnSetpoint(Rotation2d rotation) { io.setTurnPositionSetpoint(rotation); } + + @Override + public void close() throws Exception { + io.close(); + } } diff --git a/src/main/java/frc/robot/subsystems/swerve/module/ModuleIOReal.java b/src/main/java/frc/robot/subsystems/swerve/module/ModuleIOReal.java index cc29237..aaafe15 100644 --- a/src/main/java/frc/robot/subsystems/swerve/module/ModuleIOReal.java +++ b/src/main/java/frc/robot/subsystems/swerve/module/ModuleIOReal.java @@ -22,7 +22,7 @@ import org.littletonrobotics.junction.AutoLog; import org.littletonrobotics.junction.Logger; -public class ModuleIOReal { +public class ModuleIOReal implements AutoCloseable { @AutoLog public static class ModuleIOInputs { @@ -228,4 +228,11 @@ public void setTurnPositionSetpoint(Rotation2d setpoint) { public ModuleConstants getModuleConstants() { return constants; } + + @Override + public void close() throws Exception { + driveTalon.close(); + turnTalon.close(); + cancoder.close(); + } } From 1407864abbc1333916810316410c3dc903b1510f Mon Sep 17 00:00:00 2001 From: SCool62 Date: Fri, 16 Jan 2026 09:40:25 -0800 Subject: [PATCH 03/28] Proof of concept test --- src/main/java/frc/robot/Superstructure.java | 32 +++++ .../frc/robot/components/camera/Camera.java | 4 +- .../robot/components/camera/CameraIOReal.java | 2 +- .../robot/components/camera/CameraIOSim.java | 4 +- .../frc/robot/subsystems/IntakeSubsystem.java | 2 +- .../robot/subsystems/RoutingSubsystem.java | 2 +- .../robot/subsystems/ShooterSubsystem.java | 4 +- .../subsystems/swerve/SwerveSubsystem.java | 14 +-- .../subsystems/swerve/gyro/GyroIOReal.java | 2 +- .../subsystems/swerve/gyro/GyroIOSim.java | 2 +- .../subsystems/swerve/module/Module.java | 2 +- .../swerve/module/ModuleIOReal.java | 6 +- .../java/frc/robot/SuperstructureTest.java | 119 ++++++++++++++++++ 13 files changed, 172 insertions(+), 23 deletions(-) create mode 100644 src/test/java/frc/robot/SuperstructureTest.java diff --git a/src/main/java/frc/robot/Superstructure.java b/src/main/java/frc/robot/Superstructure.java index 16b3879..6602e14 100644 --- a/src/main/java/frc/robot/Superstructure.java +++ b/src/main/java/frc/robot/Superstructure.java @@ -101,6 +101,37 @@ public Superstructure( stateTimer.start(); } + // Used for testing + public Superstructure( + SwerveSubsystem swerve, + RoutingSubsystem routing, + IntakeSubsystem intake, + ShooterSubsystem shooter, + Trigger scoreReq, + Trigger intakeReq, + Trigger feedReq, + Trigger flowReq, + Trigger antiJamReq, + Trigger isFull, + Trigger isEmpty) { + this.swerve = swerve; + this.routing = routing; + this.intake = intake; + this.shooter = shooter; + this.scoreReq = scoreReq; + this.intakeReq = intakeReq; + this.feedReq = feedReq; + this.flowReq = flowReq; + this.antiJamReq = antiJamReq; + this.isFull = isFull; + this.isEmpty = isEmpty; + this.driver = null; + this.operator = null; + + addTransitions(); + addCommands(); + } + private void addTriggers() { // TODO: THESE BINDINGS WILL LIKELY CHANGE. SHOULD HAVE A FULL MEETING TO DISCUSS scoreReq = @@ -288,5 +319,6 @@ public void close() throws Exception { shooter.close(); routing.close(); swerve.close(); + Superstructure.state = SuperState.IDLE; } } diff --git a/src/main/java/frc/robot/components/camera/Camera.java b/src/main/java/frc/robot/components/camera/Camera.java index fd06a1e..0c0481e 100644 --- a/src/main/java/frc/robot/components/camera/Camera.java +++ b/src/main/java/frc/robot/components/camera/Camera.java @@ -30,7 +30,7 @@ import org.photonvision.targeting.PhotonTrackedTarget; /** Add your docs here. */ -public class Camera implements AutoCloseable{ +public class Camera implements AutoCloseable { // The intrinsics and distortion coefficients are only actually used for sim public record CameraConstants( @@ -220,6 +220,6 @@ public Pose3d getPose() { @Override public void close() throws Exception { - io.close(); + io.close(); } } diff --git a/src/main/java/frc/robot/components/camera/CameraIOReal.java b/src/main/java/frc/robot/components/camera/CameraIOReal.java index 8c7dc17..2de23db 100644 --- a/src/main/java/frc/robot/components/camera/CameraIOReal.java +++ b/src/main/java/frc/robot/components/camera/CameraIOReal.java @@ -49,6 +49,6 @@ public CameraConstants getCameraConstants() { @Override public void close() throws Exception { - camera.close(); + camera.close(); } } diff --git a/src/main/java/frc/robot/components/camera/CameraIOSim.java b/src/main/java/frc/robot/components/camera/CameraIOSim.java index 7f7c270..6161c72 100644 --- a/src/main/java/frc/robot/components/camera/CameraIOSim.java +++ b/src/main/java/frc/robot/components/camera/CameraIOSim.java @@ -91,7 +91,7 @@ public CameraConstants getCameraConstants() { @Override public void close() throws Exception { - camera.close(); - simCamera.close(); + camera.close(); + simCamera.close(); } } diff --git a/src/main/java/frc/robot/subsystems/IntakeSubsystem.java b/src/main/java/frc/robot/subsystems/IntakeSubsystem.java index be1ac1a..d841e20 100644 --- a/src/main/java/frc/robot/subsystems/IntakeSubsystem.java +++ b/src/main/java/frc/robot/subsystems/IntakeSubsystem.java @@ -23,6 +23,6 @@ public Command spit() { @Override public void close() throws Exception { - // Currently does nothing bc nothing to close + // Currently does nothing bc nothing to close } } diff --git a/src/main/java/frc/robot/subsystems/RoutingSubsystem.java b/src/main/java/frc/robot/subsystems/RoutingSubsystem.java index 325a3e6..90f0525 100644 --- a/src/main/java/frc/robot/subsystems/RoutingSubsystem.java +++ b/src/main/java/frc/robot/subsystems/RoutingSubsystem.java @@ -36,6 +36,6 @@ public Command reverseIndex() { @Override public void close() throws Exception { - // Currently nothing to close + // Currently nothing to close } } diff --git a/src/main/java/frc/robot/subsystems/ShooterSubsystem.java b/src/main/java/frc/robot/subsystems/ShooterSubsystem.java index d8af538..aef8e24 100644 --- a/src/main/java/frc/robot/subsystems/ShooterSubsystem.java +++ b/src/main/java/frc/robot/subsystems/ShooterSubsystem.java @@ -1,7 +1,5 @@ package frc.robot.subsystems; -import com.ctre.phoenix6.hardware.TalonFX; - import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.SubsystemBase; @@ -20,6 +18,6 @@ public Command rest() { @Override public void close() throws Exception { - // Currently nothing to close + // Currently nothing to close } } diff --git a/src/main/java/frc/robot/subsystems/swerve/SwerveSubsystem.java b/src/main/java/frc/robot/subsystems/swerve/SwerveSubsystem.java index 9cabc3f..5f67366 100644 --- a/src/main/java/frc/robot/subsystems/swerve/SwerveSubsystem.java +++ b/src/main/java/frc/robot/subsystems/swerve/SwerveSubsystem.java @@ -700,12 +700,12 @@ public void simulationPeriodic() { @Override public void close() throws Exception { - for (Module module : modules) { - module.close(); - } - gyroIO.close(); - for (Camera camera : cameras) { - camera.close(); - } + for (Module module : modules) { + module.close(); + } + gyroIO.close(); + for (Camera camera : cameras) { + camera.close(); + } } } diff --git a/src/main/java/frc/robot/subsystems/swerve/gyro/GyroIOReal.java b/src/main/java/frc/robot/subsystems/swerve/gyro/GyroIOReal.java index d5032da..9a50eaf 100644 --- a/src/main/java/frc/robot/subsystems/swerve/gyro/GyroIOReal.java +++ b/src/main/java/frc/robot/subsystems/swerve/gyro/GyroIOReal.java @@ -61,6 +61,6 @@ public void setYaw(Rotation2d yaw) { @Override public void close() throws Exception { - pigeon.close(); + pigeon.close(); } } diff --git a/src/main/java/frc/robot/subsystems/swerve/gyro/GyroIOSim.java b/src/main/java/frc/robot/subsystems/swerve/gyro/GyroIOSim.java index 7b17a13..7a6f8b4 100644 --- a/src/main/java/frc/robot/subsystems/swerve/gyro/GyroIOSim.java +++ b/src/main/java/frc/robot/subsystems/swerve/gyro/GyroIOSim.java @@ -26,6 +26,6 @@ public void updateInputs(GyroIOInputs inputs) { @Override public void close() throws Exception { - // Nothing to close + // Nothing to close } } diff --git a/src/main/java/frc/robot/subsystems/swerve/module/Module.java b/src/main/java/frc/robot/subsystems/swerve/module/Module.java index 62300b1..c0637c4 100644 --- a/src/main/java/frc/robot/subsystems/swerve/module/Module.java +++ b/src/main/java/frc/robot/subsystems/swerve/module/Module.java @@ -147,6 +147,6 @@ public void setTurnSetpoint(Rotation2d rotation) { @Override public void close() throws Exception { - io.close(); + io.close(); } } diff --git a/src/main/java/frc/robot/subsystems/swerve/module/ModuleIOReal.java b/src/main/java/frc/robot/subsystems/swerve/module/ModuleIOReal.java index aaafe15..7f62fde 100644 --- a/src/main/java/frc/robot/subsystems/swerve/module/ModuleIOReal.java +++ b/src/main/java/frc/robot/subsystems/swerve/module/ModuleIOReal.java @@ -231,8 +231,8 @@ public ModuleConstants getModuleConstants() { @Override public void close() throws Exception { - driveTalon.close(); - turnTalon.close(); - cancoder.close(); + driveTalon.close(); + turnTalon.close(); + cancoder.close(); } } diff --git a/src/test/java/frc/robot/SuperstructureTest.java b/src/test/java/frc/robot/SuperstructureTest.java new file mode 100644 index 0000000..8362d47 --- /dev/null +++ b/src/test/java/frc/robot/SuperstructureTest.java @@ -0,0 +1,119 @@ +package frc.robot; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import com.ctre.phoenix6.CANBus; +import edu.wpi.first.hal.HAL; +import edu.wpi.first.wpilibj.simulation.DriverStationSim; +import edu.wpi.first.wpilibj2.command.CommandScheduler; +import edu.wpi.first.wpilibj2.command.button.Trigger; +import frc.robot.Superstructure.SuperState; +import frc.robot.subsystems.IntakeSubsystem; +import frc.robot.subsystems.RoutingSubsystem; +import frc.robot.subsystems.ShooterSubsystem; +import frc.robot.subsystems.swerve.SwerveSubsystem; +import java.lang.reflect.Field; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class SuperstructureTest { + Superstructure superstructure; + IntakeSubsystem intake; + ShooterSubsystem shooter; + RoutingSubsystem routing; + SwerveSubsystem swerve; + + boolean scoreReq; + boolean intakeReq; + boolean feedReq; + boolean flowReq; + boolean antiJamReq; + boolean isFull; + boolean isEmpty; + + @BeforeEach // Runs before each test + void setup() { + // TODO: SETUP + // Reset command scheduler + Field instance; + try { + instance = CommandScheduler.class.getDeclaredField("instance"); + instance.setAccessible(true); + instance.set(null, null); + } catch (Exception e) { + e.printStackTrace(); + } + + assert HAL.initialize(500, 0); // Initialize HAL, crash if failed + + DriverStationSim.setEnabled(true); + DriverStationSim.notifyNewData(); + + scoreReq = false; + intakeReq = false; + feedReq = false; + flowReq = false; + antiJamReq = false; + isFull = false; + isEmpty = false; + + intake = new IntakeSubsystem(); + shooter = new ShooterSubsystem(); + routing = new RoutingSubsystem(); + swerve = new SwerveSubsystem(new CANBus()); + + superstructure = + new Superstructure( + swerve, + routing, + intake, + shooter, + new Trigger(() -> scoreReq), + new Trigger(() -> intakeReq), + new Trigger(() -> feedReq), + new Trigger(() -> flowReq), + new Trigger(() -> antiJamReq), + new Trigger(() -> isFull), + new Trigger(() -> isEmpty)); + } + + @AfterEach // Runs after each test + void tearDown() { + // TODO: TEARDOWN + try { + superstructure.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + void idleToIntake() { + assertEquals( + Superstructure.getState(), SuperState.IDLE); // Verify that superstructure starts in IDLE + + // Some time passes... + for (int i = 0; i < 50; i++) { + CommandScheduler.getInstance().run(); + } + + assertEquals( + Superstructure.getState(), + SuperState.IDLE); // Verify that the superstructure hasn't transitioned yet + + intakeReq = true; // This should trigger the state transition from IDLE to INTAKE + + // Some time passes... + for (int i = 0; i < 50; i++) { + CommandScheduler.getInstance().run(); + } + + assertEquals( + Superstructure.getState(), + SuperState.INTAKE); // Verify that the superstructure has properly transitioned + + // TODO: THIS DOESN'T WORK BC THE AREN'T THE SAME COMMAND IN MEMORY. FIGURE OUT HOW TO FIX + // assertEquals(intake.getCurrentCommand(), intake.intake()); // Verify that the intake is intaking + } +} From 78ef8c59fce4b1fecb03d0041712c2a6f779945a Mon Sep 17 00:00:00 2001 From: SCool62 Date: Fri, 16 Jan 2026 09:41:30 -0800 Subject: [PATCH 04/28] Spotless --- src/test/java/frc/robot/SuperstructureTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/frc/robot/SuperstructureTest.java b/src/test/java/frc/robot/SuperstructureTest.java index 8362d47..45ac834 100644 --- a/src/test/java/frc/robot/SuperstructureTest.java +++ b/src/test/java/frc/robot/SuperstructureTest.java @@ -114,6 +114,7 @@ void idleToIntake() { SuperState.INTAKE); // Verify that the superstructure has properly transitioned // TODO: THIS DOESN'T WORK BC THE AREN'T THE SAME COMMAND IN MEMORY. FIGURE OUT HOW TO FIX - // assertEquals(intake.getCurrentCommand(), intake.intake()); // Verify that the intake is intaking + // assertEquals(intake.getCurrentCommand(), intake.intake()); // Verify that the intake is + // intaking } } From 609edf80e53dae25903f43ceac310774b191fec0 Mon Sep 17 00:00:00 2001 From: SCool62 Date: Fri, 16 Jan 2026 15:38:07 -0800 Subject: [PATCH 05/28] Hopefully make ci run on all prs? --- .github/workflows/checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 4c13e52..3d5cd48 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -4,7 +4,7 @@ name: checks on: push: branches: ["main"] - pull_request: + pull_request jobs: # Checks that the build succeded From e87be9600209cebd72464f207c78335ec275f541 Mon Sep 17 00:00:00 2001 From: SCool62 Date: Fri, 16 Jan 2026 15:40:25 -0800 Subject: [PATCH 06/28] Revert "Hopefully make ci run on all prs?" This reverts commit 609edf80e53dae25903f43ceac310774b191fec0. --- .github/workflows/checks.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 3d5cd48..4c13e52 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -4,7 +4,7 @@ name: checks on: push: branches: ["main"] - pull_request + pull_request: jobs: # Checks that the build succeded From 5ee9c0b7a091510f743f6769b3624da497daedb0 Mon Sep 17 00:00:00 2001 From: SCool62 Date: Fri, 16 Jan 2026 19:11:53 -0800 Subject: [PATCH 07/28] Fix constructor --- src/main/java/frc/robot/Superstructure.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/frc/robot/Superstructure.java b/src/main/java/frc/robot/Superstructure.java index aac09b3..65edb14 100644 --- a/src/main/java/frc/robot/Superstructure.java +++ b/src/main/java/frc/robot/Superstructure.java @@ -105,9 +105,9 @@ public Superstructure( // Used for testing public Superstructure( SwerveSubsystem swerve, - RoutingSubsystem routing, + IndexerSubsystem indexer, IntakeSubsystem intake, - ShooterSubsystem shooter, + HoodSubsystem shooter, Trigger scoreReq, Trigger intakeReq, Trigger feedReq, @@ -116,8 +116,8 @@ public Superstructure( Trigger isFull, Trigger isEmpty) { this.swerve = swerve; - this.routing = routing; this.intake = intake; + this.indexer = indexer; this.shooter = shooter; this.scoreReq = scoreReq; this.intakeReq = intakeReq; From 9939f666e34f2a14ac4a9f9213202e741603f3b8 Mon Sep 17 00:00:00 2001 From: SCool62 Date: Fri, 16 Jan 2026 19:14:19 -0800 Subject: [PATCH 08/28] Re implement auto-closeable --- src/main/java/frc/robot/Superstructure.java | 2 +- .../java/frc/robot/components/rollers/RollerIOReal.java | 7 ++++++- src/main/java/frc/robot/subsystems/hood/HoodIO.java | 7 ++++++- src/main/java/frc/robot/subsystems/hood/HoodSubsystem.java | 7 ++++++- .../frc/robot/subsystems/indexer/IndexerSubsystem.java | 7 ++++++- .../java/frc/robot/subsystems/intake/IntakeSubsystem.java | 7 ++++++- 6 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/main/java/frc/robot/Superstructure.java b/src/main/java/frc/robot/Superstructure.java index 65edb14..d225100 100644 --- a/src/main/java/frc/robot/Superstructure.java +++ b/src/main/java/frc/robot/Superstructure.java @@ -330,7 +330,7 @@ public boolean stateIsIdle() { public void close() throws Exception { intake.close(); shooter.close(); - routing.close(); + indexer.close(); swerve.close(); Superstructure.state = SuperState.IDLE; } diff --git a/src/main/java/frc/robot/components/rollers/RollerIOReal.java b/src/main/java/frc/robot/components/rollers/RollerIOReal.java index dafcf64..7ac727f 100644 --- a/src/main/java/frc/robot/components/rollers/RollerIOReal.java +++ b/src/main/java/frc/robot/components/rollers/RollerIOReal.java @@ -13,7 +13,7 @@ import edu.wpi.first.wpilibj2.command.Command; import org.littletonrobotics.junction.AutoLog; -public class RollerIOReal { +public class RollerIOReal implements AutoCloseable { @AutoLog public static class RollerIOInputs { @@ -84,4 +84,9 @@ public Command getVoltage() { // TODO Auto-generated method stub throw new UnsupportedOperationException("Unimplemented method 'getVoltage'"); } + + @Override + public void close() throws Exception { + rollerMotor.close(); + } } diff --git a/src/main/java/frc/robot/subsystems/hood/HoodIO.java b/src/main/java/frc/robot/subsystems/hood/HoodIO.java index c350cf7..c83d94f 100644 --- a/src/main/java/frc/robot/subsystems/hood/HoodIO.java +++ b/src/main/java/frc/robot/subsystems/hood/HoodIO.java @@ -21,7 +21,7 @@ import edu.wpi.first.units.measure.Voltage; import org.littletonrobotics.junction.AutoLog; -public class HoodIO { +public class HoodIO implements AutoCloseable { /** Creates a new HoodIOReal. */ @AutoLog public static class HoodIOInputs { @@ -123,4 +123,9 @@ public void updateInputs(HoodIOInputsAutoLogged inputs) { inputs.hoodSupplyCurrentAmp = hoodSupplyCurrent.getValueAsDouble(); inputs.hoodTempC = hoodTemp.getValueAsDouble(); } + + @Override + public void close() throws Exception { + hoodMotor.close(); + } } diff --git a/src/main/java/frc/robot/subsystems/hood/HoodSubsystem.java b/src/main/java/frc/robot/subsystems/hood/HoodSubsystem.java index 57cddb2..71f9179 100644 --- a/src/main/java/frc/robot/subsystems/hood/HoodSubsystem.java +++ b/src/main/java/frc/robot/subsystems/hood/HoodSubsystem.java @@ -13,7 +13,7 @@ import java.util.function.Supplier; import org.littletonrobotics.junction.Logger; -public class HoodSubsystem extends SubsystemBase { +public class HoodSubsystem extends SubsystemBase implements AutoCloseable { private HoodIO hoodIO; private HoodIOInputsAutoLogged hoodInputs = new HoodIOInputsAutoLogged(); @@ -70,4 +70,9 @@ public Command spit() { return this.run( () -> hoodIO.setHoodPosition(Rotation2d.kZero)); // TODO: FLYWHEEL AND TUNE HOOD POS } + + @Override + public void close() throws Exception { + hoodIO.close(); + } } diff --git a/src/main/java/frc/robot/subsystems/indexer/IndexerSubsystem.java b/src/main/java/frc/robot/subsystems/indexer/IndexerSubsystem.java index ccd6730..a3f666e 100644 --- a/src/main/java/frc/robot/subsystems/indexer/IndexerSubsystem.java +++ b/src/main/java/frc/robot/subsystems/indexer/IndexerSubsystem.java @@ -12,7 +12,7 @@ import frc.robot.components.rollers.RollerIOReal; import org.littletonrobotics.junction.Logger; -public class IndexerSubsystem extends SubsystemBase { +public class IndexerSubsystem extends SubsystemBase implements AutoCloseable { public static double GEAR_RATIO = 2.0; // Add actual CanBus @@ -112,4 +112,9 @@ public void periodic() { rollerIO.updateInputs(rollerInputs); Logger.processInputs("Indexer/Roller", rollerInputs); } + + @Override + public void close() throws Exception { + rollerIO.close(); + } } diff --git a/src/main/java/frc/robot/subsystems/intake/IntakeSubsystem.java b/src/main/java/frc/robot/subsystems/intake/IntakeSubsystem.java index 530291b..f4b50c5 100644 --- a/src/main/java/frc/robot/subsystems/intake/IntakeSubsystem.java +++ b/src/main/java/frc/robot/subsystems/intake/IntakeSubsystem.java @@ -9,7 +9,7 @@ import frc.robot.components.rollers.RollerIOReal; import org.littletonrobotics.junction.Logger; -public class IntakeSubsystem extends SubsystemBase { +public class IntakeSubsystem extends SubsystemBase implements AutoCloseable { public static double GEAR_RATIO = 2.0; private RollerIOReal io; @@ -65,4 +65,9 @@ public static TalonFXConfiguration getIntakeIOConfig() { return config; } + + @Override + public void close() throws Exception { + io.close(); + } } From 7b89e58f5fe2ffa797ec7c83f1abfd57b726790d Mon Sep 17 00:00:00 2001 From: SCool62 Date: Fri, 16 Jan 2026 19:17:12 -0800 Subject: [PATCH 09/28] Make test build --- .../components/rollers/RollerIOReal.java | 2 +- .../frc/robot/subsystems/hood/HoodIO.java | 2 +- .../robot/subsystems/hood/HoodSubsystem.java | 2 +- .../subsystems/indexer/IndexerSubsystem.java | 2 +- .../subsystems/intake/IntakeSubsystem.java | 2 +- .../java/frc/robot/SuperstructureTest.java | 20 +++++++++++-------- 6 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/main/java/frc/robot/components/rollers/RollerIOReal.java b/src/main/java/frc/robot/components/rollers/RollerIOReal.java index 7ac727f..18975c7 100644 --- a/src/main/java/frc/robot/components/rollers/RollerIOReal.java +++ b/src/main/java/frc/robot/components/rollers/RollerIOReal.java @@ -87,6 +87,6 @@ public Command getVoltage() { @Override public void close() throws Exception { - rollerMotor.close(); + rollerMotor.close(); } } diff --git a/src/main/java/frc/robot/subsystems/hood/HoodIO.java b/src/main/java/frc/robot/subsystems/hood/HoodIO.java index c83d94f..2ebf006 100644 --- a/src/main/java/frc/robot/subsystems/hood/HoodIO.java +++ b/src/main/java/frc/robot/subsystems/hood/HoodIO.java @@ -126,6 +126,6 @@ public void updateInputs(HoodIOInputsAutoLogged inputs) { @Override public void close() throws Exception { - hoodMotor.close(); + hoodMotor.close(); } } diff --git a/src/main/java/frc/robot/subsystems/hood/HoodSubsystem.java b/src/main/java/frc/robot/subsystems/hood/HoodSubsystem.java index 71f9179..67dfc1e 100644 --- a/src/main/java/frc/robot/subsystems/hood/HoodSubsystem.java +++ b/src/main/java/frc/robot/subsystems/hood/HoodSubsystem.java @@ -73,6 +73,6 @@ public Command spit() { @Override public void close() throws Exception { - hoodIO.close(); + hoodIO.close(); } } diff --git a/src/main/java/frc/robot/subsystems/indexer/IndexerSubsystem.java b/src/main/java/frc/robot/subsystems/indexer/IndexerSubsystem.java index a3f666e..9c82540 100644 --- a/src/main/java/frc/robot/subsystems/indexer/IndexerSubsystem.java +++ b/src/main/java/frc/robot/subsystems/indexer/IndexerSubsystem.java @@ -115,6 +115,6 @@ public void periodic() { @Override public void close() throws Exception { - rollerIO.close(); + rollerIO.close(); } } diff --git a/src/main/java/frc/robot/subsystems/intake/IntakeSubsystem.java b/src/main/java/frc/robot/subsystems/intake/IntakeSubsystem.java index f4b50c5..d3d1e1b 100644 --- a/src/main/java/frc/robot/subsystems/intake/IntakeSubsystem.java +++ b/src/main/java/frc/robot/subsystems/intake/IntakeSubsystem.java @@ -68,6 +68,6 @@ public static TalonFXConfiguration getIntakeIOConfig() { @Override public void close() throws Exception { - io.close(); + io.close(); } } diff --git a/src/test/java/frc/robot/SuperstructureTest.java b/src/test/java/frc/robot/SuperstructureTest.java index 45ac834..4e893eb 100644 --- a/src/test/java/frc/robot/SuperstructureTest.java +++ b/src/test/java/frc/robot/SuperstructureTest.java @@ -8,9 +8,11 @@ import edu.wpi.first.wpilibj2.command.CommandScheduler; import edu.wpi.first.wpilibj2.command.button.Trigger; import frc.robot.Superstructure.SuperState; -import frc.robot.subsystems.IntakeSubsystem; -import frc.robot.subsystems.RoutingSubsystem; -import frc.robot.subsystems.ShooterSubsystem; +import frc.robot.components.rollers.RollerIOReal; +import frc.robot.subsystems.hood.HoodIOSim; +import frc.robot.subsystems.hood.HoodSubsystem; +import frc.robot.subsystems.indexer.IndexerSubsystem; +import frc.robot.subsystems.intake.IntakeSubsystem; import frc.robot.subsystems.swerve.SwerveSubsystem; import java.lang.reflect.Field; import org.junit.jupiter.api.AfterEach; @@ -20,8 +22,8 @@ public class SuperstructureTest { Superstructure superstructure; IntakeSubsystem intake; - ShooterSubsystem shooter; - RoutingSubsystem routing; + HoodSubsystem shooter; + IndexerSubsystem routing; SwerveSubsystem swerve; boolean scoreReq; @@ -58,9 +60,11 @@ void setup() { isFull = false; isEmpty = false; - intake = new IntakeSubsystem(); - shooter = new ShooterSubsystem(); - routing = new RoutingSubsystem(); + intake = new IntakeSubsystem(new RollerIOReal(10, IntakeSubsystem.getIntakeIOConfig())); + shooter = new HoodSubsystem(new HoodIOSim(new CANBus())); + routing = + new IndexerSubsystem( + new CANBus(), new RollerIOReal(11, IndexerSubsystem.getIndexerConfigs())); swerve = new SwerveSubsystem(new CANBus()); superstructure = From 87cf920437325d82f88f6f667571c7531e75b3a4 Mon Sep 17 00:00:00 2001 From: SCool62 Date: Fri, 16 Jan 2026 19:19:31 -0800 Subject: [PATCH 10/28] Add test running to ci checks --- .github/workflows/checks.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index b855262..b155319 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -62,3 +62,31 @@ jobs: # Runs a single command using the runners shell - name: Run formatting check run: ./gradlew spotlessCheck + + test: + name: Test + + runs-on: ubuntu-latest + + # Wpilib docker container + # Latest as of 1/11/26 + # Need to use a container without -py. The ones with -py don't have java installed + container: wpilib/roborio-cross-ubuntu:2025-22.04 + + # Steps represent a sequence of tasks that will be executed as part of the job + # Copied from Onseason implementation + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v3 + + # Declares the repository safe and not under dubious ownership. + - name: Add repository to git safe directories + run: git config --global --add safe.directory $GITHUB_WORKSPACE + + # Grant execute permission for gradlew + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + # Runs a single command using the runners shell + - name: Run test + run: ./gradlew test \ No newline at end of file From cdcc3db9e73524b6cadbc3cfd5664b84ea67746f Mon Sep 17 00:00:00 2001 From: SCool62 Date: Fri, 16 Jan 2026 19:22:06 -0800 Subject: [PATCH 11/28] Failing test to test ci --- src/test/java/frc/robot/SuperstructureTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/test/java/frc/robot/SuperstructureTest.java b/src/test/java/frc/robot/SuperstructureTest.java index 4e893eb..f00a982 100644 --- a/src/test/java/frc/robot/SuperstructureTest.java +++ b/src/test/java/frc/robot/SuperstructureTest.java @@ -121,4 +121,9 @@ void idleToIntake() { // assertEquals(intake.getCurrentCommand(), intake.intake()); // Verify that the intake is // intaking } + + @Test + void shouldFail() { + assertEquals(1, 2); + } } From 4bed2b8975796870d2305eb90ba05f0e941d1015 Mon Sep 17 00:00:00 2001 From: SCool62 Date: Fri, 16 Jan 2026 19:26:43 -0800 Subject: [PATCH 12/28] Turns out we don't need a seperate CI check, and the failing test does fail --- .github/workflows/checks.yml | 28 ------------------- .../java/frc/robot/SuperstructureTest.java | 5 ---- 2 files changed, 33 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index b155319..b855262 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -62,31 +62,3 @@ jobs: # Runs a single command using the runners shell - name: Run formatting check run: ./gradlew spotlessCheck - - test: - name: Test - - runs-on: ubuntu-latest - - # Wpilib docker container - # Latest as of 1/11/26 - # Need to use a container without -py. The ones with -py don't have java installed - container: wpilib/roborio-cross-ubuntu:2025-22.04 - - # Steps represent a sequence of tasks that will be executed as part of the job - # Copied from Onseason implementation - steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v3 - - # Declares the repository safe and not under dubious ownership. - - name: Add repository to git safe directories - run: git config --global --add safe.directory $GITHUB_WORKSPACE - - # Grant execute permission for gradlew - - name: Grant execute permission for gradlew - run: chmod +x gradlew - - # Runs a single command using the runners shell - - name: Run test - run: ./gradlew test \ No newline at end of file diff --git a/src/test/java/frc/robot/SuperstructureTest.java b/src/test/java/frc/robot/SuperstructureTest.java index f00a982..4e893eb 100644 --- a/src/test/java/frc/robot/SuperstructureTest.java +++ b/src/test/java/frc/robot/SuperstructureTest.java @@ -121,9 +121,4 @@ void idleToIntake() { // assertEquals(intake.getCurrentCommand(), intake.intake()); // Verify that the intake is // intaking } - - @Test - void shouldFail() { - assertEquals(1, 2); - } } From c31134a64c0fb21e98d1f0007d8f00e910647f5a Mon Sep 17 00:00:00 2001 From: SCool62 Date: Sat, 17 Jan 2026 11:49:06 -0800 Subject: [PATCH 13/28] Intake to READY test --- .../java/frc/robot/SuperstructureTest.java | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/src/test/java/frc/robot/SuperstructureTest.java b/src/test/java/frc/robot/SuperstructureTest.java index 4e893eb..c19f886 100644 --- a/src/test/java/frc/robot/SuperstructureTest.java +++ b/src/test/java/frc/robot/SuperstructureTest.java @@ -58,7 +58,7 @@ void setup() { flowReq = false; antiJamReq = false; isFull = false; - isEmpty = false; + isEmpty = true; intake = new IntakeSubsystem(new RollerIOReal(10, IntakeSubsystem.getIntakeIOConfig())); shooter = new HoodSubsystem(new HoodIOSim(new CANBus())); @@ -121,4 +121,32 @@ void idleToIntake() { // assertEquals(intake.getCurrentCommand(), intake.intake()); // Verify that the intake is // intaking } + + @Test + void intakeToReadyNotFull() { + idleToIntake(); // First, we need to get into intake + + isEmpty = false; // We're no longer empty + + // Some time passes... + for (int i = 0; i < 50; i++) { + CommandScheduler.getInstance().run(); + } + + assertEquals( + SuperState.INTAKE, + Superstructure.getState()); // Should still be intaking bc the request is not off + + intakeReq = false; + + // Some time passes... + for (int i = 0; i < 50; i++) { + CommandScheduler.getInstance().run(); + } + + assertEquals( + SuperState.READY, + Superstructure + .getState()); // Should be in READY because we're not empty and intakeReq is false + } } From 6e428c86698c7cb2fc22370ea46e2b20bcd2f4f5 Mon Sep 17 00:00:00 2001 From: SCool62 Date: Sat, 17 Jan 2026 11:49:53 -0800 Subject: [PATCH 14/28] These assert statements should go the other way around lol --- src/test/java/frc/robot/SuperstructureTest.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/test/java/frc/robot/SuperstructureTest.java b/src/test/java/frc/robot/SuperstructureTest.java index c19f886..f3022c8 100644 --- a/src/test/java/frc/robot/SuperstructureTest.java +++ b/src/test/java/frc/robot/SuperstructureTest.java @@ -94,17 +94,16 @@ void tearDown() { @Test void idleToIntake() { - assertEquals( - Superstructure.getState(), SuperState.IDLE); // Verify that superstructure starts in IDLE + assertEquals( SuperState.IDLE, + Superstructure.getState()); // Verify that superstructure starts in IDLE // Some time passes... for (int i = 0; i < 50; i++) { CommandScheduler.getInstance().run(); } - assertEquals( - Superstructure.getState(), - SuperState.IDLE); // Verify that the superstructure hasn't transitioned yet + assertEquals(SuperState.IDLE, + Superstructure.getState()); // Verify that the superstructure hasn't transitioned yet intakeReq = true; // This should trigger the state transition from IDLE to INTAKE @@ -113,9 +112,8 @@ void idleToIntake() { CommandScheduler.getInstance().run(); } - assertEquals( - Superstructure.getState(), - SuperState.INTAKE); // Verify that the superstructure has properly transitioned + assertEquals(SuperState.INTAKE, + Superstructure.getState()); // Verify that the superstructure has properly transitioned // TODO: THIS DOESN'T WORK BC THE AREN'T THE SAME COMMAND IN MEMORY. FIGURE OUT HOW TO FIX // assertEquals(intake.getCurrentCommand(), intake.intake()); // Verify that the intake is From dada1e707af97e3d30187d171d9d32ad48f5d882 Mon Sep 17 00:00:00 2001 From: SCool62 Date: Sat, 17 Jan 2026 11:50:07 -0800 Subject: [PATCH 15/28] Spotless --- src/test/java/frc/robot/SuperstructureTest.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/test/java/frc/robot/SuperstructureTest.java b/src/test/java/frc/robot/SuperstructureTest.java index f3022c8..247b8d9 100644 --- a/src/test/java/frc/robot/SuperstructureTest.java +++ b/src/test/java/frc/robot/SuperstructureTest.java @@ -94,15 +94,16 @@ void tearDown() { @Test void idleToIntake() { - assertEquals( SuperState.IDLE, - Superstructure.getState()); // Verify that superstructure starts in IDLE + assertEquals( + SuperState.IDLE, Superstructure.getState()); // Verify that superstructure starts in IDLE // Some time passes... for (int i = 0; i < 50; i++) { CommandScheduler.getInstance().run(); } - assertEquals(SuperState.IDLE, + assertEquals( + SuperState.IDLE, Superstructure.getState()); // Verify that the superstructure hasn't transitioned yet intakeReq = true; // This should trigger the state transition from IDLE to INTAKE @@ -112,7 +113,8 @@ void idleToIntake() { CommandScheduler.getInstance().run(); } - assertEquals(SuperState.INTAKE, + assertEquals( + SuperState.INTAKE, Superstructure.getState()); // Verify that the superstructure has properly transitioned // TODO: THIS DOESN'T WORK BC THE AREN'T THE SAME COMMAND IN MEMORY. FIGURE OUT HOW TO FIX From 66596f1e0fcdc9d856210f3618847af578ec688b Mon Sep 17 00:00:00 2001 From: SCool62 Date: Sat, 17 Jan 2026 11:53:15 -0800 Subject: [PATCH 16/28] Intake to READY when full test --- .../java/frc/robot/SuperstructureTest.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/test/java/frc/robot/SuperstructureTest.java b/src/test/java/frc/robot/SuperstructureTest.java index 247b8d9..e74463c 100644 --- a/src/test/java/frc/robot/SuperstructureTest.java +++ b/src/test/java/frc/robot/SuperstructureTest.java @@ -149,4 +149,32 @@ void intakeToReadyNotFull() { Superstructure .getState()); // Should be in READY because we're not empty and intakeReq is false } + + @Test + void intakeToReadyFull() { + idleToIntake(); // Enter Intake + + isEmpty = false; // We have at least 1 ball + + // Some time passes... + for (int i = 0; i < 50; i++) { + CommandScheduler.getInstance().run(); + } + + assertEquals( + SuperState.INTAKE, + Superstructure + .getState()); // Should still be intaking because we're not full and the request is not + // off + + isFull = true; // Full + + // Some time passes... + for (int i = 0; i < 50; i++) { + CommandScheduler.getInstance().run(); + } + + assertEquals(SuperState.READY, Superstructure.getState()); // Should be ready because we're full + assertEquals(true, intakeReq); // Even though we're still requesting to intake + } } From c8ffb98c29f44771f018bfb656082a276ae28e89 Mon Sep 17 00:00:00 2001 From: SCool62 Date: Sat, 17 Jan 2026 12:42:14 -0800 Subject: [PATCH 17/28] Ready to score and ready to feed tests --- src/main/java/frc/robot/Superstructure.java | 27 +++++++++-- .../java/frc/robot/SuperstructureTest.java | 46 +++++++++++++++++++ 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/src/main/java/frc/robot/Superstructure.java b/src/main/java/frc/robot/Superstructure.java index 75e5421..fd69009 100644 --- a/src/main/java/frc/robot/Superstructure.java +++ b/src/main/java/frc/robot/Superstructure.java @@ -149,7 +149,12 @@ private void addTriggers() { intakeReq = driver.leftTrigger().and(DriverStation::isTeleop).or(Autos.autoIntakeReq); - feedReq = driver.rightBumper().and(DriverStation::isTeleop).and(() -> shouldFeed == true).or(Autos.autoFeedReq); + feedReq = + driver + .rightBumper() + .and(DriverStation::isTeleop) + .and(() -> shouldFeed == true) + .or(Autos.autoFeedReq); flowReq = operator.rightTrigger(); @@ -190,10 +195,16 @@ private void addTransitions() { bindTransition(SuperState.FEED_FLOW, SuperState.FEED, flowReq.negate().and(feedReq)); - bindTransition(SuperState.FEED_FLOW, SuperState.READY, flowReq.negate().and(feedReq.negate()).and(isEmpty.negate())); + bindTransition( + SuperState.FEED_FLOW, + SuperState.READY, + flowReq.negate().and(feedReq.negate()).and(isEmpty.negate())); // No so sure about the end condition here. - bindTransition(SuperState.FEED_FLOW, SuperState.IDLE, flowReq.negate().and(isEmpty).and(feedReq.negate())); + bindTransition( + SuperState.FEED_FLOW, + SuperState.IDLE, + flowReq.negate().and(isEmpty).and(feedReq.negate())); } // SCORE_FLOW transitions @@ -204,10 +215,16 @@ private void addTransitions() { bindTransition(SuperState.SCORE_FLOW, SuperState.SCORE, flowReq.negate().and(scoreReq)); - bindTransition(SuperState.SCORE_FLOW, SuperState.READY, flowReq.negate().and(scoreReq.negate()).and(isEmpty.negate())); + bindTransition( + SuperState.SCORE_FLOW, + SuperState.READY, + flowReq.negate().and(scoreReq.negate()).and(isEmpty.negate())); // No so sure about the end condition here. - bindTransition(SuperState.SCORE_FLOW, SuperState.IDLE, flowReq.negate().and(isEmpty).and(scoreReq.negate())); + bindTransition( + SuperState.SCORE_FLOW, + SuperState.IDLE, + flowReq.negate().and(isEmpty).and(scoreReq.negate())); } // Transition from any state to SPIT for anti jamming diff --git a/src/test/java/frc/robot/SuperstructureTest.java b/src/test/java/frc/robot/SuperstructureTest.java index e74463c..8f35651 100644 --- a/src/test/java/frc/robot/SuperstructureTest.java +++ b/src/test/java/frc/robot/SuperstructureTest.java @@ -177,4 +177,50 @@ void intakeToReadyFull() { assertEquals(SuperState.READY, Superstructure.getState()); // Should be ready because we're full assertEquals(true, intakeReq); // Even though we're still requesting to intake } + + @Test + void readyToScore() { + intakeToReadyNotFull(); // Get into ready + + scoreReq = true; // I.e. press button to start scoring + + // Some time passes... + for (int i = 0; i < 50; i++) { + CommandScheduler.getInstance().run(); + } + + assertEquals(SuperState.SCORE, Superstructure.getState()); + + isEmpty = true; // We've shot our whole hopper + + // Some time passes... + for (int i = 0; i < 50; i++) { + CommandScheduler.getInstance().run(); + } + + assertEquals(SuperState.IDLE, Superstructure.getState()); + } + + @Test + void readyToFeed() { + intakeToReadyNotFull(); // Get into ready + + feedReq = true; // I.e. press button to start scoring + + // Some time passes... + for (int i = 0; i < 50; i++) { + CommandScheduler.getInstance().run(); + } + + assertEquals(SuperState.FEED, Superstructure.getState()); + + isEmpty = true; // We've shot our whole hopper + + // Some time passes... + for (int i = 0; i < 50; i++) { + CommandScheduler.getInstance().run(); + } + + assertEquals(SuperState.IDLE, Superstructure.getState()); + } } From b89f1fd93115071dc796c9755f7e24441a3309e8 Mon Sep 17 00:00:00 2001 From: SCool62 Date: Sat, 17 Jan 2026 12:52:23 -0800 Subject: [PATCH 18/28] Add score transition tests --- .../java/frc/robot/SuperstructureTest.java | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/test/java/frc/robot/SuperstructureTest.java b/src/test/java/frc/robot/SuperstructureTest.java index 8f35651..bca2675 100644 --- a/src/test/java/frc/robot/SuperstructureTest.java +++ b/src/test/java/frc/robot/SuperstructureTest.java @@ -190,6 +190,25 @@ void readyToScore() { } assertEquals(SuperState.SCORE, Superstructure.getState()); + } + + @Test + void scoreToIdle() { + readyToScore(); // Start scoring + + assertEquals(SuperState.SCORE, Superstructure.getState()); // Ensure we're still scoring + assertEquals(true, scoreReq); + + scoreReq = false; + + // Some time passes... + for (int i = 0; i < 50; i++) { + CommandScheduler.getInstance().run(); + } + + assertEquals( + SuperState.SCORE, + Superstructure.getState()); // Should still score because we only transition when empty isEmpty = true; // We've shot our whole hopper @@ -213,6 +232,25 @@ void readyToFeed() { } assertEquals(SuperState.FEED, Superstructure.getState()); + } + + @Test + void feedToIdle() { + readyToFeed(); // Start feeding + + assertEquals(SuperState.FEED, Superstructure.getState()); // Ensure we're still scoring + assertEquals(true, feedReq); + + feedReq = false; + + // Some time passes... + for (int i = 0; i < 50; i++) { + CommandScheduler.getInstance().run(); + } + + assertEquals( + SuperState.FEED, + Superstructure.getState()); // Should still score because we only transition when empty isEmpty = true; // We've shot our whole hopper @@ -223,4 +261,38 @@ void readyToFeed() { assertEquals(SuperState.IDLE, Superstructure.getState()); } + + @Test + void feedToFeedFlow() { + readyToFeed(); // Get into feed + + assertEquals(SuperState.FEED, Superstructure.getState()); // Ensure we're still feeding + assertEquals(true, feedReq); // Make sure we're still requesting to feed + + flowReq = true; // Request to flow + + // Some time passes... + for (int i = 0; i < 50; i++) { + CommandScheduler.getInstance().run(); + } + + assertEquals(SuperState.FEED_FLOW, Superstructure.getState()); // Should be in FEED_FLOW now + } + + @Test + void scoreToScoreFlow() { + readyToScore(); // Get into score + + assertEquals(SuperState.SCORE, Superstructure.getState()); // Ensure we're still feeding + assertEquals(true, scoreReq); // Make sure we're still requesting to feed + + flowReq = true; // Request to flow + + // Some time passes... + for (int i = 0; i < 50; i++) { + CommandScheduler.getInstance().run(); + } + + assertEquals(SuperState.SCORE_FLOW, Superstructure.getState()); // Should be in FEED_FLOW now + } } From 17cf7f15ac88d10f43b00601cbc51bb2132cc598 Mon Sep 17 00:00:00 2001 From: SCool62 Date: Sat, 17 Jan 2026 12:57:09 -0800 Subject: [PATCH 19/28] I've decided it would be better to have seperate build and test ci checks --- .github/workflows/checks.yml | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index b855262..6a5beef 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -32,8 +32,9 @@ jobs: run: chmod +x gradlew # Runs a single command using the runners shell - - name: Compile and run tests on robot code - run: ./gradlew build + # Assemble builds the code without running tests + - name: Compile robot code + run: ./gradlew assemble format: name: Format @@ -62,3 +63,31 @@ jobs: # Runs a single command using the runners shell - name: Run formatting check run: ./gradlew spotlessCheck + + test: + name: Test + + runs-on: ubuntu-latest + + # Wpilib docker container + # Latest as of 1/11/26 + # Need to use a container without -py. The ones with -py don't have java installed + container: wpilib/roborio-cross-ubuntu:2025-22.04 + + # Steps represent a sequence of tasks that will be executed as part of the job + # Copied from Onseason implementation + steps: + # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it + - uses: actions/checkout@v3 + + # Declares the repository safe and not under dubious ownership. + - name: Add repository to git safe directories + run: git config --global --add safe.directory $GITHUB_WORKSPACE + + # Grant execute permission for gradlew + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + # Runs a single command using the runners shell + - name: Run formatting check + run: ./gradlew test From 8578bb3df1aaec49b0ecf5f4e3f25da319892f07 Mon Sep 17 00:00:00 2001 From: SCool62 Date: Sat, 17 Jan 2026 12:59:43 -0800 Subject: [PATCH 20/28] Failing test to test ci --- src/test/java/frc/robot/SuperstructureTest.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/test/java/frc/robot/SuperstructureTest.java b/src/test/java/frc/robot/SuperstructureTest.java index bca2675..32eff03 100644 --- a/src/test/java/frc/robot/SuperstructureTest.java +++ b/src/test/java/frc/robot/SuperstructureTest.java @@ -295,4 +295,9 @@ void scoreToScoreFlow() { assertEquals(SuperState.SCORE_FLOW, Superstructure.getState()); // Should be in FEED_FLOW now } + + @Test + void shouldFail() { + assertEquals(true, false); + } } From 0df3fc90dbce483b4725c414e2291c79b7ace927 Mon Sep 17 00:00:00 2001 From: SCool62 Date: Sat, 17 Jan 2026 13:01:47 -0800 Subject: [PATCH 21/28] Revert "Failing test to test ci" because we don't need the failing test anymore This reverts commit 8578bb3df1aaec49b0ecf5f4e3f25da319892f07. --- src/test/java/frc/robot/SuperstructureTest.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/test/java/frc/robot/SuperstructureTest.java b/src/test/java/frc/robot/SuperstructureTest.java index 32eff03..bca2675 100644 --- a/src/test/java/frc/robot/SuperstructureTest.java +++ b/src/test/java/frc/robot/SuperstructureTest.java @@ -295,9 +295,4 @@ void scoreToScoreFlow() { assertEquals(SuperState.SCORE_FLOW, Superstructure.getState()); // Should be in FEED_FLOW now } - - @Test - void shouldFail() { - assertEquals(true, false); - } } From b8a3afd7d11862eec15b502c67bd32c6c919c332 Mon Sep 17 00:00:00 2001 From: SCool62 Date: Sat, 17 Jan 2026 13:10:03 -0800 Subject: [PATCH 22/28] IDLE to flowstate tests --- .github/workflows/checks.yml | 2 +- .../java/frc/robot/SuperstructureTest.java | 53 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 6a5beef..12bde68 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -89,5 +89,5 @@ jobs: run: chmod +x gradlew # Runs a single command using the runners shell - - name: Run formatting check + - name: Run tests run: ./gradlew test diff --git a/src/test/java/frc/robot/SuperstructureTest.java b/src/test/java/frc/robot/SuperstructureTest.java index bca2675..b5b408d 100644 --- a/src/test/java/frc/robot/SuperstructureTest.java +++ b/src/test/java/frc/robot/SuperstructureTest.java @@ -295,4 +295,57 @@ void scoreToScoreFlow() { assertEquals(SuperState.SCORE_FLOW, Superstructure.getState()); // Should be in FEED_FLOW now } + + @Test + void idleToFeedFlow() { + assertEquals(SuperState.IDLE, Superstructure.getState()); // Ensure we start in IDLE + assertEquals(feedReq, false); + + flowReq = true; // We want to flow + + // Some time passes... + for (int i = 0; i < 50; i++) { + CommandScheduler.getInstance().run(); + } + + assertEquals( + SuperState.IDLE, + Superstructure.getState()); // Shouldn't transition yet bc feedReq is still false + + feedReq = true; // We want to feed + + // Some time passes... + for (int i = 0; i < 50; i++) { + CommandScheduler.getInstance().run(); + } + + assertEquals(SuperState.FEED_FLOW, Superstructure.getState()); // Should be in FEED_FLOW now + } + + @Test + void idleToScoreFlow() { + assertEquals(SuperState.IDLE, Superstructure.getState()); // Ensure we start in IDLE + assertEquals(scoreReq, false); + + flowReq = true; // We want to flow + + // Some time passes... + for (int i = 0; i < 50; i++) { + CommandScheduler.getInstance().run(); + } + + assertEquals( + SuperState.IDLE, + Superstructure.getState()); // Shouldn't transition yet bc scoreReq is still false + + scoreReq = true; // We want to score + + // Some time passes... + for (int i = 0; i < 50; i++) { + CommandScheduler.getInstance().run(); + } + + assertEquals(SuperState.SCORE_FLOW, Superstructure.getState()); // Should be in SCORE_FLOW now + } + } From 32bfc024dd68b2f89c888a8460f7a255cabc0b8c Mon Sep 17 00:00:00 2001 From: SCool62 Date: Sun, 18 Jan 2026 11:39:16 -0800 Subject: [PATCH 23/28] Flow state to idle --- .../java/frc/robot/SuperstructureTest.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/src/test/java/frc/robot/SuperstructureTest.java b/src/test/java/frc/robot/SuperstructureTest.java index b5b408d..0306bb1 100644 --- a/src/test/java/frc/robot/SuperstructureTest.java +++ b/src/test/java/frc/robot/SuperstructureTest.java @@ -348,4 +348,37 @@ void idleToScoreFlow() { assertEquals(SuperState.SCORE_FLOW, Superstructure.getState()); // Should be in SCORE_FLOW now } + @Test + void feedFlowToIdle() { + idleToFeedFlow(); // Get into feed flow + assertEquals(SuperState.FEED_FLOW, Superstructure.getState()); + assertEquals(true, flowReq); + assertEquals(true, feedReq); + + flowReq = false; + + // Some time passes... + for (int i = 0; i < 50; i++) { + CommandScheduler.getInstance().run(); + } + + assertEquals(SuperState.IDLE, Superstructure.getState()); + } + + @Test + void scoreFlowToIdle() { + idleToScoreFlow(); // Get into feed flow + assertEquals(SuperState.SCORE_FLOW, Superstructure.getState()); + assertEquals(true, flowReq); + assertEquals(true, scoreReq); + + flowReq = false; + + // Some time passes... + for (int i = 0; i < 50; i++) { + CommandScheduler.getInstance().run(); + } + + assertEquals(SuperState.IDLE, Superstructure.getState()); + } } From 31d4b275a3a807ee027bf42adf2319d79b12c7f7 Mon Sep 17 00:00:00 2001 From: SCool62 Date: Thu, 22 Jan 2026 17:37:09 -0800 Subject: [PATCH 24/28] Make it build --- src/main/java/frc/robot/Superstructure.java | 2 +- src/main/java/frc/robot/components/rollers/RollerIO.java | 4 ++-- .../frc/robot/subsystems/indexer/IndexerSubsystem.java | 5 +++-- .../java/frc/robot/subsystems/shooter/FlywheelIO.java | 8 +++++++- .../frc/robot/subsystems/shooter/ShooterSubsystem.java | 8 +++++++- 5 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/main/java/frc/robot/Superstructure.java b/src/main/java/frc/robot/Superstructure.java index 56fcefa..f38713a 100644 --- a/src/main/java/frc/robot/Superstructure.java +++ b/src/main/java/frc/robot/Superstructure.java @@ -111,7 +111,7 @@ public Superstructure( SwerveSubsystem swerve, IndexerSubsystem indexer, IntakeSubsystem intake, - HoodSubsystem shooter, + ShooterSubsystem shooter, Trigger scoreReq, Trigger intakeReq, Trigger feedReq, diff --git a/src/main/java/frc/robot/components/rollers/RollerIO.java b/src/main/java/frc/robot/components/rollers/RollerIO.java index 502f4c4..1fd4180 100644 --- a/src/main/java/frc/robot/components/rollers/RollerIO.java +++ b/src/main/java/frc/robot/components/rollers/RollerIO.java @@ -14,7 +14,7 @@ import edu.wpi.first.wpilibj2.command.Command; import org.littletonrobotics.junction.AutoLog; -public class RollerIO { +public class RollerIO implements AutoCloseable { @AutoLog public static class RollerIOInputs { @@ -90,6 +90,6 @@ public Command getVoltage() { @Override public void close() throws Exception { - rollerMotor.close(); + motor.close(); } } diff --git a/src/main/java/frc/robot/subsystems/indexer/IndexerSubsystem.java b/src/main/java/frc/robot/subsystems/indexer/IndexerSubsystem.java index ca3b0a2..9ee6d52 100644 --- a/src/main/java/frc/robot/subsystems/indexer/IndexerSubsystem.java +++ b/src/main/java/frc/robot/subsystems/indexer/IndexerSubsystem.java @@ -166,7 +166,7 @@ public void periodic() { Logger.processInputs("Indexer/Second Beambreak", secondCANRangeInputs); indexRollerIO.updateInputs(rollerInputs); Logger.processInputs("Indexer/Roller", rollerInputs); - kickerIO.updateInputs(kickerInputs); + kickerIO.updateInputs(kickerInputs); Logger.processInputs("Intake/Kicker", kickerInputs); } @@ -180,6 +180,7 @@ public Command runRollerSysId() { @Override public void close() throws Exception { - rollerIO.close(); + indexRollerIO.close(); + kickerIO.close(); } } diff --git a/src/main/java/frc/robot/subsystems/shooter/FlywheelIO.java b/src/main/java/frc/robot/subsystems/shooter/FlywheelIO.java index ac355ed..17d3617 100644 --- a/src/main/java/frc/robot/subsystems/shooter/FlywheelIO.java +++ b/src/main/java/frc/robot/subsystems/shooter/FlywheelIO.java @@ -22,7 +22,7 @@ import org.littletonrobotics.junction.AutoLog; /** Add your docs here. */ -public class FlywheelIO { +public class FlywheelIO implements AutoCloseable { @AutoLog public static class FlywheelIOInputs { @@ -166,4 +166,10 @@ public void updateInputs(FlywheelIOInputs inputs) { public double getSetpointRotPerSec() { return velocitySetpointRotPerSec; } + + @Override + public void close() { + flywheelFollower.close(); + flywheelLeader.close(); + } } diff --git a/src/main/java/frc/robot/subsystems/shooter/ShooterSubsystem.java b/src/main/java/frc/robot/subsystems/shooter/ShooterSubsystem.java index 9cfde0a..2ab426b 100644 --- a/src/main/java/frc/robot/subsystems/shooter/ShooterSubsystem.java +++ b/src/main/java/frc/robot/subsystems/shooter/ShooterSubsystem.java @@ -21,7 +21,7 @@ import java.util.function.Supplier; import org.littletonrobotics.junction.Logger; -public class ShooterSubsystem extends SubsystemBase { +public class ShooterSubsystem extends SubsystemBase implements AutoCloseable { public static double HOOD_GEAR_RATIO = 147.0 / 13.0; public static Rotation2d HOOD_MAX_ROTATION = Rotation2d.fromDegrees(40); public static Rotation2d HOOD_MIN_ROTATION = Rotation2d.fromDegrees(0); @@ -152,4 +152,10 @@ public boolean atFlywheelVelocitySetpoint() { flywheelIO.getSetpointRotPerSec(), FLYWHEEL_VELOCITY_TOLERANCE_ROTATIONS_PER_SECOND); } + + @Override + public void close() throws Exception { + flywheelIO.close(); + hoodIO.close(); + } } From 9d57e73d4249967b1c4bd3da3247e8318acbf547 Mon Sep 17 00:00:00 2001 From: SCool62 Date: Thu, 22 Jan 2026 17:40:25 -0800 Subject: [PATCH 25/28] Fix errors in --- src/test/java/frc/robot/SuperstructureTest.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/java/frc/robot/SuperstructureTest.java b/src/test/java/frc/robot/SuperstructureTest.java index 0306bb1..48d4c50 100644 --- a/src/test/java/frc/robot/SuperstructureTest.java +++ b/src/test/java/frc/robot/SuperstructureTest.java @@ -8,11 +8,12 @@ import edu.wpi.first.wpilibj2.command.CommandScheduler; import edu.wpi.first.wpilibj2.command.button.Trigger; import frc.robot.Superstructure.SuperState; -import frc.robot.components.rollers.RollerIOReal; -import frc.robot.subsystems.hood.HoodIOSim; -import frc.robot.subsystems.hood.HoodSubsystem; +import frc.robot.components.rollers.RollerIO; import frc.robot.subsystems.indexer.IndexerSubsystem; import frc.robot.subsystems.intake.IntakeSubsystem; +import frc.robot.subsystems.shooter.FlywheelIO; +import frc.robot.subsystems.shooter.HoodIO; +import frc.robot.subsystems.shooter.ShooterSubsystem; import frc.robot.subsystems.swerve.SwerveSubsystem; import java.lang.reflect.Field; import org.junit.jupiter.api.AfterEach; @@ -22,7 +23,7 @@ public class SuperstructureTest { Superstructure superstructure; IntakeSubsystem intake; - HoodSubsystem shooter; + ShooterSubsystem shooter; IndexerSubsystem routing; SwerveSubsystem swerve; @@ -60,11 +61,10 @@ void setup() { isFull = false; isEmpty = true; - intake = new IntakeSubsystem(new RollerIOReal(10, IntakeSubsystem.getIntakeIOConfig())); - shooter = new HoodSubsystem(new HoodIOSim(new CANBus())); + intake = new IntakeSubsystem(new RollerIO(10, IntakeSubsystem.getIntakeConfig(), new CANBus())); + shooter = new ShooterSubsystem(new HoodIO(HoodIO.getHoodConfiguration(), new CANBus()), new FlywheelIO(FlywheelIO.getFlywheelConfiguration(), new CANBus())); routing = - new IndexerSubsystem( - new CANBus(), new RollerIOReal(11, IndexerSubsystem.getIndexerConfigs())); + new IndexerSubsystem(new CANBus(), new RollerIO(11, IndexerSubsystem.getIndexerConfigs(), new CANBus()), new RollerIO(12, IndexerSubsystem.getKickerConfigs(), new CANBus())); swerve = new SwerveSubsystem(new CANBus()); superstructure = From e9286083cd882fce42cde213cd45e74d196d53d4 Mon Sep 17 00:00:00 2001 From: SCool62 Date: Thu, 22 Jan 2026 17:53:29 -0800 Subject: [PATCH 26/28] Cleanup test class. Tests aren't passing but bringup has some fixes --- src/main/java/frc/robot/Superstructure.java | 2 +- .../java/frc/robot/SuperstructureTest.java | 43 +++++++++++-------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/main/java/frc/robot/Superstructure.java b/src/main/java/frc/robot/Superstructure.java index f38713a..fc7987e 100644 --- a/src/main/java/frc/robot/Superstructure.java +++ b/src/main/java/frc/robot/Superstructure.java @@ -175,7 +175,7 @@ private void addTransitions() { bindTransition( SuperState.INTAKE, SuperState.READY, (intakeReq.negate().and(isEmpty.negate())).or(isFull)); - bindTransition(SuperState.INTAKE, SuperState.SPIN_UP_FEED, feedReq); + bindTransition(SuperState.READY, SuperState.SPIN_UP_FEED, feedReq); bindTransition(SuperState.READY, SuperState.INTAKE, intakeReq.and(isFull.negate())); diff --git a/src/test/java/frc/robot/SuperstructureTest.java b/src/test/java/frc/robot/SuperstructureTest.java index 48d4c50..98e7201 100644 --- a/src/test/java/frc/robot/SuperstructureTest.java +++ b/src/test/java/frc/robot/SuperstructureTest.java @@ -62,9 +62,15 @@ void setup() { isEmpty = true; intake = new IntakeSubsystem(new RollerIO(10, IntakeSubsystem.getIntakeConfig(), new CANBus())); - shooter = new ShooterSubsystem(new HoodIO(HoodIO.getHoodConfiguration(), new CANBus()), new FlywheelIO(FlywheelIO.getFlywheelConfiguration(), new CANBus())); + shooter = + new ShooterSubsystem( + new HoodIO(HoodIO.getHoodConfiguration(), new CANBus()), + new FlywheelIO(FlywheelIO.getFlywheelConfiguration(), new CANBus())); routing = - new IndexerSubsystem(new CANBus(), new RollerIO(11, IndexerSubsystem.getIndexerConfigs(), new CANBus()), new RollerIO(12, IndexerSubsystem.getKickerConfigs(), new CANBus())); + new IndexerSubsystem( + new CANBus(), + new RollerIO(11, IndexerSubsystem.getIndexerConfigs(), new CANBus()), + new RollerIO(12, IndexerSubsystem.getKickerConfigs(), new CANBus())); swerve = new SwerveSubsystem(new CANBus()); superstructure = @@ -179,22 +185,21 @@ void intakeToReadyFull() { } @Test - void readyToScore() { + void readyToSpinUpScore() { intakeToReadyNotFull(); // Get into ready scoreReq = true; // I.e. press button to start scoring - // Some time passes... - for (int i = 0; i < 50; i++) { - CommandScheduler.getInstance().run(); - } + // + CommandScheduler.getInstance().run(); - assertEquals(SuperState.SCORE, Superstructure.getState()); + // Same note as readyToSpinUpFeed + assertEquals(SuperState.SPIN_UP_SCORE, Superstructure.getState()); } @Test void scoreToIdle() { - readyToScore(); // Start scoring + // readyToScore(); // Start scoring assertEquals(SuperState.SCORE, Superstructure.getState()); // Ensure we're still scoring assertEquals(true, scoreReq); @@ -221,22 +226,22 @@ void scoreToIdle() { } @Test - void readyToFeed() { + void readyToSpinUpFeed() { intakeToReadyNotFull(); // Get into ready feedReq = true; // I.e. press button to start scoring - // Some time passes... - for (int i = 0; i < 50; i++) { - CommandScheduler.getInstance().run(); - } - - assertEquals(SuperState.FEED, Superstructure.getState()); + // One cycle to change states + CommandScheduler.getInstance().run(); + // I believe this test is failing bc when the check runs, the flywheel actual and setpoint + // velocity are both zero. Fixed in bringup by adding a debounce. When that gets merged, will + // work on maiking this pass + assertEquals(SuperState.SPIN_UP_FEED, Superstructure.getState()); } @Test void feedToIdle() { - readyToFeed(); // Start feeding + // readyToFeed(); // Start feeding assertEquals(SuperState.FEED, Superstructure.getState()); // Ensure we're still scoring assertEquals(true, feedReq); @@ -264,7 +269,7 @@ void feedToIdle() { @Test void feedToFeedFlow() { - readyToFeed(); // Get into feed + // readyToFeed(); // Get into feed assertEquals(SuperState.FEED, Superstructure.getState()); // Ensure we're still feeding assertEquals(true, feedReq); // Make sure we're still requesting to feed @@ -281,7 +286,7 @@ void feedToFeedFlow() { @Test void scoreToScoreFlow() { - readyToScore(); // Get into score + // readyToScore(); // Get into score assertEquals(SuperState.SCORE, Superstructure.getState()); // Ensure we're still feeding assertEquals(true, scoreReq); // Make sure we're still requesting to feed From 73c2db7514fc90e4d5dea9ee0be2dd67e895c151 Mon Sep 17 00:00:00 2001 From: SCool62 Date: Fri, 23 Jan 2026 09:04:54 -0800 Subject: [PATCH 27/28] Autocloseable impl (again) --- src/main/java/frc/robot/Superstructure.java | 9 ++++----- src/main/java/frc/robot/subsystems/indexer/Indexer.java | 2 +- .../frc/robot/subsystems/indexer/LindexerSubsystem.java | 2 +- .../frc/robot/subsystems/indexer/SpindexerSubsystem.java | 5 +++++ .../frc/robot/subsystems/intake/FintakeSubsystem.java | 2 +- src/main/java/frc/robot/subsystems/intake/Intake.java | 2 +- .../frc/robot/subsystems/intake/LintakeSubsystem.java | 5 +++++ src/main/java/frc/robot/subsystems/shooter/Shooter.java | 2 +- .../frc/robot/subsystems/shooter/ShooterSubsystem.java | 2 +- .../frc/robot/subsystems/shooter/TurretSubsystem.java | 5 +++++ 10 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/main/java/frc/robot/Superstructure.java b/src/main/java/frc/robot/Superstructure.java index dcbeca3..9d51ee6 100644 --- a/src/main/java/frc/robot/Superstructure.java +++ b/src/main/java/frc/robot/Superstructure.java @@ -11,6 +11,7 @@ import edu.wpi.first.wpilibj2.command.Commands; import edu.wpi.first.wpilibj2.command.button.Trigger; import frc.robot.subsystems.indexer.Indexer; +import frc.robot.subsystems.indexer.LindexerSubsystem; import frc.robot.subsystems.intake.Intake; import frc.robot.subsystems.shooter.Shooter; import frc.robot.subsystems.swerve.SwerveSubsystem; @@ -116,13 +117,12 @@ public Superstructure( // Used for testing public Superstructure( SwerveSubsystem swerve, - IndexerSubsystem indexer, - IntakeSubsystem intake, - ShooterSubsystem shooter, + Indexer indexer, + Intake intake, + Shooter shooter, Trigger scoreReq, Trigger intakeReq, Trigger feedReq, - Trigger flowReq, Trigger antiJamReq, Trigger isFull, Trigger isEmpty) { @@ -133,7 +133,6 @@ public Superstructure( this.scoreReq = scoreReq; this.intakeReq = intakeReq; this.feedReq = feedReq; - this.flowReq = flowReq; this.antiJamReq = antiJamReq; this.isFull = isFull; this.isEmpty = isEmpty; diff --git a/src/main/java/frc/robot/subsystems/indexer/Indexer.java b/src/main/java/frc/robot/subsystems/indexer/Indexer.java index 6bd3118..f286754 100644 --- a/src/main/java/frc/robot/subsystems/indexer/Indexer.java +++ b/src/main/java/frc/robot/subsystems/indexer/Indexer.java @@ -7,7 +7,7 @@ import edu.wpi.first.wpilibj2.command.Command; /** Add your docs here. */ -public interface Indexer { +public interface Indexer extends AutoCloseable { public boolean isFull(); diff --git a/src/main/java/frc/robot/subsystems/indexer/LindexerSubsystem.java b/src/main/java/frc/robot/subsystems/indexer/LindexerSubsystem.java index 7dffc3f..a594a4f 100644 --- a/src/main/java/frc/robot/subsystems/indexer/LindexerSubsystem.java +++ b/src/main/java/frc/robot/subsystems/indexer/LindexerSubsystem.java @@ -17,7 +17,7 @@ import frc.robot.components.rollers.RollerIOInputsAutoLogged; import org.littletonrobotics.junction.Logger; -public class LindexerSubsystem extends SubsystemBase implements AutoCloseable, Indexer { +public class LindexerSubsystem extends SubsystemBase implements Indexer { // Add actual CanBus public static final double GEAR_RATIO = 2.0; diff --git a/src/main/java/frc/robot/subsystems/indexer/SpindexerSubsystem.java b/src/main/java/frc/robot/subsystems/indexer/SpindexerSubsystem.java index 4346925..32a16d5 100644 --- a/src/main/java/frc/robot/subsystems/indexer/SpindexerSubsystem.java +++ b/src/main/java/frc/robot/subsystems/indexer/SpindexerSubsystem.java @@ -58,4 +58,9 @@ public Command rest() { // TODO Auto-generated method stub throw new UnsupportedOperationException("Unimplemented method 'rest'"); } + + @Override + public void close() throws Exception { + // No-op rn bc nothing to close + } } diff --git a/src/main/java/frc/robot/subsystems/intake/FintakeSubsystem.java b/src/main/java/frc/robot/subsystems/intake/FintakeSubsystem.java index 7405174..d1c03b6 100644 --- a/src/main/java/frc/robot/subsystems/intake/FintakeSubsystem.java +++ b/src/main/java/frc/robot/subsystems/intake/FintakeSubsystem.java @@ -15,7 +15,7 @@ import org.littletonrobotics.junction.Logger; /** Fintake = Fixed Intake. !! ALPHA !! */ -public class FintakeSubsystem extends SubsystemBase implements Intake, AutoCloseable { +public class FintakeSubsystem extends SubsystemBase implements Intake { public static final double GEAR_RATIO = 2.0; private RollerIO io; diff --git a/src/main/java/frc/robot/subsystems/intake/Intake.java b/src/main/java/frc/robot/subsystems/intake/Intake.java index 9a6196f..3d18615 100644 --- a/src/main/java/frc/robot/subsystems/intake/Intake.java +++ b/src/main/java/frc/robot/subsystems/intake/Intake.java @@ -7,7 +7,7 @@ import edu.wpi.first.wpilibj2.command.Command; /** Add your docs here. */ -public interface Intake { +public interface Intake extends AutoCloseable { /** Run balls towards the shooter */ public Command intake(); diff --git a/src/main/java/frc/robot/subsystems/intake/LintakeSubsystem.java b/src/main/java/frc/robot/subsystems/intake/LintakeSubsystem.java index a400db1..3678cec 100644 --- a/src/main/java/frc/robot/subsystems/intake/LintakeSubsystem.java +++ b/src/main/java/frc/robot/subsystems/intake/LintakeSubsystem.java @@ -34,4 +34,9 @@ public Command rest() { // TODO Auto-generated method stub throw new UnsupportedOperationException("Unimplemented method 'rest'"); } + + @Override + public void close() throws Exception { + // No-op rn bc nothing to close + } } diff --git a/src/main/java/frc/robot/subsystems/shooter/Shooter.java b/src/main/java/frc/robot/subsystems/shooter/Shooter.java index cacef67..a95cda3 100644 --- a/src/main/java/frc/robot/subsystems/shooter/Shooter.java +++ b/src/main/java/frc/robot/subsystems/shooter/Shooter.java @@ -9,7 +9,7 @@ import java.util.function.Supplier; /** Add your docs here. */ -public interface Shooter { +public interface Shooter extends AutoCloseable { /** * Sets hood angle and flywheel velocity based on distance from hub from the shot map + current diff --git a/src/main/java/frc/robot/subsystems/shooter/ShooterSubsystem.java b/src/main/java/frc/robot/subsystems/shooter/ShooterSubsystem.java index 01ee943..cf6de47 100644 --- a/src/main/java/frc/robot/subsystems/shooter/ShooterSubsystem.java +++ b/src/main/java/frc/robot/subsystems/shooter/ShooterSubsystem.java @@ -23,7 +23,7 @@ import org.littletonrobotics.junction.AutoLogOutput; import org.littletonrobotics.junction.Logger; -public class ShooterSubsystem extends SubsystemBase implements Shooter, AutoCloseable { +public class ShooterSubsystem extends SubsystemBase implements Shooter { public static double HOOD_GEAR_RATIO = 147.0 / 13.0; public static Rotation2d HOOD_MAX_ROTATION = Rotation2d.fromDegrees(40); public static Rotation2d HOOD_MIN_ROTATION = Rotation2d.fromDegrees(2); diff --git a/src/main/java/frc/robot/subsystems/shooter/TurretSubsystem.java b/src/main/java/frc/robot/subsystems/shooter/TurretSubsystem.java index 685b95a..487b139 100644 --- a/src/main/java/frc/robot/subsystems/shooter/TurretSubsystem.java +++ b/src/main/java/frc/robot/subsystems/shooter/TurretSubsystem.java @@ -66,4 +66,9 @@ public Command testShoot() { // TODO Auto-generated method stub throw new UnsupportedOperationException("Unimplemented method 'testShoot'"); } + + @Override + public void close() throws Exception { + // No-op rn bc nothing to close + } } From b3061ff88270976a4118afbb2e7cedef0381274d Mon Sep 17 00:00:00 2001 From: SCool62 Date: Fri, 23 Jan 2026 09:20:01 -0800 Subject: [PATCH 28/28] Some cleanup in superstructure tests --- .../java/frc/robot/SuperstructureTest.java | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/test/java/frc/robot/SuperstructureTest.java b/src/test/java/frc/robot/SuperstructureTest.java index 98e7201..c968979 100644 --- a/src/test/java/frc/robot/SuperstructureTest.java +++ b/src/test/java/frc/robot/SuperstructureTest.java @@ -9,10 +9,14 @@ import edu.wpi.first.wpilibj2.command.button.Trigger; import frc.robot.Superstructure.SuperState; import frc.robot.components.rollers.RollerIO; -import frc.robot.subsystems.indexer.IndexerSubsystem; -import frc.robot.subsystems.intake.IntakeSubsystem; +import frc.robot.subsystems.indexer.Indexer; +import frc.robot.subsystems.indexer.LindexerSubsystem; +import frc.robot.subsystems.intake.FintakeSubsystem; +import frc.robot.subsystems.intake.Intake; +import frc.robot.subsystems.intake.LintakeSubsystem; import frc.robot.subsystems.shooter.FlywheelIO; import frc.robot.subsystems.shooter.HoodIO; +import frc.robot.subsystems.shooter.Shooter; import frc.robot.subsystems.shooter.ShooterSubsystem; import frc.robot.subsystems.swerve.SwerveSubsystem; import java.lang.reflect.Field; @@ -22,9 +26,9 @@ public class SuperstructureTest { Superstructure superstructure; - IntakeSubsystem intake; - ShooterSubsystem shooter; - IndexerSubsystem routing; + Intake intake; + Shooter shooter; + Indexer routing; SwerveSubsystem swerve; boolean scoreReq; @@ -61,16 +65,16 @@ void setup() { isFull = false; isEmpty = true; - intake = new IntakeSubsystem(new RollerIO(10, IntakeSubsystem.getIntakeConfig(), new CANBus())); + intake = new FintakeSubsystem(new RollerIO(10, FintakeSubsystem.getIntakeConfig(), new CANBus())); shooter = new ShooterSubsystem( new HoodIO(HoodIO.getHoodConfiguration(), new CANBus()), new FlywheelIO(FlywheelIO.getFlywheelConfiguration(), new CANBus())); routing = - new IndexerSubsystem( + new LindexerSubsystem( new CANBus(), - new RollerIO(11, IndexerSubsystem.getIndexerConfigs(), new CANBus()), - new RollerIO(12, IndexerSubsystem.getKickerConfigs(), new CANBus())); + new RollerIO(11, LindexerSubsystem.getIndexerConfigs(), new CANBus()), + new RollerIO(12, LindexerSubsystem.getKickerConfigs(), new CANBus())); swerve = new SwerveSubsystem(new CANBus()); superstructure = @@ -82,7 +86,6 @@ void setup() { new Trigger(() -> scoreReq), new Trigger(() -> intakeReq), new Trigger(() -> feedReq), - new Trigger(() -> flowReq), new Trigger(() -> antiJamReq), new Trigger(() -> isFull), new Trigger(() -> isEmpty));