Skip to main content

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(), or coast()).
  • Telemetry helps with debugging: log states, goals, and errors.
  • Prefer using Commands.run() and finallyDo() to keep actions declarative and safe.