Gamepad Tank Drive
You know how to spin a motor at a fixed power. But in a real TeleOp match, the driver needs to control the robot in real time using a gamepad. In this lesson, you will implement tank drive -- one of the most common drivetrain control schemes in FTC.
The Gamepad Object
The FTC SDK gives you access to two gamepad objects: gamepad1 and gamepad2. These are automatically updated with the latest input from the Driver Station controllers.
Here are some of the most commonly used gamepad fields:
| Field | Type | Description |
|---|---|---|
left_stick_x | float | Left stick horizontal (-1.0 left to 1.0 right) |
left_stick_y | float | Left stick vertical (-1.0 up to 1.0 down) |
right_stick_x | float | Right stick horizontal |
right_stick_y | float | Right stick vertical |
a, b, x, y | boolean | Face buttons |
left_trigger, right_trigger | float | Triggers (0.0 to 1.0) |
left_bumper, right_bumper | boolean | Bumpers |
double leftY = gamepad1.left_stick_y;
boolean aButton = gamepad1.a;
What is Tank Drive?
Tank drive is a control scheme where:
- The left joystick controls the left side motors.
- The right joystick controls the right side motors.
It is called "tank drive" because it works exactly like the two-lever controls on a tank or bulldozer.
The Y-Axis Inversion Gotcha
Here is something that trips up almost every new FTC programmer:
On a gamepad, pushing the joystick forward gives a negative Y value.
This is a standard convention in game controllers (inherited from flight simulators where pushing forward means "nose down"), but it is the opposite of what you would expect. If the driver pushes the left stick forward, gamepad1.left_stick_y will be something like -0.8, not +0.8.
Since we want "forward on the stick" to mean "forward on the motor" (positive power), we need to negate the Y value:
double leftPower = -gamepad1.left_stick_y; // Negate to fix direction
double rightPower = -gamepad1.right_stick_y; // Negate to fix direction
This is one of the most common bugs in FTC code. If your robot drives backwards when you push forward, you probably forgot the negation!
Putting It Together
Here is what a complete tank drive looks like:
@TeleOp(name = "Tank Drive")
public class TankDrive extends LinearOpMode {
@Override
public void runOpMode() {
DcMotor leftMotor = hardwareMap.get(DcMotor.class, "leftMotor");
DcMotor rightMotor = hardwareMap.get(DcMotor.class, "rightMotor");
waitForStart();
while (opModeIsActive()) {
double leftPower = -gamepad1.left_stick_y;
double rightPower = -gamepad1.right_stick_y;
leftMotor.setPower(leftPower);
rightMotor.setPower(rightPower);
telemetry.addData("Left Power", leftPower);
telemetry.addData("Right Power", rightPower);
telemetry.update();
}
}
}
Notice the while (opModeIsActive()) loop. In a real TeleOp, you need to continuously read the gamepad and update the motors. The opModeIsActive() method returns true as long as the OpMode has not been stopped.
Your Exercise
For this exercise, you will implement the core of tank drive. The simulated gamepad has:
left_stick_yset to -0.8 (as if the driver is pushing forward)right_stick_yset to -0.6 (as if the driver is pushing forward, but less)
- Read the gamepad stick values and negate them (to fix the Y-axis inversion).
- Set
leftMotorpower to the corrected left stick value. - Set
rightMotorpower to the corrected right stick value.
leftMotor should be at power 0.8 and rightMotor at 0.6.
Give it a try!