diff --git a/src/main/java/frc/robot/RobotContainer.java b/src/main/java/frc/robot/RobotContainer.java index 621064f..cc89419 100644 --- a/src/main/java/frc/robot/RobotContainer.java +++ b/src/main/java/frc/robot/RobotContainer.java @@ -7,7 +7,6 @@ package frc.robot; -import static edu.wpi.first.units.Units.Volts; import static frc.robot.subsystems.vision.VisionConstants.*; import com.ctre.phoenix6.CANBus; @@ -15,7 +14,6 @@ import edu.wpi.first.wpilibj.XboxController; import edu.wpi.first.wpilibj2.command.Command; import edu.wpi.first.wpilibj2.command.Commands; -import edu.wpi.first.wpilibj2.command.InstantCommand; import edu.wpi.first.wpilibj2.command.button.CommandXboxController; import frc.robot.commands.DriveCommands; import frc.robot.generated.TunerConstants; @@ -24,13 +22,12 @@ import frc.robot.operator.OperatorIntent; import frc.robot.state.MatchState; import frc.robot.subsystems.drive.Drive; -import frc.robot.util.GoalBehavior; -import frc.robot.util.SubsystemBehavior; import frc.robot.subsystems.drive.GyroIO; import frc.robot.subsystems.drive.GyroIOPigeon2; import frc.robot.subsystems.drive.ModuleIO; import frc.robot.subsystems.drive.ModuleIOSim; import frc.robot.subsystems.drive.ModuleIOTalonFX; +import frc.robot.subsystems.launcher.LauncherBehavior; import frc.robot.subsystems.launcher.LauncherIOSim; import frc.robot.subsystems.launcher.LauncherIOTalonFX; import frc.robot.subsystems.launcher.LauncherSubsystem; @@ -38,6 +35,8 @@ import frc.robot.subsystems.vision.VisionIO; import frc.robot.subsystems.vision.VisionIOLimelight; import frc.robot.subsystems.vision.VisionIOPhotonVisionSim; +import frc.robot.util.GoalBehavior; +import frc.robot.util.SubsystemBehavior; /** * This class is where the bulk of the robot should be declared. Since Command-based is a @@ -155,6 +154,7 @@ public RobotContainer() { // Create goal behaviors (wires operator intent → robot goals) new RobotGoalsBehavior(robotGoals); + new LauncherBehavior(launcher); // TODO (students): Create subsystem behaviors here, e.g.: // new LauncherBehavior(launcher); @@ -162,7 +162,7 @@ public RobotContainer() { // Configure all behaviors GoalBehavior.configureAll(operatorIntent); - SubsystemBehavior.configureAll(robotGoals, matchState); + SubsystemBehavior.configureAll(robotGoals, matchState, launcher); // Configure the button bindings configureButtonBindings(); @@ -193,20 +193,6 @@ private void configureButtonBindings() { // () -> -controller.getLeftX(), // () -> Rotation2d.kZero)); - controller - .b() - .onTrue( - new InstantCommand( - () -> { - launcher.setLaunchSpeed(Volts.of(2)); - launcher.setIndexerSpeed(Volts.of(2)); - })) - .onFalse( - new InstantCommand( - () -> { - launcher.stop(); - })); - // Switch to X pattern when X button is pressed controller.x().onTrue(Commands.runOnce(drive::stopWithX, drive)); diff --git a/src/main/java/frc/robot/goals/RobotGoal.java b/src/main/java/frc/robot/goals/RobotGoal.java index 36226c3..7711d00 100644 --- a/src/main/java/frc/robot/goals/RobotGoal.java +++ b/src/main/java/frc/robot/goals/RobotGoal.java @@ -1,11 +1,12 @@ package frc.robot.goals; /** - * Enum representing what the robot is currently trying to accomplish. - * These are high-level goals, not hardware states. + * Enum representing what the robot is currently trying to accomplish. These are high-level goals, + * not hardware states. * *
TODO (students): Add your robot's goals here (e.g., LAUNCHING, INTAKING) */ public enum RobotGoal { - IDLE + IDLE, + LAUNCHING } diff --git a/src/main/java/frc/robot/goals/RobotGoalEvents.java b/src/main/java/frc/robot/goals/RobotGoalEvents.java index e9c6920..12f8dc2 100644 --- a/src/main/java/frc/robot/goals/RobotGoalEvents.java +++ b/src/main/java/frc/robot/goals/RobotGoalEvents.java @@ -3,11 +3,13 @@ import edu.wpi.first.wpilibj2.command.button.Trigger; /** - * Interface exposing robot goal triggers for behaviors to react to. - * Behaviors should only depend on this interface, not on RobotGoals directly. + * Interface exposing robot goal triggers for behaviors to react to. Behaviors should only depend on + * this interface, not on RobotGoals directly. * *
TODO (students): Add triggers for each goal in RobotGoal enum */ public interface RobotGoalEvents { - Trigger isIdle(); + Trigger isIdleTrigger(); + + Trigger isLaunchingTrigger(); } diff --git a/src/main/java/frc/robot/goals/RobotGoals.java b/src/main/java/frc/robot/goals/RobotGoals.java index 5d91cfe..e2121eb 100644 --- a/src/main/java/frc/robot/goals/RobotGoals.java +++ b/src/main/java/frc/robot/goals/RobotGoals.java @@ -9,31 +9,36 @@ /** * Central robot state: what we're doing (goal). * - * Can be set by: - * - Teleop via RobotGoalsBehavior reacting to OperatorIntent - * - Autonomous via direct command calls + *
Can be set by: - Teleop via RobotGoalsBehavior reacting to OperatorIntent - Autonomous via + * direct command calls * *
TODO (students): Add goal triggers for each value in RobotGoal enum
*/
public class RobotGoals extends VirtualSubsystem implements RobotGoalEvents {
- private final EnumState This is the teleop-specific logic. Autonomous bypasses this and calls RobotGoals.setGoal()
+ * directly.
*
- * TODO (students): Map your button intents to goals here
- * Example:
- * intent.wantsToScore().onTrue(goals.setGoal(RobotGoal.LAUNCHING))
- * .onFalse(goals.setGoal(RobotGoal.IDLE));
+ * TODO (students): Map your button intents to goals here Example:
+ * intent.wantsToScore().onTrue(goals.setGoal(RobotGoal.LAUNCHING))
+ * .onFalse(goals.setGoal(RobotGoal.IDLE));
*/
public class RobotGoalsBehavior extends GoalBehavior {
- private RobotGoals goals;
+ private RobotGoals goals;
- public RobotGoalsBehavior(RobotGoals goals) {
- this.goals = goals;
- }
+ public RobotGoalsBehavior(RobotGoals goals) {
+ this.goals = goals;
+ }
- @Override
- public void configure(OperatorIntentEvents intent) {
- // TODO (students): Wire intent triggers to goal state changes
- }
+ @Override
+ public void configure(OperatorIntentEvents intent) {
+ intent
+ .wantsToScoreTrigger()
+ .whileTrue(goals.setGoalCommand(RobotGoal.LAUNCHING))
+ .whileFalse(goals.setGoalCommand(RobotGoal.IDLE));
+ }
}
diff --git a/src/main/java/frc/robot/operator/OperatorIntent.java b/src/main/java/frc/robot/operator/OperatorIntent.java
index 2326133..2fab593 100644
--- a/src/main/java/frc/robot/operator/OperatorIntent.java
+++ b/src/main/java/frc/robot/operator/OperatorIntent.java
@@ -6,28 +6,33 @@
/**
* Interprets driver controller inputs into intent triggers.
*
- * This class has NO state - it just wraps controller buttons
- * and provides semantic meaning (wantsToScore vs rightTrigger).
+ * This class has NO state - it just wraps controller buttons and provides semantic meaning
+ * (wantsToScore vs rightTrigger).
*
- * State lives in RobotGoals. This class just says what the
- * operator is physically doing right now.
+ * State lives in RobotGoals. This class just says what the operator is physically doing right
+ * now.
*
* TODO (students): Map your controller buttons to semantic intents here
*/
public class OperatorIntent implements OperatorIntentEvents {
- private final CommandXboxController driver;
+ private final CommandXboxController driver;
- public OperatorIntent(int driverPort) {
- this.driver = new CommandXboxController(driverPort);
- }
+ public OperatorIntent(int driverPort) {
+ this.driver = new CommandXboxController(driverPort);
+ }
- @Override
- public Trigger wantsToScore() {
- return driver.rightTrigger(0.5);
- }
+ @Override
+ public Trigger wantsToScoreTrigger() {
+ return driver.rightTrigger(0.5);
+ }
- public CommandXboxController getDriver() {
- return driver;
- }
+ public CommandXboxController getDriver() {
+ return driver;
+ }
+
+ @Override
+ public Trigger wantsToOutake() {
+ return driver.b();
+ }
}
diff --git a/src/main/java/frc/robot/operator/OperatorIntentEvents.java b/src/main/java/frc/robot/operator/OperatorIntentEvents.java
index 2cdd6ca..8c83bb4 100644
--- a/src/main/java/frc/robot/operator/OperatorIntentEvents.java
+++ b/src/main/java/frc/robot/operator/OperatorIntentEvents.java
@@ -3,11 +3,13 @@
import edu.wpi.first.wpilibj2.command.button.Trigger;
/**
- * Interface exposing only the triggers that behaviors might need from OperatorIntent.
- * Keeps the contract minimal - behaviors shouldn't know about raw button inputs.
+ * Interface exposing only the triggers that behaviors might need from OperatorIntent. Keeps the
+ * contract minimal - behaviors shouldn't know about raw button inputs.
*
* TODO (students): Add intent triggers for your robot's actions
*/
public interface OperatorIntentEvents {
- Trigger wantsToScore();
+ Trigger wantsToScoreTrigger();
+
+ Trigger wantsToOutake();
}
diff --git a/src/main/java/frc/robot/state/MatchState.java b/src/main/java/frc/robot/state/MatchState.java
index dbe6bd5..9a0809e 100644
--- a/src/main/java/frc/robot/state/MatchState.java
+++ b/src/main/java/frc/robot/state/MatchState.java
@@ -5,33 +5,33 @@
import frc.robot.util.VirtualSubsystem;
/**
- * Exposes match phase state as triggers for behaviors to react to.
- * Wraps DriverStation calls into a reactive interface.
+ * Exposes match phase state as triggers for behaviors to react to. Wraps DriverStation calls into a
+ * reactive interface.
*/
public class MatchState extends VirtualSubsystem implements MatchStateEvents {
- @Override
- public Trigger isDisabled() {
- return new Trigger(DriverStation::isDisabled);
- }
+ @Override
+ public Trigger isDisabled() {
+ return new Trigger(DriverStation::isDisabled);
+ }
- @Override
- public Trigger isAutonomous() {
- return new Trigger(DriverStation::isAutonomousEnabled);
- }
+ @Override
+ public Trigger isAutonomous() {
+ return new Trigger(DriverStation::isAutonomousEnabled);
+ }
- @Override
- public Trigger isTeleop() {
- return new Trigger(DriverStation::isTeleopEnabled);
- }
+ @Override
+ public Trigger isTeleop() {
+ return new Trigger(DriverStation::isTeleopEnabled);
+ }
- @Override
- public Trigger isEnabled() {
- return new Trigger(DriverStation::isEnabled);
- }
+ @Override
+ public Trigger isEnabled() {
+ return new Trigger(DriverStation::isEnabled);
+ }
- @Override
- public void periodic() {
- // No periodic updates needed - triggers poll DriverStation directly
- }
+ @Override
+ public void periodic() {
+ // No periodic updates needed - triggers poll DriverStation directly
+ }
}
diff --git a/src/main/java/frc/robot/state/MatchStateEvents.java b/src/main/java/frc/robot/state/MatchStateEvents.java
index dcfbc09..a95afd6 100644
--- a/src/main/java/frc/robot/state/MatchStateEvents.java
+++ b/src/main/java/frc/robot/state/MatchStateEvents.java
@@ -3,20 +3,20 @@
import edu.wpi.first.wpilibj2.command.button.Trigger;
/**
- * Interface exposing match phase state as triggers for behaviors to react to.
- * Provides triggers for disabled, autonomous, teleop, and enabled states.
+ * Interface exposing match phase state as triggers for behaviors to react to. Provides triggers for
+ * disabled, autonomous, teleop, and enabled states.
*/
public interface MatchStateEvents {
- /** Trigger when robot is disabled */
- Trigger isDisabled();
+ /** Trigger when robot is disabled */
+ Trigger isDisabled();
- /** Trigger when robot is in autonomous mode */
- Trigger isAutonomous();
+ /** Trigger when robot is in autonomous mode */
+ Trigger isAutonomous();
- /** Trigger when robot is in teleop mode */
- Trigger isTeleop();
+ /** Trigger when robot is in teleop mode */
+ Trigger isTeleop();
- /** Trigger when robot is enabled (auto OR teleop) */
- Trigger isEnabled();
+ /** Trigger when robot is enabled (auto OR teleop) */
+ Trigger isEnabled();
}
diff --git a/src/main/java/frc/robot/subsystems/launcher/LauncherBehavior.java b/src/main/java/frc/robot/subsystems/launcher/LauncherBehavior.java
new file mode 100644
index 0000000..a7ec305
--- /dev/null
+++ b/src/main/java/frc/robot/subsystems/launcher/LauncherBehavior.java
@@ -0,0 +1,21 @@
+package frc.robot.subsystems.launcher;
+
+import frc.robot.goals.RobotGoalEvents;
+import frc.robot.state.MatchStateEvents;
+import frc.robot.util.SubsystemBehavior;
+
+public class LauncherBehavior extends SubsystemBehavior {
+
+ private final LauncherSubsystem launcher;
+
+ public LauncherBehavior(LauncherSubsystem launcher) {
+ this.launcher = launcher;
+ }
+
+ @Override
+ public void configure(
+ RobotGoalEvents goals, MatchStateEvents matchState, LauncherEvents launcherState) {
+ goals.isLaunchingTrigger().whileTrue(this.launcher.launchCommand());
+ goals.isIdleTrigger().whileTrue(this.launcher.idleCommand());
+ }
+}
diff --git a/src/main/java/frc/robot/subsystems/launcher/LauncherEvents.java b/src/main/java/frc/robot/subsystems/launcher/LauncherEvents.java
new file mode 100644
index 0000000..7bd5bf3
--- /dev/null
+++ b/src/main/java/frc/robot/subsystems/launcher/LauncherEvents.java
@@ -0,0 +1,9 @@
+package frc.robot.subsystems.launcher;
+
+import edu.wpi.first.wpilibj2.command.button.Trigger;
+
+public interface LauncherEvents {
+ public Trigger isIdleTrigger();
+
+ public Trigger isLaunchingTrigger();
+}
diff --git a/src/main/java/frc/robot/subsystems/launcher/LauncherState.java b/src/main/java/frc/robot/subsystems/launcher/LauncherState.java
new file mode 100644
index 0000000..4651ff5
--- /dev/null
+++ b/src/main/java/frc/robot/subsystems/launcher/LauncherState.java
@@ -0,0 +1,6 @@
+package frc.robot.subsystems.launcher;
+
+public enum LauncherState {
+ IDLE,
+ LAUNCHING
+}
diff --git a/src/main/java/frc/robot/subsystems/launcher/LauncherSubsystem.java b/src/main/java/frc/robot/subsystems/launcher/LauncherSubsystem.java
index 7d6ac4d..cc7999d 100644
--- a/src/main/java/frc/robot/subsystems/launcher/LauncherSubsystem.java
+++ b/src/main/java/frc/robot/subsystems/launcher/LauncherSubsystem.java
@@ -8,14 +8,20 @@
import static edu.wpi.first.units.Units.Volts;
import edu.wpi.first.units.measure.Voltage;
+import edu.wpi.first.wpilibj2.command.Command;
import edu.wpi.first.wpilibj2.command.SubsystemBase;
+import edu.wpi.first.wpilibj2.command.button.Trigger;
+import frc.robot.util.EnumState;
import org.littletonrobotics.junction.Logger;
/** Sets the controless the launcher and endexer */
-public class LauncherSubsystem extends SubsystemBase {
+public class LauncherSubsystem extends SubsystemBase implements LauncherEvents {
/** Creates a new ExampleSubsystem. */
private LauncherIO m_IO;
+ private final EnumState This is the foundation for both:
+ *
* All behaviors auto-register when constructed and can be configured in batch.
@@ -19,19 +20,19 @@
*/
public abstract class Behavior Example:
- * The state will be logged to "YourName/State" whenever it changes.
- *
- * Example:
- * Example:
+ *
+ * The state will be logged to "YourName/State" whenever it changes.
+ *
+ * Example:
+ *
+ * This is the main method you'll use! Example:
- * If logging is enabled, automatically logs the change to AdvantageKit.
- *
- * Example:
- * This is the main method you'll use! Example:
+ *
+ * Example:
- * If logging is enabled, automatically logs the change to AdvantageKit.
+ *
+ * Example:
+ *
+ * Example:
+ *
+ * Example:
- * Example:
+ *
+ * Example:
- * Example:
+ *
+ * Example:
- * Example:
+ *
+ * Useful for detecting transitions:
- * Useful for detecting transitions:
+ *
+ * Useful for debugging or dashboard integration.
- *
- * @return Map from enum value to its corresponding Trigger
- */
- public Map Useful for debugging or dashboard integration.
+ *
+ * @return Map from enum value to its corresponding Trigger
+ */
+ public Map Usually not needed since set() logs automatically,
- * but can be called in periodic() if desired.
- */
- public void log() {
- if (name != null) {
- Logger.recordOutput(name + "/State", currentState.name());
- }
+ /**
+ * Manually trigger a log update.
+ *
+ * Usually not needed since set() logs automatically, but can be called in periodic() if
+ * desired.
+ */
+ public void log() {
+ if (name != null) {
+ Logger.recordOutput(name + "/State", currentState.name());
}
+ }
- /**
- * Returns the current state name as a string.
- */
- @Override
- public String toString() {
- return currentState.name();
- }
+ /** Returns the current state name as a string. */
+ @Override
+ public String toString() {
+ return currentState.name();
+ }
}
diff --git a/src/main/java/frc/robot/util/Gains.java b/src/main/java/frc/robot/util/Gains.java
index 110f79b..d487ce0 100644
--- a/src/main/java/frc/robot/util/Gains.java
+++ b/src/main/java/frc/robot/util/Gains.java
@@ -15,134 +15,134 @@
* } Goal behaviors listen to the UI layer (OperatorIntent) and drive the
- * API layer (RobotGoals state).
+ * Goal behaviors listen to the UI layer (OperatorIntent) and drive the API layer (RobotGoals
+ * state).
*
* Usage:
+ *
* Subsystem behaviors listen to the API layer (RobotGoalEvents) and drive
- * the hardware layer (Launcher, Drive, etc.).
+ * Subsystem behaviors listen to the API layer (RobotGoalEvents) and drive the hardware layer
+ * (Launcher, Drive, etc.).
*
* Usage:
+ *
* TODO (students): Add additional subsystem event interfaces to the signature
- * as you create them (e.g., LauncherEvents, DriveEvents)
+ * TODO (students): Add additional subsystem event interfaces to the signature as you create them
+ * (e.g., LauncherEvents, DriveEvents)
*/
public abstract class SubsystemBehavior extends Behavior
- *
*
* Basic Usage:
+ *
* {@code
* // 1. Define your states as an enum
* public enum IntakeState { IDLE, INTAKING, HOLDING, EJECTING }
@@ -28,6 +29,7 @@
* }
*
* With Automatic Logging:
+ *
* {@code
* // Add a name and it logs automatically to AdvantageKit!
* private final EnumState
*
* In RobotContainer Bindings:
+ *
* {@code
* // These triggers work just like any other WPILib Trigger
* intake.state.is(HOLDING)
@@ -50,251 +53,259 @@
*/
public class EnumState
*/
public class Gains {
- public final double kP;
- public final double kI;
- public final double kD;
- public final double kS;
- public final double kG;
- public final double kV;
- public final double kA;
-
- // Motion Magic parameters
- public final double kMMV;
- public final double kMMA;
- public final double kMMJ;
- public final double kMMEV;
- public final double kMMEA;
-
- private Gains(
- double kP,
- double kI,
- double kD,
- double kS,
- double kG,
- double kV,
- double kA,
- double kMMV,
- double kMMA,
- double kMMJ,
- double kMMEV,
- double kMMEA) {
- this.kP = kP;
- this.kI = kI;
- this.kD = kD;
- this.kS = kS;
- this.kG = kG;
- this.kV = kV;
- this.kA = kA;
-
- this.kMMV = kMMV;
- this.kMMA = kMMA;
- this.kMMJ = kMMJ;
- this.kMMEA = kMMEA;
- this.kMMEV = kMMEV;
+ public final double kP;
+ public final double kI;
+ public final double kD;
+ public final double kS;
+ public final double kG;
+ public final double kV;
+ public final double kA;
+
+ // Motion Magic parameters
+ public final double kMMV;
+ public final double kMMA;
+ public final double kMMJ;
+ public final double kMMEV;
+ public final double kMMEA;
+
+ private Gains(
+ double kP,
+ double kI,
+ double kD,
+ double kS,
+ double kG,
+ double kV,
+ double kA,
+ double kMMV,
+ double kMMA,
+ double kMMJ,
+ double kMMEV,
+ double kMMEA) {
+ this.kP = kP;
+ this.kI = kI;
+ this.kD = kD;
+ this.kS = kS;
+ this.kG = kG;
+ this.kV = kV;
+ this.kA = kA;
+
+ this.kMMV = kMMV;
+ this.kMMA = kMMA;
+ this.kMMJ = kMMJ;
+ this.kMMEA = kMMEA;
+ this.kMMEV = kMMEV;
+ }
+
+ public static Gains getEmpty() {
+ return new Gains(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private double kP = 0;
+ private double kI = 0;
+ private double kD = 0;
+ private double kS = 0;
+ private double kG = 0;
+ private double kV = 0;
+ private double kA = 0;
+
+ private double kMMV = 0;
+ private double kMMA = 0;
+ private double kMMJ = 0;
+ private double kMMEV = 0;
+ private double kMMEA = 0;
+
+ public Builder kP(double kP) {
+ this.kP = kP;
+ return this;
}
- public static Gains getEmpty() {
- return new Gains(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ public Builder kI(double kI) {
+ this.kI = kI;
+ return this;
}
- public static Builder builder() {
- return new Builder();
+ public Builder kD(double kD) {
+ this.kD = kD;
+ return this;
}
- public static class Builder {
- private double kP = 0;
- private double kI = 0;
- private double kD = 0;
- private double kS = 0;
- private double kG = 0;
- private double kV = 0;
- private double kA = 0;
-
- private double kMMV = 0;
- private double kMMA = 0;
- private double kMMJ = 0;
- private double kMMEV = 0;
- private double kMMEA = 0;
-
- public Builder kP(double kP) {
- this.kP = kP;
- return this;
- }
-
- public Builder kI(double kI) {
- this.kI = kI;
- return this;
- }
-
- public Builder kD(double kD) {
- this.kD = kD;
- return this;
- }
-
- public Builder kS(double kS) {
- this.kS = kS;
- return this;
- }
-
- public Builder kG(double kG) {
- this.kG = kG;
- return this;
- }
-
- public Builder kV(double kV) {
- this.kV = kV;
- return this;
- }
-
- public Builder kA(double kA) {
- this.kA = kA;
- return this;
- }
-
- public Builder kMMV(double kMMV) {
- this.kMMV = kMMV;
- return this;
- }
-
- public Builder kMMA(double kMMA) {
- this.kMMA = kMMA;
- return this;
- }
-
- public Builder kMMJ(double kMMJ) {
- this.kMMJ = kMMJ;
- return this;
- }
-
- public Builder kMMEV(double kMMEV) {
- this.kMMEV = kMMEV;
- return this;
- }
-
- public Builder kMMEA(double kMMEA) {
- this.kMMEA = kMMEA;
- return this;
- }
-
- public Gains build() {
- return new Gains(kP, kI, kD, kS, kG, kV, kA, kMMV, kMMA, kMMJ, kMMEV, kMMEA);
- }
+ public Builder kS(double kS) {
+ this.kS = kS;
+ return this;
}
+
+ public Builder kG(double kG) {
+ this.kG = kG;
+ return this;
+ }
+
+ public Builder kV(double kV) {
+ this.kV = kV;
+ return this;
+ }
+
+ public Builder kA(double kA) {
+ this.kA = kA;
+ return this;
+ }
+
+ public Builder kMMV(double kMMV) {
+ this.kMMV = kMMV;
+ return this;
+ }
+
+ public Builder kMMA(double kMMA) {
+ this.kMMA = kMMA;
+ return this;
+ }
+
+ public Builder kMMJ(double kMMJ) {
+ this.kMMJ = kMMJ;
+ return this;
+ }
+
+ public Builder kMMEV(double kMMEV) {
+ this.kMMEV = kMMEV;
+ return this;
+ }
+
+ public Builder kMMEA(double kMMEA) {
+ this.kMMEA = kMMEA;
+ return this;
+ }
+
+ public Gains build() {
+ return new Gains(kP, kI, kD, kS, kG, kV, kA, kMMV, kMMA, kMMJ, kMMEV, kMMEA);
+ }
+ }
}
diff --git a/src/main/java/frc/robot/util/GoalBehavior.java b/src/main/java/frc/robot/util/GoalBehavior.java
index 06611e9..13347c0 100644
--- a/src/main/java/frc/robot/util/GoalBehavior.java
+++ b/src/main/java/frc/robot/util/GoalBehavior.java
@@ -5,13 +5,14 @@
import java.util.List;
/**
- * Base class for goal-level behaviors that react to operator intent.
- * These behaviors translate operator intent into robot goal state changes.
+ * Base class for goal-level behaviors that react to operator intent. These behaviors translate
+ * operator intent into robot goal state changes.
*
- * {@code
- * private final EnumState
- *
- * @param initialState The starting state
- */
- public EnumState(E initialState) {
- this(null, initialState);
- }
+ private E currentState;
+ private E previousState;
+ private final String name;
+ private final Class{@code
- * // Logs to "Intake/State" in AdvantageKit
- * private final EnumState
- *
- * @param name The name for logging (e.g., "Intake", "Shooter")
- * @param initialState The starting state
- */
- @SuppressWarnings("unchecked")
- public EnumState(String name, E initialState) {
- this.currentState = initialState;
- this.previousState = initialState;
- this.name = name;
- this.enumClass = (Class{@code
+ * private final EnumState
+ *
+ * @param initialState The starting state
+ */
+ public EnumState(E initialState) {
+ this(null, initialState);
+ }
- // Pre-create triggers for every enum value
- // This way .is() always returns the same Trigger instance
- for (E value : enumClass.getEnumConstants()) {
- triggerCache.put(value, new Trigger(() -> currentState == value));
- }
+ /**
+ * Create a new EnumState with automatic AdvantageKit logging.
+ *
+ * {@code
+ * // Logs to "Intake/State" in AdvantageKit
+ * private final EnumState
+ *
+ * @param name The name for logging (e.g., "Intake", "Shooter")
+ * @param initialState The starting state
+ */
+ @SuppressWarnings("unchecked")
+ public EnumState(String name, E initialState) {
+ this.currentState = initialState;
+ this.previousState = initialState;
+ this.name = name;
+ this.enumClass = (Class{@code
- * // In RobotContainer:
- * intake.state.is(IntakeState.HOLDING)
- * .onTrue(flashLEDsCommand());
- *
- * // Combine with other triggers:
- * driver.a()
- * .and(intake.state.is(HOLDING))
- * .and(shooter.state.is(READY))
- * .onTrue(shootCommand());
- * }
- *
- * @param state The state to check for
- * @return A Trigger that is true when currentState equals the given state
- */
- public Trigger is(E state) {
- return triggerCache.get(state);
- }
+ // ==================== CORE METHODS ====================
- /**
- * Change to a new state.
- *
- * {@code
- * public Command intakeCommand() {
- * return startEnd(
- * () -> state.set(IntakeState.INTAKING),
- * () -> state.set(IntakeState.IDLE)
- * );
- * }
- * }
- *
- * @param newState The state to change to
- */
- public void set(E newState) {
- if (currentState != newState) {
- previousState = currentState;
- currentState = newState;
- log();
- }
- }
+ /**
+ * Get a Trigger that is TRUE when in the specified state.
+ *
+ * {@code
+ * // In RobotContainer:
+ * intake.state.is(IntakeState.HOLDING)
+ * .onTrue(flashLEDsCommand());
+ *
+ * // Combine with other triggers:
+ * driver.a()
+ * .and(intake.state.is(HOLDING))
+ * .and(shooter.state.is(READY))
+ * .onTrue(shootCommand());
+ * }
+ *
+ * @param state The state to check for
+ * @return A Trigger that is true when currentState equals the given state
+ */
+ public Trigger is(E state) {
+ return triggerCache.get(state);
+ }
- /**
- * Get the current state.
- *
- * {@code
- * if (state.get() == IntakeState.HOLDING) {
- * // Do something
- * }
- * }
- *
- * @return The current state
- */
- public E get() {
- return currentState;
+ /**
+ * Change to a new state.
+ *
+ * {@code
+ * public Command intakeCommand() {
+ * return startEnd(
+ * () -> state.set(IntakeState.INTAKING),
+ * () -> state.set(IntakeState.IDLE)
+ * );
+ * }
+ * }
+ *
+ * @param newState The state to change to
+ */
+ public void set(E newState) {
+ if (currentState != newState) {
+ previousState = currentState;
+ currentState = newState;
+ log();
}
+ }
+
+ /**
+ * Get the current state.
+ *
+ * {@code
+ * if (state.get() == IntakeState.HOLDING) {
+ * // Do something
+ * }
+ * }
+ *
+ * @return The current state
+ */
+ public E get() {
+ return currentState;
+ }
- // ==================== CONVENIENCE METHODS ====================
+ // ==================== CONVENIENCE METHODS ====================
- /**
- * Get a Trigger that is TRUE when in ANY of the specified states.
- *
- * {@code
- * // True when IDLE or HOLDING (not actively moving)
- * state.isAnyOf(IntakeState.IDLE, IntakeState.HOLDING)
- * .whileTrue(allowShootingCommand());
- * }
- *
- * @param states The states to check for (varargs - pass as many as you want)
- * @return A Trigger that is true when in any of the given states
- */
- @SafeVarargs
- public final Trigger isAnyOf(E... states) {
- return new Trigger(() -> {
- for (E state : states) {
- if (currentState == state) {
- return true;
- }
+ /**
+ * Get a Trigger that is TRUE when in ANY of the specified states.
+ *
+ * {@code
+ * // True when IDLE or HOLDING (not actively moving)
+ * state.isAnyOf(IntakeState.IDLE, IntakeState.HOLDING)
+ * .whileTrue(allowShootingCommand());
+ * }
+ *
+ * @param states The states to check for (varargs - pass as many as you want)
+ * @return A Trigger that is true when in any of the given states
+ */
+ @SafeVarargs
+ public final Trigger isAnyOf(E... states) {
+ return new Trigger(
+ () -> {
+ for (E state : states) {
+ if (currentState == state) {
+ return true;
}
- return false;
+ }
+ return false;
});
- }
+ }
- /**
- * Get a Trigger that is TRUE when NOT in the specified state.
- *
- * {@code
- * // True when not idle (doing something)
- * state.isNot(IntakeState.IDLE)
- * .whileTrue(runMotorCommand());
- * }
- *
- * @param state The state to check against
- * @return A Trigger that is true when NOT in the given state
- */
- public Trigger isNot(E state) {
- return triggerCache.get(state).negate();
- }
+ /**
+ * Get a Trigger that is TRUE when NOT in the specified state.
+ *
+ * {@code
+ * // True when not idle (doing something)
+ * state.isNot(IntakeState.IDLE)
+ * .whileTrue(runMotorCommand());
+ * }
+ *
+ * @param state The state to check against
+ * @return A Trigger that is true when NOT in the given state
+ */
+ public Trigger isNot(E state) {
+ return triggerCache.get(state).negate();
+ }
- /**
- * Get a Trigger that is TRUE when NOT in any of the specified states.
- *
- * {@code
- * // True when not IDLE and not HOLDING
- * state.isNoneOf(IntakeState.IDLE, IntakeState.HOLDING)
- * .whileTrue(busyIndicatorCommand());
- * }
- *
- * @param states The states to exclude
- * @return A Trigger that is true when NOT in any of the given states
- */
- @SafeVarargs
- public final Trigger isNoneOf(E... states) {
- return isAnyOf(states).negate();
- }
+ /**
+ * Get a Trigger that is TRUE when NOT in any of the specified states.
+ *
+ * {@code
+ * // True when not IDLE and not HOLDING
+ * state.isNoneOf(IntakeState.IDLE, IntakeState.HOLDING)
+ * .whileTrue(busyIndicatorCommand());
+ * }
+ *
+ * @param states The states to exclude
+ * @return A Trigger that is true when NOT in any of the given states
+ */
+ @SafeVarargs
+ public final Trigger isNoneOf(E... states) {
+ return isAnyOf(states).negate();
+ }
- /**
- * Get the previous state (what we were in before the last change).
- *
- * {@code
- * if (state.get() == HOLDING && state.getPrevious() == INTAKING) {
- * // We just finished intaking and now we're holding
- * }
- * }
- *
- * @return The state we were in before the current state
- */
- public E getPrevious() {
- return previousState;
- }
+ /**
+ * Get the previous state (what we were in before the last change).
+ *
+ * {@code
+ * if (state.get() == HOLDING && state.getPrevious() == INTAKING) {
+ * // We just finished intaking and now we're holding
+ * }
+ * }
+ *
+ * @return The state we were in before the current state
+ */
+ public E getPrevious() {
+ return previousState;
+ }
- // ==================== UTILITY METHODS ====================
+ // ==================== UTILITY METHODS ====================
- /**
- * Get all available triggers as a map.
- *
- * {@code
* public class RobotGoalsBehavior extends GoalBehavior {
* private final RobotGoals goals;
@@ -32,30 +33,30 @@
*/
public abstract class GoalBehavior extends Behavior
*/
public class LoggedTunableGainsBuilder {
- private LoggedTunableNumber kP;
- private LoggedTunableNumber kI;
- private LoggedTunableNumber kD;
- private LoggedTunableNumber kS;
- private LoggedTunableNumber kG;
- private LoggedTunableNumber kV;
- private LoggedTunableNumber kA;
+ private LoggedTunableNumber kP;
+ private LoggedTunableNumber kI;
+ private LoggedTunableNumber kD;
+ private LoggedTunableNumber kS;
+ private LoggedTunableNumber kG;
+ private LoggedTunableNumber kV;
+ private LoggedTunableNumber kA;
- private LoggedTunableNumber kMMV;
- private LoggedTunableNumber kMMA;
- private LoggedTunableNumber kMMJ;
- private LoggedTunableNumber kMMEV;
- private LoggedTunableNumber kMMEA;
+ private LoggedTunableNumber kMMV;
+ private LoggedTunableNumber kMMA;
+ private LoggedTunableNumber kMMJ;
+ private LoggedTunableNumber kMMEV;
+ private LoggedTunableNumber kMMEA;
- public LoggedTunableGainsBuilder(
- String key,
- double kP,
- double kI,
- double kD,
- double kS,
- double kG,
- double kV,
- double kA,
- double kMMV,
- double kMMA,
- double kMMJ,
- double kMMEV,
- double kMMEA) {
- this.kP = new LoggedTunableNumber(key + "kP", kP);
- this.kI = new LoggedTunableNumber(key + "kI", kI);
- this.kD = new LoggedTunableNumber(key + "kD", kD);
- this.kS = new LoggedTunableNumber(key + "kS", kS);
- this.kG = new LoggedTunableNumber(key + "kG", kG);
- this.kV = new LoggedTunableNumber(key + "kV", kV);
- this.kA = new LoggedTunableNumber(key + "kA", kA);
- this.kMMV = new LoggedTunableNumber(key + "kMMV", kMMV);
- this.kMMA = new LoggedTunableNumber(key + "kMMA", kMMA);
- this.kMMJ = new LoggedTunableNumber(key + "kMMJ", kMMJ);
- this.kMMEV = new LoggedTunableNumber(key + "kMMEV", kMMEV);
- this.kMMEA = new LoggedTunableNumber(key + "kMMEA", kMMEA);
- }
+ public LoggedTunableGainsBuilder(
+ String key,
+ double kP,
+ double kI,
+ double kD,
+ double kS,
+ double kG,
+ double kV,
+ double kA,
+ double kMMV,
+ double kMMA,
+ double kMMJ,
+ double kMMEV,
+ double kMMEA) {
+ this.kP = new LoggedTunableNumber(key + "kP", kP);
+ this.kI = new LoggedTunableNumber(key + "kI", kI);
+ this.kD = new LoggedTunableNumber(key + "kD", kD);
+ this.kS = new LoggedTunableNumber(key + "kS", kS);
+ this.kG = new LoggedTunableNumber(key + "kG", kG);
+ this.kV = new LoggedTunableNumber(key + "kV", kV);
+ this.kA = new LoggedTunableNumber(key + "kA", kA);
+ this.kMMV = new LoggedTunableNumber(key + "kMMV", kMMV);
+ this.kMMA = new LoggedTunableNumber(key + "kMMA", kMMA);
+ this.kMMJ = new LoggedTunableNumber(key + "kMMJ", kMMJ);
+ this.kMMEV = new LoggedTunableNumber(key + "kMMEV", kMMEV);
+ this.kMMEA = new LoggedTunableNumber(key + "kMMEA", kMMEA);
+ }
- /**
- * Calls the consumer with the current gains if any gain value has changed since last check.
- *
- * @param gainsConsumer Callback to apply the new gains (e.g., update motor configuration)
- */
- public void ifGainsHaveChanged(Consumer{@code
* public class LauncherBehavior extends SubsystemBehavior {
* private final LauncherSubsystem launcher;
@@ -29,35 +31,39 @@
* }
* }
*
- *