Skip to content
IncredibotsAcademy
Incredibots playbook

Controlling Subsystems

Learn how to use FTCLib's GamepadEx to bind your commands to controller buttons.

15 minrookie

By the end you can

  • Learn how to use GamepadEx for advanced controller inputs.
  • Bind commands to buttons using whileHeld and whenPressed.
  • Control your mechanisms exactly like the team's repository.

Now that you have a TeleOp with a driving robot, you probably want to use the rest of your controller to actually move your other subsystems (like turning on the intake)!

In standard FTC programming, you have to write messy if/else statements inside a while loop to check if a button is pressed. But because we use FTCLib's Command-Based Architecture, we can use Button Bindings.

Using GamepadEx

In our MainTeleop.java lesson, you might have noticed these two lines:

driverGamepad = new GamepadEx(gamepad1);
operatorGamepad = new GamepadEx(gamepad2);

By wrapping the standard gamepad1 inside an FTCLib GamepadEx object, we unlock the ability to magically link buttons to Commands.

Binding Commands to Buttons

All of our button bindings happen inside our central Robot class (Incredibot.java), specifically inside the initTeleop() method.

Let's look at exactly how our team controls the Intake subsystem. We want the intake to run only while the operator is holding down the 'A' button.

  1. Open your Incredibot.java class.
  2. Scroll down to your initTeleop() method.
  3. Add the following code below your default drive command:
public void initTeleop(GamepadEx driverGamepad, GamepadEx operatorGamepad) {
    CommandScheduler.getInstance().reset();
    
    // Set the default drive command (from the previous lesson)
    driveSubsystem.setDefaultCommand(new DriveRobotCommand(driveSubsystem, driverGamepad));
 
    // =========================================================
    // BUTTON BINDINGS
    // =========================================================
    
    // 1. whileHeld: The command runs as long as the button is held down.
    // When the button is released, the command is cancelled (and stopIntake() is called).
    operatorGamepad.getGamepadButton(GamepadKeys.Button.A)
            .whileHeld(new RunIntakeCommand(intakeSubsystem));
 
}

Other Types of Bindings

Our team's Github repository uses several different types of bindings depending on what the mechanism needs to do. Here are the most common ones you will use:

whenPressed()

The command starts exactly once when the button is pressed, and runs until its isFinished() method returns true. This is perfect for shooting a single ball.

operatorGamepad.getGamepadButton(GamepadKeys.Button.RIGHT_BUMPER)
        .whenPressed(new LaunchBallsCommand(launchSubsystem, launchGateSubsystem));

toggleWhenPressed()

Pressing the button once starts the command. Pressing the button again cancels the command. This is great for toggling a state, like turning a targeting light on and off.

operatorGamepad.getGamepadButton(GamepadKeys.Button.Y)
        .toggleWhenPressed(new TurnLightOnCommand(), new TurnLightOffCommand());

How the Magic Works

You might be wondering: "How does the robot know to stop the motor when I let go of the button?"

When you use .whileHeld(), the Command Scheduler is actively watching that button.

  1. When you press the button, it calls initialize() and then calls execute() over and over.
  2. When you let go of the button, the Scheduler interrupts the command.
  3. This triggers the command's end(boolean interrupted) method.
  4. Because you wisely put intake.stopIntake() inside your command's end() method, the motor stops instantly!

Check Your Understanding

Check yourself

Which button binding is the best choice for a command that shoots exactly one game piece and then stops itself automatically?