Subsystems
Overview
A Subsystem represents physical hardware - motors, sensors, and configuration. Each subsystem should:
- Own and configure its hardware
- Enforce safety limits
- Expose intention-level commands (like
setPosition(), not “set motor voltage”) - Report telemetry for logging and dashboards
- Define a default command for idle behavior
Design Checklist
- Hardware setup and configuration
- Built-in limits (current, soft, neutral mode)
- Telemetry (
positions,currents,state) - No blocking or sleeping threads
- Private raw controls; public “intent” methods
- Clean default command behavior
Example – Arm Subsystem
public class ArmSubsystem extends SubsystemBase {
private final TalonFX motor = new TalonFX(31, "rio");
private final MotionMagicDutyCycle motionMagic = new MotionMagicDutyCycle(0);
private double goalPosition = 0.0;
public ArmSubsystem() {
// Configure limits, PID slots, neutral mode, etc.
setDefaultCommand(hold());
}
public double getPosition() {
return motor.getPosition().getValueAsDouble();
}
public boolean atTarget() {
return Math.abs(getPosition() - goalPosition) < 0.5;
}
/** Hold position when idle */
public Command hold() {
return Commands.run(() ->
motor.setControl(motionMagic.withPosition(goalPosition)), this)
.withName("Arm Hold");
}
/** Move to a new target position */
public Command setPosition(DoubleSupplier pos) {
return Commands.run(() -> {
goalPosition = pos.getAsDouble();
motor.setControl(motionMagic.withPosition(goalPosition));
}, this).withName("Arm SetPosition");
}
/** Percent control (manual mode) */
public Command percent(DoubleSupplier speed) {
return Commands.run(() ->
motor.setControl(new DutyCycleOut(speed.getAsDouble())), this)
.finallyDo(i -> motor.stopMotor())
.withName("Arm Percent");
}
}
Best Practices
- Keep raw motor calls private. Commands should only interact through intent-level methods.
- Each subsystem should define its own commands — don’t mix logic into other subsystems.
- Default commands should reflect idle state (e.g.,
hold(),stop(), orcoast()). - Telemetry helps with debugging: log states, goals, and errors.
- Prefer using Commands.run() and finallyDo() to keep actions declarative and safe.