TeleOp Examples
Using VingVing Robot for driver-controlled operation
TeleOp with VingVing Robot
While VingVing Robot excels at autonomous, you can also use its drivetrain and localization features during TeleOp for field-centric driving, position tracking, and driver assists.
Example 1: Basic TeleOp
BasicTeleOp.java
package org.firstinspires.ftc.teamcode;
import com.qualcomm.robotcore.eventloop.opmode.OpMode;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import com.vingvingrobot.Robot;
@TeleOp(name = "Basic TeleOp", group = "VingVing")
public class BasicTeleOp extends OpMode {
Robot robot;
@Override
public void init() {
robot = new Robot(hardwareMap, RobotConfig.class);
robot.initializeLocalizer(hardwareMap);
telemetry.addLine("Robot initialized");
telemetry.addLine("Ready to start!");
}
@Override
public void loop() {
// Update localizer
robot.update();
// Get gamepad inputs
double drive = -gamepad1.left_stick_y; // Forward/backward
double strafe = gamepad1.left_stick_x; // Left/right
double turn = gamepad1.right_stick_x; // Rotation
// Apply power scaling for better control
double powerScale = gamepad1.right_trigger > 0.1 ? 0.4 : 1.0; // Slow mode
// Calculate motor powers (robot-centric)
double[] powers = calculateMecanumPowers(
drive * powerScale,
strafe * powerScale,
turn * powerScale
);
// Set motor powers
robot.setDrivePowers(powers);
// Telemetry
telemetry.addData("Position", "(%.1f, %.1f)",
robot.getLocalizer().getX(),
robot.getLocalizer().getY());
telemetry.addData("Heading", "%.1f°",
Math.toDegrees(robot.getLocalizer().getHeading()));
telemetry.addData("Speed Mode", powerScale == 1.0 ? "Normal" : "Slow");
}
private double[] calculateMecanumPowers(double drive, double strafe, double turn) {
double lf = drive + strafe + turn;
double rf = drive - strafe - turn;
double lb = drive - strafe + turn;
double rb = drive + strafe - turn;
// Normalize powers
double max = Math.max(Math.max(Math.abs(lf), Math.abs(rf)),
Math.max(Math.abs(lb), Math.abs(rb)));
if (max > 1.0) {
lf /= max;
rf /= max;
lb /= max;
rb /= max;
}
return new double[]{lf, rf, lb, rb};
}
}Example 2: Field-Centric TeleOp
FieldCentricTeleOp.java
@TeleOp(name = "Field-Centric TeleOp")
public class FieldCentricTeleOp extends OpMode {
Robot robot;
boolean fieldCentric = true;
@Override
public void init() {
robot = new Robot(hardwareMap, RobotConfig.class);
robot.initializeLocalizer(hardwareMap);
}
@Override
public void loop() {
robot.update();
// Toggle field-centric mode
if (gamepad1.a) {
fieldCentric = !fieldCentric;
sleep(200); // Debounce
}
// Get joystick inputs
double drive = -gamepad1.left_stick_y;
double strafe = gamepad1.left_stick_x;
double turn = gamepad1.right_stick_x;
double[] powers;
if (fieldCentric) {
// Field-centric: joystick directions relative to field
double heading = robot.getLocalizer().getHeading();
// Rotate drive vector by robot heading
double rotDrive = drive * Math.cos(-heading) - strafe * Math.sin(-heading);
double rotStrafe = drive * Math.sin(-heading) + strafe * Math.cos(-heading);
powers = calculateMecanumPowers(rotDrive, rotStrafe, turn);
} else {
// Robot-centric: joystick directions relative to robot
powers = calculateMecanumPowers(drive, strafe, turn);
}
robot.setDrivePowers(powers);
// Telemetry
telemetry.addData("Drive Mode", fieldCentric ? "Field-Centric" : "Robot-Centric");
telemetry.addData("Position", "(%.1f, %.1f)",
robot.getLocalizer().getX(),
robot.getLocalizer().getY());
telemetry.addData("Heading", "%.1f°",
Math.toDegrees(robot.getLocalizer().getHeading()));
telemetry.addLine();
telemetry.addLine("Press A to toggle drive mode");
}
private double[] calculateMecanumPowers(double drive, double strafe, double turn) {
double lf = drive + strafe + turn;
double rf = drive - strafe - turn;
double lb = drive - strafe + turn;
double rb = drive + strafe - turn;
double max = Math.max(Math.max(Math.abs(lf), Math.abs(rf)),
Math.max(Math.abs(lb), Math.abs(rb)));
if (max > 1.0) {
lf /= max; rf /= max; lb /= max; rb /= max;
}
return new double[]{lf, rf, lb, rb};
}
}Example 3: TeleOp with Driver Assists
AssistedTeleOp.java
@TeleOp(name = "Assisted TeleOp")
public class AssistedTeleOp extends OpMode {
Robot robot;
Follower follower;
// Preset positions (field coordinates)
private static final Point SCORING_POSITION = new Point(6, 52, Math.toRadians(90), Point.FIELD);
private static final Point LOADING_POSITION = new Point(48, 12, Math.toRadians(180), Point.FIELD);
private boolean autoMode = false;
@Override
public void init() {
robot = new Robot(hardwareMap, RobotConfig.class);
robot.initializeLocalizer(hardwareMap);
follower = new Follower(hardwareMap);
}
@Override
public void loop() {
robot.update();
// Driver Assist: Auto-navigate to preset positions
if (gamepad1.y && !autoMode) {
// Go to scoring position
navigateToPosition(SCORING_POSITION);
autoMode = true;
} else if (gamepad1.b && !autoMode) {
// Go to loading position
navigateToPosition(LOADING_POSITION);
autoMode = true;
} else if (gamepad1.x) {
// Cancel auto navigation
autoMode = false;
}
if (autoMode) {
// Auto-navigate mode
follower.update();
robot.setDrivePowers(follower.getMotorPowers());
if (follower.isPathComplete()) {
autoMode = false; // Return to manual control
}
telemetry.addLine("🤖 AUTO-NAVIGATION");
telemetry.addData("Progress", "%.0f%%", follower.getPathProgress() * 100);
} else {
// Manual control
double drive = -gamepad1.left_stick_y;
double strafe = gamepad1.left_stick_x;
double turn = gamepad1.right_stick_x;
double[] powers = calculateMecanumPowers(drive, strafe, turn);
robot.setDrivePowers(powers);
telemetry.addLine("👤 MANUAL CONTROL");
}
// Position telemetry
telemetry.addData("Position", "(%.1f, %.1f)",
robot.getLocalizer().getX(),
robot.getLocalizer().getY());
telemetry.addLine();
telemetry.addLine("Y: Auto to Scoring | B: Auto to Loading");
telemetry.addLine("X: Cancel Auto");
}
private void navigateToPosition(Point target) {
// Get current position
double currentX = robot.getLocalizer().getX();
double currentY = robot.getLocalizer().getY();
double currentHeading = robot.getLocalizer().getHeading();
// Create path from current to target
follower.followPath(
new BezierLine(
new Point(currentX, currentY, currentHeading, Point.FIELD),
target
).setLinearHeadingInterpolation()
);
}
private double[] calculateMecanumPowers(double drive, double strafe, double turn) {
double lf = drive + strafe + turn;
double rf = drive - strafe - turn;
double lb = drive - strafe + turn;
double rb = drive + strafe - turn;
double max = Math.max(Math.max(Math.abs(lf), Math.abs(rf)),
Math.max(Math.abs(lb), Math.abs(rb)));
if (max > 1.0) {
lf /= max; rf /= max; lb /= max; rb /= max;
}
return new double[]{lf, rf, lb, rb};
}
}TeleOp Tips
💡 Field-Centric is Powerful
Field-centric drive makes controlling the robot much easier - pushing forward always moves toward the opponent's side, regardless of robot rotation.
💡 Use Position Tracking
Even in TeleOp, knowing your position helps drivers. Display coordinates on telemetry or use for automated positioning assists.
💡 Driver Assists Win Matches
Auto-navigation to scoring positions saves time and reduces driver error. Let drivers focus on strategy, not precise positioning.