Gray Matter LogoGray Matter Workshop

Triggers

Triggers - Connecting User Input to Commands

Triggers link user inputs (buttons, joysticks, sensors) to commands. They define when and how commands should run based on controller input or robot state.

đŸŽ¯ Key Concept: Use onTrue() to run commands when buttons are pressed, and onFalse() to run commands when buttons are released.

Trigger Implementation & Examples

đŸŽ¯ Trigger Examples - Binding Input to Commands
RobotContainer.java - configureBindings()JAVA
1package frc.robot;
2
3import edu.wpi.first.wpilibj2.command.button.CommandXboxController;
4import frc.robot.subsystems.Arm;
5
6public class RobotContainer {
7    // Hardware - controllers and subsystems
8    private final CommandXboxController controller = new CommandXboxController(0);
9    private final Arm armSubsystem = new Arm();
10
11    public RobotContainer() {
12        configureBindings();
13    }
14
15    private void configureBindings() {
16        // Left trigger: arm runs fast when pressed, stops when released
17        controller.leftTrigger().onTrue(arm.runFast());
18
19        // Right trigger: flywheel runs fast when pressed, runs slow when released
20        controller.rightTrigger().onTrue(flywheel.runFast()).onFalse(flywheel.runSlow());
21
22        // A button: flywheel runs fast when pressed, stops when released
23        controller.a().onTrue(flywheel.runFast()).onFalse(flywheel.stopCommand());
24    }
25}

🎮 onTrue() Trigger

Run a command once when a button is pressed or condition becomes true. The command completes its full lifecycle (initialize, execute, end).
controller.a()
  .onTrue(command);

đŸ”Ŋ onFalse() Trigger

Run a command once when a button is released or condition becomes false. Perfect for stopping motors or returning to safe positions.
controller.a()
  .onFalse(command);

🔄 Chaining Triggers

Chain onTrue() and onFalse() together to define different actions for press and release, giving you full control over button behavior.
.onTrue(cmd1)
.onFalse(cmd2);

đŸŽ¯ Sensor Triggers

Triggers can be created from any boolean condition - sensors, limit switches, or custom logic - not just controller buttons.
new Trigger(
  () => sensor.get())
  .onTrue(cmd);

🔄 Before → After: Implementation

📋 Before

  • â€ĸ Empty RobotContainer constructor
  • â€ĸ No controller declared
  • â€ĸ No configureBindings() method
  • â€ĸ Commands exist but can't be triggered

✅ After

  • â€ĸ CommandXboxController instantiated
  • â€ĸ configureBindings() method created
  • â€ĸ Button triggers bound to commands
  • â€ĸ Robot responds to controller input

đŸŽ¯ Final Implementation & GitHub Changes

Loading file...

🚀 Advanced Command Patterns

â„šī¸ Advanced Topics - Beyond This Workshop

This workshop uses simplified patterns (runOnce(), onTrue(), and onFalse()) for easier learning. The examples below show advanced command patterns that are powerful for competition but not required for this workshop's scope.

💡 Feel free to explore these after completing the workshop fundamentals!

Extending WPILib Command

For more complex commands, extend Command directly instead of using inline methods.See WPILib documentation →

1public class AimAndShoot extends Command {
2  private final Drivetrain drive;
3  private final Shooter shooter;
4
5  public AimAndShoot(Drivetrain drive, Shooter shooter) {
6    this.drive = drive;
7    this.shooter = shooter;
8    addRequirements(drive, shooter);
9  }
10
11  @Override
12  public void initialize() {
13    shooter.setTargetSpeed(3000);
14  }
15
16  @Override
17  public void execute() {
18    drive.aimAtTarget();
19  }
20
21  @Override
22  public boolean isFinished() {
23    return drive.onTarget() && shooter.atSpeed();
24  }
25
26  @Override
27  public void end(boolean interrupted) {
28    drive.stop();
29    shooter.stop();
30  }
31}

Complex Command Groups

Combine sequences and parallel actions to coordinate subsystems.

1// Run intake and raise arm simultaneously after driving
2new SequentialCommandGroup(
3  new DriveDistance(2.0, drivetrain),
4  new ParallelCommandGroup(
5    new RaiseArm(arm),
6    new RunIntake(intake).withTimeout(2)
7  )
8);

Composition Strategies

Use fluent helpers to assemble commands from smaller pieces.

1Command shootAndDrive =
2  shooter.spinUp()
3    .andThen(intake.feed())
4    .andThen(drivetrain.driveForward(1.0));

Common Pitfalls

Always declare subsystem requirements to avoid unexpected conflicts.

1public class BadCommand extends Command {
2  private final Drivetrain drive;
3  public BadCommand(Drivetrain drive) {
4    this.drive = drive;
5    // Missing: addRequirements(drive);
6  }
7}

Advanced Triggers

Create triggers from sensor conditions or button combinations.

1Trigger armReady = new Trigger(
2  () -> arm.atPosition() && shooter.atSpeed());
3armReady.onTrue(new FireCommand(shooter, arm));

Real-World Scenario

Combine patterns to build robust autonomous routines.

1Command auto =
2  new ParallelDeadlineGroup(
3    new DriveDistance(3, drive),
4    new SequentialCommandGroup(
5      new SpinUpFlywheel(shooter),
6      new FeedShooter(intake, shooter)
7    )
8  );

We use PostHog analytics with user-identifying features disabled to improve our site. Data is aggregated and not used to identify you. You can accept or reject analytics.