Why Command-Based? Subsystems and the Scheduler
Adopt the modern command-based framework. Learn what subsystems are and how the command scheduler manages resources.
Sign in to track progress, earn XP, and save lessons.
The two core ideas
The command-based framework organizes code around two abstractions:
- Subsystems — a collection of hardware that works as a unit (a drivetrain, an arm, an intake). The subsystem owns its motors and sensors and exposes clean public methods like
setSpeed()orgetAngle(). The rest of the code can't touch the motors directly — only through the subsystem. - Commands — actions the robot performs (drive forward, raise the arm, run the intake). Commands use subsystems to do their work.
This separation keeps your code organized: hardware details stay inside subsystems, and behavior lives in commands.
Creating a subsystem
The recommended way is to subclass SubsystemBase (Java/C++):
public class Intake extends SubsystemBase {
private final PWMSparkMax m_motor = new PWMSparkMax(5);
public void run() { m_motor.set(0.8); }
public void stop() { m_motor.set(0.0); }
@Override
public void periodic() {
// Called automatically every 20 ms by the scheduler
}
}
A subsystem's periodic() is run automatically by the scheduler — perfect for logging sensor values or running closed-loop updates.
The CommandScheduler
The CommandScheduler is a singleton that runs the whole system. You start it by calling CommandScheduler.getInstance().run() once per loop — and the Command Robot template does this for you in robotPeriodic(). Each loop, the scheduler:
- Runs each subsystem's
periodic(). - Polls triggers/button bindings.
- Runs the currently scheduled commands.
- Handles commands that have finished or been interrupted.
Requirements: the resource-management rule
The single most important rule: each command declares which subsystems it requires. The scheduler guarantees that no two commands require the same subsystem at the same time. If a new command needs a subsystem already in use, the old command is interrupted (by default). This prevents two pieces of code from fighting over the same motor — a classic source of bugs.
Default commands
A subsystem can have a default command that runs whenever no other command requires it. The classic example: the drivetrain's default command reads the joysticks and drives the robot, so the robot is always drivable unless something else (like an auto-aim command) takes over.
drivetrain.setDefaultCommand(
drivetrain.run(() -> drivetrain.arcadeDrive(driver.getLeftY(), driver.getRightX())));
Why this scales
With subsystems + the scheduler + requirements, complex robots stay manageable: each mechanism is isolated, conflicts are impossible by design, and behavior is composed from small, reusable commands. This is why command-based is the recommended structure for nearly all teams.
Key takeaways
- Subsystems encapsulate hardware; commands encapsulate behavior.
- Subclass SubsystemBase to create a subsystem; its periodic() runs automatically.
- The CommandScheduler runs everything; the Command Robot template calls it in robotPeriodic().
- Each command declares required subsystems, so two commands can never fight over one subsystem.
- Default commands run when nothing else needs the subsystem — e.g., joystick driving.
Lesson quiz
RequiredAnswer all 3 questions correctly to complete this lesson.
1.In command-based programming, what does a subsystem represent?
2.How does the CommandScheduler prevent two commands from fighting over the same hardware?
3.What is a major advantage of the command-based framework over writing everything directly in teleopPeriodic?
Answer every question to submit.