Binding Commands to Triggers
Apart from autonomous commands, which are scheduled at the start of the autonomous period, and default commands, which are automatically scheduled whenever their subsystem is not currently in-use, the most common way to run a command is by binding it to a triggering event, such as a button being pressed by a human operator. The command-based paradigm makes this extremely easy to do.
As mentioned earlier, command-based is a declarative paradigm. Accordingly, binding buttons to commands is done declaratively; the association of a button and a command is «declared» once, during robot initialization. The library then does all the hard work of checking the button state and scheduling (or canceling) the command as needed, behind-the-scenes. Users only need to worry about designing their desired UI setup - not about implementing it!
Command binding is done through the Trigger
class (Java, C++) and its various Button
subclasses (Java, C++).
Composing Triggers
The Trigger
class (including its Button
subclasses) can be composed to create composite triggers through the and()
, or()
, and negate()
methods (or, in C++, the &&
, ||
, and !
operators). For example:
// Binds an ExampleCommand to be scheduled when both the 'X' and 'Y' buttons of the driver gamepad are pressed
new JoystickButton(exampleController, XBoxController.Button.kX.value)
.and(new JoystickButton(exampleController, XboxController.Button.kY.value))
.whenActive(new ExampleCommand());
// Binds an ExampleCommand to be scheduled when both the 'X' and 'Y' buttons of the driver gamepad are pressed
(frc2::JoystickButton(&exampleController, frc::XBoxController::Button::kX)
&& JoystickButton(&exampleController, frc::XboxController::Button::kY))
.WhenActive(new ExampleCommand());
Note that these methods return a Trigger
, not a Button
, so the Trigger
binding method names must be used even when buttons are composed.
Debouncing Triggers
To avoid rapid repeated activation, triggers (especially those originating from digital inputs) can be debounced with the WPILib Debouncer class using the debounce method:
// debounces exampleButton with a 0.1s debounce time, rising edges only
exampleButton.debounce(0.1).whenActive(new ExampleCommand());
// debounces exampleButton with a 0.1s debounce time, both rising and falling edges
exampleButton.debounce(0.1, Debouncer.DebounceType.kBoth).whenActive(new ExampleCommand());
// debounces exampleButton with a 100ms debounce time, rising edges only
exampleButton.Debounce(100_ms).WhenActive(new ExampleCommand());
// debounces exampleButton with a 100ms debounce time, both rising and falling edges
exampleButton.Debounce(100_ms, Debouncer::DebounceType::Both).WhenActive(new ExampleCommand());
Creating Your Own Custom Trigger
While binding to HID buttons is by far the most common use case, advanced users may occasionally want to bind commands to arbitrary triggering events. This can be easily done by simply writing your own subclass of Trigger
or Button
:
public class ExampleTrigger extends Trigger {
@Override
public boolean get() {
// This returns whether the trigger is active
}
}
class ExampleTrigger : public frc2::Trigger {
public:
bool get() override {
// This returns whether the trigger is active
}
}
Alternatively, this can also be done inline by passing a lambda to the constructor of trigger
or button
:
// Here it is assumed that "condition" is an object with a method "get" that returns whether the trigger should be active
Trigger exampleTrigger = new Trigger(condition::get);
// Here it is assumed that "condition" is a boolean that determines whether the trigger should be active
frc2::Trigger exampleTrigger([&condition] { return condition; });