Controlling Subsystems
Learn how to use FTCLib's GamepadEx to bind your commands to controller buttons.
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.
- Open your
Incredibot.javaclass. - Scroll down to your
initTeleop()method. - 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.
- When you press the button, it calls
initialize()and then callsexecute()over and over. - When you let go of the button, the Scheduler interrupts the command.
- This triggers the command's
end(boolean interrupted)method. - Because you wisely put
intake.stopIntake()inside your command'send()method, the motor stops instantly!
Check Your Understanding
Check yourself