RLD 7: Command Based - TEAM1771/Crash-Course GitHub Wiki

What is Command Based Robot Code?

From wpilib's website, "'Command-based' programming is one possible design pattern for robot software. It is not the only way to write a robot program, but it is a very effective one. Command-based robot code tends to be clean, extensible, and (with some tricks) easy to re-use from year to year."

In other words, Command Based is another way to write robot code (as opposed to Time Based). It excels at handling more complex robot actions, preventing code from trying to control the same system at the same time, and also provides very elegant solutions for state management.

Command Based is best illustrated with an example

Take a look at this Timed Based code

static bool pressed = false;

if(controller.ButtonPressed()) {
  if(!pressed) {
    piston.Set(frc::DoubleSolenoid::kForward);
    pressed = true;
  }
} else {
  pressed = false;
}

This code activates a piston when the controller's button is pressed, taking care to only send a new signal when the button is pressed again.

Now, let's look at how Command Based would handle this.

controller.Button().OnTrue(frc2::cmd::RunOnce([&piston] { piston.Set(frc::DoubleSolenoid::kForward)));

Essentially, Command Based allows programmers to specify a "condition" and the action that should be run when the condition becomes true. This is more generally called declarative programming, "a style of software which focuses on describing what a program should do, rather than how it gets done."

Core Concepts

For a more detailed explanation, please read through the wpilib docs, but I'll provide a brief overview of the main concepts here.

Subsystems

Subsystems represent individually-controlled groups of robot hardware (think sensors, motor controllers, pneumatics, etc.) which operate together. Logic and code specific only to runnings of a specific system can then be abstracted, or hidden from the rest of the code to reduce code complexity. Additionally, subsystems can only process one command at a time. This prevents a situation where two conflicting commands try to control the same physical hardware.

An example of a subsystem would be an intake, including a few motor controllers (that raise/lower the intake and run its rollers) and a beam-break sensor that detects game pieces.

For more on subsystems (including some WPILIB examples), check this out.

Commands

As mentioned, Commands represent actions the robot can take. Commands can require subsystems, and two commands requiring the same system cannot be run concurrently. Commands are powerful in that they can be chained, stacked, etc together to create complex compositions controlling entire robots. As an example, for our 2024 robot, Toothless, the command aimPivotSpinupAndShoot would aim the pivot, spinup the shooter wheels, and request that the intake feed the note into the shooter once the pivot and shooter hit tolerance.

Commands are only run when they are scheduled, either manually or by a triggering condition (i.e. a button press or a state change). We'll talk more about triggers in a moment.

The Command Scheduler checks for commands to run and executes their actions, all while ensuring no commands are using the same system.

For more on commands, please check out wpilib's command and command composition articles.

image