Binding Commands to Triggers Lesson

Binding Commands to Triggers

You've learned that `RobotContainer` is where you connect commands to controllers. The modern WPILib framework provides a powerful and flexible way to do this using Triggers, which represent conditions that can start and stop commands.

What is a `Trigger`?

A `Trigger` is a WPILib object that represents a condition that can be either `true` or `false`. While the most common trigger is a button press (`JoystickButton`), it can be any condition, such as a sensor value, a keyboard key, or even a combination of inputs.

Declarative Syntax

The `Trigger` system allows for a clean, "declarative" syntax. Instead of writing `if (buttonIsPressed)` inside a loop, you declare the relationship once: "when this button is pressed, then run this command."

Key Trigger Binding Methods

Inside the `configureButtonBindings()` method of your `RobotContainer`, you'll use these methods to map your commands to controller inputs.

  • `.onTrue(command)`: Schedules a command to run once when the trigger becomes `true`. It's a "fire-and-forget" action, great for moving an arm to a set position.
  • `.whileTrue(command)`: Schedules a command to run continuously as long as the trigger is `true`. The command is automatically canceled when the trigger becomes `false`. This is perfect for a "hold-to-run" action, like spinning an intake motor.
  • `.onFalse(command)`: Schedules a command to run once when the trigger becomes `false` (e.g., when a button is released).
  • `.toggleOnTrue(command)`: Toggles a command on or off with each press. Useful for mechanisms with two states (e.g., on/off, up/down).

A Complete Example

Let's create a binding to run an intake motor while the 'A' button is held down. We'll use a simplified `IntakeSubsystem` and `IntakeCommand` for this example.

1. The Subsystem and Command

// The subsystem provides the basic motor control
public class IntakeSubsystem extends SubsystemBase {
    private final Spark m_motor = new Spark(5);
    public void run() { m_motor.set(0.8); }
    public void stop() { m_motor.set(0.0); }
}

// The command tells the subsystem what to do
public class IntakeCommand extends Command {
    private final IntakeSubsystem m_intake;
    public IntakeCommand(IntakeSubsystem intake) {
        m_intake = intake;
        addRequirements(m_intake);
    }

    @Override public void execute() { m_intake.run(); }
    @Override public boolean isFinished() { return false; } // Runs forever until interrupted
    @Override public void end(boolean interrupted) { m_intake.stop(); }
}
    

2. The `RobotContainer` with Trigger Bindings

This is where we connect the controller to the command.

public class RobotContainer {
    private final IntakeSubsystem m_intake = new IntakeSubsystem();
    private final XboxController m_operatorController = new XboxController(1);

    public RobotContainer() {
        configureButtonBindings();
    }

    private void configureButtonBindings() {
        // Create a trigger for the 'A' button on the operator controller.
        // While that trigger is true (held down), run a new IntakeCommand.
        new JoystickButton(m_operatorController, XboxController.Button.kA.value)
            .whileTrue(new IntakeCommand(m_intake));
    }
}
    

Test Your Knowledge

Question: You want to create a control where holding down the 'B' button on a controller runs the intake motor, and releasing the button stops it. Which `Trigger` binding method is the most appropriate for this?