dev only

What Is Command-Based Programming?

The Big Payoff of Everything So Far

Every idea from Ch.17-24 — inheritance, interfaces, the IO-Layer Pattern, static factories, builders — leads here. Command-based programming is WPILib's own official architecture pattern for structuring an entire robot's code. It's not the only way to write a robot program, but it's the one WPILib itself provides deep library support for, and the one most competitive FRC codebases are built around.

Declarative, Not Imperative

Command-based is a declarative paradigm: you describe what should happen under what condition, and the library handles checking that condition every single loop, on your behalf. Compare these two ways of saying "extend the piston when a condition becomes true":

// Declarative (command-based): say what should happen, once
new Trigger(condition::get).onTrue(Commands.runOnce(() -> piston.set(DoubleSolenoid.Value.kForward)));
// Imperative (without command-based): manually track state every single loop
if (condition.get())
{
    if (!pressed)
    {
        piston.set(DoubleSolenoid.Value.kForward);
        pressed = true;
    }
}
else
{
    pressed = false;
}

The declarative version is written once and never touched again; the imperative version requires you to manually manage a pressed flag correctly, forever, in every place a similar check is needed. Multiply that by dozens of buttons and sensors across a real robot, and the difference in maintainability is enormous.

Two Core Abstractions: Subsystems and Commands

Command-based organizes an entire robot around exactly two ideas:

  • A Subsystem represents an independently-controlled piece of hardware (or group of hardware) — a drivetrain, an intake, a climber. Ch.20's IO-Layer Pattern already showed how a subsystem hides its hardware details behind a clean interface; command-based builds directly on that.
  • A Command represents an action the robot can take — something that runs when scheduled, until it's interrupted or its own end condition is met.

Commands declare which subsystem(s) they need (their requirements), and this is what makes resource management automatic: the scheduler guarantees only one command can control a given subsystem at a time, so two different pieces of code can never fight over the same motor's output.

How It All Runs: The Scheduler

The CommandScheduler is the engine underneath all of this — a singleton object that, once per loop (every 20ms), checks all registered triggers for commands that should start, runs the currently-active commands, and ends any that have finished. Lesson 25.3 covers the scheduler's actual run sequence in depth.

Composability

Commands are recursively composable — a complex robot action (like "intake a game piece, then aim the shooter, then fire") can be built out of several small, simple commands combined together, and that composite is itself just another command, usable anywhere a command is expected. Lesson 25.2 covers this in depth.

Common Pitfalls

  • Writing large amounts of imperative logic directly in Robot.java. This works against the entire declarative philosophy command-based is built on — the goal is to describe what happens, and let the scheduler handle when.
  • Forgetting that commands need declared requirements. A command that touches a subsystem without declaring it as a requirement bypasses the resource-management system entirely, risking two commands fighting over the same hardware.
  • Assuming command-based is the only valid way to write robot code. It isn't — but it's the pattern this curriculum focuses on, since it's what WPILib itself is built to support.

Key Takeaways

  • Command-based programming is WPILib's own declarative architecture pattern: describe what should happen under what condition, once, and the library handles checking it every loop.
  • The two core abstractions are Subsystems (hardware, building on Ch.20's IO-Layer Pattern) and Commands (actions), tied together by the CommandScheduler.
  • A command declares its subsystem requirements, which is what lets the scheduler guarantee only one command controls a given subsystem at a time.
  • Commands are recursively composable — small commands combine into larger ones, which are themselves still just commands.

Derived from other-reference-repo: wpilib/command-based/01-what-is-command-based.md (WPILIB 20.1)