Skip to content
Video course · Lesson 1 70 min

Your First TeleOp from Scratch

Configure your drive motors on the Control Hub, then write, upload and run a Driver-Controlled OpMode that drives a mecanum robot with the gamepad sticks.

VIDEO COMING SOON

Our team is preparing this lesson. Written materials and practical exercises are available below.

In this lesson you will

  • Create a robot configuration with clear, matching motor names
  • Write a LinearOpMode with @TeleOp that loads four motors from hardwareMap
  • Set motor directions so positive power always means forward
  • Convert gamepad stick values into normalised mecanum wheel powers
  • Upload, run and debug the OpMode using telemetry

Lesson

In this lesson you will build a complete Driver-Controlled (TeleOp) program step by step. By the end, one driver with one gamepad will be able to drive your robot forward, sideways and in turns. The code is written for a four-motor mecanum drivetrain, and a short tank drive alternative is included if your robot has normal wheels.

Step 1: Name your motors in the robot configuration

Your code never talks to a motor port directly. Instead, the Control Hub stores a robot configuration: a list that says which device is plugged into which port and what its name is. Your code asks for a device by that name. If the names do not match exactly, the program stops with an error, so set this up carefully first.

  1. 1
    Open the configuration screen
    Power on the robot and connect the Driver Station. Open the menu (three dots) and choose Configure Robot, then New (or Edit an existing configuration).
  2. 2
    Add the four drive motors
    Open the Control Hub, then Motors. For ports 0 to 3, pick the motor type that matches your hardware and type the names front_left, front_right, back_left and back_right. Names are exact: front_left and Front_Left are different, so use lowercase with underscores and write down which port each motor is plugged into.
  3. 3
    Check the IMU
    On a Control Hub the built-in IMU usually already appears on I2C bus 0 with the name imu. Leave it there; you will use it in the next lesson.
  4. 4
    Save and activate
    Press Done until you are asked to save, give the configuration a name such as training_bot, and make sure it is the active configuration shown on the main screen.

Step 2: Understand the OpMode lifecycle

An OpMode is one program the drivers can pick on the Driver Station. A LinearOpMode runs from top to bottom: the code before waitForStart() runs when the driver presses INIT, the code after it runs when they press START, and a while (opModeIsActive()) loop keeps repeating until STOP is pressed or the match ends.

InithardwareMap.get(...)waitForStart()Loopwhile (opModeIsActive())① read inputs② set outputs③ telemetryStop
INIT sets up hardware, waitForStart() pauses, the loop repeats until STOP.

Step 3: Write the TeleOp

Create a new Java file called FirstTeleOp in the teamcode folder. In OnBot Java, connect your laptop to the Control Hub's Wi-Fi, open the OnBot Java page in a browser and add the file inside org.firstinspires.ftc.teamcode. In Android Studio, add it to the TeamCode module in the same package. Then type in this complete program.

JAVA
1package org.firstinspires.ftc.teamcode;
2
3import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;
4import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
5import com.qualcomm.robotcore.hardware.DcMotor;
6
7@TeleOp(name = "First TeleOp", group = "Training")
8public class FirstTeleOp extends LinearOpMode {
9    @Override
10    public void runOpMode() {
11        // INIT: names must match the robot configuration exactly
12        DcMotor frontLeft = hardwareMap.get(DcMotor.class, "front_left");
13        DcMotor backLeft = hardwareMap.get(DcMotor.class, "back_left");
14        DcMotor frontRight = hardwareMap.get(DcMotor.class, "front_right");
15        DcMotor backRight = hardwareMap.get(DcMotor.class, "back_right");
16
17        // Motors on one side are mirrored, so reverse that side
18        frontLeft.setDirection(DcMotor.Direction.REVERSE);
19        backLeft.setDirection(DcMotor.Direction.REVERSE);
20
21        telemetry.addData("Status", "Ready - press START");
22        telemetry.update();
23        waitForStart();
24
25        while (opModeIsActive()) {
26            double y = -gamepad1.left_stick_y; // pushing forward gives a negative value
27            double x = gamepad1.left_stick_x;  // strafe left/right
28            double rx = gamepad1.right_stick_x; // turn
29
30            // Keep every power between -1 and 1 without changing the ratios
31            double max = Math.max(Math.abs(y) + Math.abs(x) + Math.abs(rx), 1.0);
32            double fl = (y + x + rx) / max;
33            double bl = (y - x + rx) / max;
34            double fr = (y - x - rx) / max;
35            double br = (y + x - rx) / max;
36
37            frontLeft.setPower(fl);
38            backLeft.setPower(bl);
39            frontRight.setPower(fr);
40            backRight.setPower(br);
41
42            telemetry.addData("Sticks", "y %.2f  x %.2f  rx %.2f", y, x, rx);
43            telemetry.addData("Front L/R", "%.2f / %.2f", fl, fr);
44            telemetry.addData("Back  L/R", "%.2f / %.2f", bl, br);
45            telemetry.update();
46        }
47    }
48}
A complete mecanum TeleOp. Left stick drives and strafes, right stick turns.
  • The @TeleOp(name = ...) annotation puts the OpMode in the TeleOp list on the Driver Station. Without it, the OpMode never appears.
  • The call hardwareMap.get(DcMotor.class, "front_left") looks up the motor by its configuration name.
  • Motor directions: motors on the left and right are mounted facing opposite ways, so the same power would spin them in opposite directions. Reversing one side means positive power drives every wheel forward. Which side to reverse depends on your motors and gearing, so you will test it.
  • Forward is negative: on FTC gamepads, pushing a stick up gives a negative left_stick_y. The minus sign in -gamepad1.left_stick_y turns forward into a positive number.
  • Normalisation: adding forward, strafe and turn can give values like 1.8, but setPower() only accepts -1 to 1. Dividing all four by the largest possible sum keeps them in range and keeps the wheel speeds in the right proportion, so the robot still moves in the direction you asked.
  • Telemetry: telemetry.addData() queues a line and telemetry.update() sends it to the Driver Station screen. Use it to see what your code is thinking.
Left stick → Drive / strafeLeft trigger → IntakeD-pad → Lift presetsRight stick → TurnA / B → ClawRight trigger → Intake
Left stick: forward/back and strafe. Right stick X: turn.
FLFRBLBRDrive forwardFLFRBLBRStrafe rightFLFRBLBRTurn right
Each mecanum roller pushes at an angle. Combining the four wheel directions gives forward, strafe or turn.
JAVA
1// Each stick controls one side of the robot
2double left = -gamepad1.left_stick_y;
3double right = -gamepad1.right_stick_y;
4
5frontLeft.setPower(left);
6backLeft.setPower(left);
7frontRight.setPower(right);
8backRight.setPower(right);
9
10telemetry.addData("Left / Right", "%.2f / %.2f", left, right);
11telemetry.update();
Tank drive alternative: replace the loop body if your robot has normal wheels.

Step 4: Upload, run and fix common errors

In OnBot Java, press Build Everything and wait for a successful build. In Android Studio, press Run with the Control Hub connected. On the Driver Station, assign the gamepad to user 1 by holding Start and pressing A. Choose First TeleOp from the TeleOp list, press INIT, then START. Test with the wheels off the ground first, then on the floor at low speed.

ProblemLikely causeFix
Error: unable to find a hardware device named ...Name in code and configuration differ, or the wrong configuration is activeCompare names letter by letter and activate the correct configuration
OpMode is not in the listMissing @TeleOp, a @Disabled annotation, or the build failedAdd the annotation, remove @Disabled, rebuild and read the build errors
Robot drives backward or spins when you push forwardWrong side reversed or one motor wired to the wrong portSpin each wheel alone with telemetry and fix the directions or port names
Nothing moves but telemetry shows powerGamepad not assigned, flat battery or loose motor cablePress Start + A, charge the battery and check every connector
Strafing curves or drifts diagonallyWheels mounted in the wrong pattern or uneven weightCheck wheel orientation against your kit instructions and Game Manual 0

Key terms

Robot configuration
A saved list on the Control Hub that gives each port's device a name your code can look up.
hardwareMap
The object your OpMode uses to get a motor, servo or sensor by its configuration name.
LinearOpMode
An OpMode that runs its code from top to bottom, pausing at waitForStart() until the driver presses START.
Normalisation
Scaling a set of motor powers so the largest is at most 1 while keeping their ratios the same.
Telemetry
Text your program sends to the Driver Station screen to show values while the robot runs.

Practical exercise

Build and tune your first TeleOp

  1. 1Create and activate a robot configuration with front_left, front_right, back_left and back_right.
  2. 2Type in FirstTeleOp, build it and run it with the wheels off the ground.
  3. 3Push the left stick forward and check that all four wheels spin forward; fix motor directions if not.
  4. 4Put the robot on the floor and drive a square: forward, strafe right, backward, strafe left.
  5. 5Add a slow mode: when gamepad1.left_bumper is held, multiply all four powers by 0.4.
Deliverable: A TeleOp OpMode that drives correctly in all directions, includes a slow mode, and shows stick values and motor powers in telemetry.

Knowledge check

Answer every question, then check your answers.

  1. Q1Your code says hardwareMap.get(DcMotor.class, "front_left") but the configuration uses frontLeft. What happens?
  2. Q2Why does the code use -gamepad1.left_stick_y for forward?
  3. Q3What is the purpose of dividing every wheel power by max?
  4. Q4The robot spins in place when you push the left stick forward. What should you check first?

Further resources

Mark lesson complete