Joystick mapping
Turn gamepad input into simple, testable motor commands
Gamepad input
A gamepad stick gives a number between -1 and 1. Near the middle it is close to 0. On a typical gamepad, pushing the left stick up makes left_stick_y negative, so code often uses -gamepad1.left_stick_y to make forward positive.

The labels connected gamepads as gamepad1 and gamepad2. Check which driver holds each controller before assigning a .
| Input | Kind of value | Example use |
|---|---|---|
| Stick axis | About -1 to 1 | Drive forward, backward, or turn |
| Trigger | 0 to 1 | Gradually control an |
| Button or D-pad | true or false | Open a claw or select a preset |
Tank drive
Tank drive uses one stick for the left side and one for the right side. Configure the as left_drive and right_drive before running this example. Lift the drive wheels off the ground for the first test.

package org.firstinspires.ftc.teamcode;
import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import com.qualcomm.robotcore.hardware.DcMotor;
@TeleOp(name = "Tank Drive")
public class TankDrive extends LinearOpMode {
@Override
public void runOpMode() {
DcMotor left = hardwareMap.get(DcMotor.class, "left_drive");
DcMotor right = hardwareMap.get(DcMotor.class, "right_drive");
waitForStart();
while (opModeIsActive()) {
double leftPower = -gamepad1.left_stick_y * 0.25;
double rightPower = -gamepad1.right_stick_y * 0.25;
left.setPower(leftPower);
right.setPower(rightPower);
}
left.setPower(0);
right.setPower(0);
}
}package org.firstinspires.ftc.teamcode
import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode
import com.qualcomm.robotcore.eventloop.opmode.TeleOp
import com.qualcomm.robotcore.hardware.DcMotor
@TeleOp(name = "Tank Drive")
class TankDrive : LinearOpMode() {
override fun runOpMode() {
val left = hardwareMap.get(DcMotor::class.java, "left_drive")
val right = hardwareMap.get(DcMotor::class.java, "right_drive")
waitForStart()
while (opModeIsActive()) {
val leftPower = -gamepad1.left_stick_y.toDouble() * 0.25
val rightPower = -gamepad1.right_stick_y.toDouble() * 0.25
left.power = leftPower
right.power = rightPower
}
left.power = 0.0
right.power = 0.0
}
}The 0.25 factor limits speed while you check motor direction. With both sticks forward, both wheels should move the forward. If one wheel turns backward, correct that motor's direction in hardware setup or code before raising the speed. Do not assume that the right motor must always be reversed; mounting varies.
Button input
A button is either pressed or not pressed. Inside the same loop, a simple claw action could look like this after you have mapped and checked a named claw:
if (gamepad1.a) {
claw.setPosition(CLOSED_POSITION);
} else if (gamepad1.b) {
claw.setPosition(OPEN_POSITION);
}CLOSED_POSITION and OPEN_POSITION are values your team must measure for its own claw, between 0.0 and 1.0. This fragment illustrates the button logic; it is not a complete .
Control tuning
- Dead zone: If a motor creeps while a stick is centered, treat a small input such as
abs(value) < 0.05as zero. Measure the drift on your gamepad before choosing the cutoff. - Speed limit: Keep the
0.25multiplier for initial tests, then raise it gradually if the robot is controllable. - Telemetry: Show stick input and motor power during debugging so you can see whether a problem begins at the gamepad or motor.
Four-wheel and X-drive robots need a separate wheel-mixing calculation and careful checks of wheel order and direction. Once tank drive makes sense, check the geometry of your actual . Do not paste a wheel formula for a different layout into your robot.
For an X-roller mecanum drivetrain, continue with Field-centric mecanum drive. It starts with direction checks, then adds an heading so a stick direction stays aligned with the field as the robot turns.
Practice
Push only the left stick, then only the right stick. Predict which wheel will move before each test. When both sticks move together, explain why the robot goes forward or turns.