Drivetrain Java
En esta guía crearás un drivetrain mecanum (holonómico) usando Java y el SDK oficial de FTC, ya sea desde OnBot Java o Android Studio: el código es idéntico en ambos.
El objetivo es aprender:
- Qué es un OpMode y cómo funciona
LinearOpMode - Qué es un drivetrain mecanum y por qué es tan común en FTC
- Cómo configurar motores con
hardwareMap - Cómo leer el gamepad
- Cómo combinar ejes de movimiento para mover el robot en cualquier dirección
- Cómo compilar y correr el OpMode
- Cómo probarlo desde Driver Station
¿Qué es un OpMode?
Section titled “¿Qué es un OpMode?”Un OpMode es una clase que corre en el Control Hub y controla el robot durante un período: TeleOp (control manual) o Autonomous (rutina automática).
LinearOpMode es el tipo de OpMode más común para empezar: se ejecuta de forma lineal, de arriba hacia abajo, con un bucle principal controlado por opModeIsActive().
¿Qué es un Drivetrain Mecanum?
Section titled “¿Qué es un Drivetrain Mecanum?”Un drivetrain mecanum usa 4 ruedas con rodillos montados en ángulo, formando una X vista desde arriba. Esto le permite al robot moverse en cualquier dirección (adelante, atrás, lateral) sin girar las ruedas ni cambiar su orientación.
Es uno de los drivetrains más usados en FTC, mucho más que en FRC.
Antes de comenzar
Section titled “Antes de comenzar”Asegúrate de tener:
- OnBot Java accesible o Android Studio con el proyecto FtcRobotController abierto
- Driver Station instalada y conectada al Control Hub
- Control Hub configurado
- Gamepad conectado
- 4 motores mecanum cableados y conectados al Control Hub o Expansion Hub
¿Qué vamos a construir?
Section titled “¿Qué vamos a construir?”Crearemos un OpMode con:
- 4 motores DcMotor
- Lectura del gamepad 1
- Cálculo de potencia por motor combinando 3 ejes de movimiento
- Normalización de potencias
- Control desde TeleOp
Motores├── front_left_drive├── back_left_drive├── front_right_drive└── back_right_driveNombrar los motores en la configuración del Robot Controller
Section titled “Nombrar los motores en la configuración del Robot Controller”Antes de escribir código, los motores deben existir en el archivo de configuración del Robot Controller, con nombres exactos.
- Toca los tres puntos verticales en la esquina superior derecha de la app Driver Station para abrir el menú.
- Selecciona Configure Robot para abrir la pantalla Configuration.
- Toca la palabra Motors para abrir la pantalla Motor Configuration.
- Repite esto para los 4 motores: usa el selector desplegable de cada puerto para elegir el tipo de motor, y usa el teclado en pantalla para escribir su nombre — usaremos
front_left_drive,back_left_drive,front_right_drive,back_right_drive. - Presiona Done para completar la configuración de cada motor.
Importando clases necesarias
Section titled “Importando clases necesarias”import com.qualcomm.robotcore.eventloop.opmode.LinearOpMode;import com.qualcomm.robotcore.eventloop.opmode.TeleOp;import com.qualcomm.robotcore.hardware.DcMotor;Declarando la clase del OpMode
Section titled “Declarando la clase del OpMode”@TeleOp(name="Mecanum Drive", group="TeleOp")public class MecanumDrive extends LinearOpMode {
private DcMotor frontLeftDrive = null; private DcMotor backLeftDrive = null; private DcMotor frontRightDrive = null; private DcMotor backRightDrive = null;
@Override public void runOpMode() {
}}name es el texto que verás en el dropdown de Driver Station. group te permite organizar varios OpModes relacionados.
Obteniendo los motores desde hardwareMap
Section titled “Obteniendo los motores desde hardwareMap”Dentro de runOpMode():
frontLeftDrive = hardwareMap.get(DcMotor.class, "front_left_drive");backLeftDrive = hardwareMap.get(DcMotor.class, "back_left_drive");frontRightDrive = hardwareMap.get(DcMotor.class, "front_right_drive");backRightDrive = hardwareMap.get(DcMotor.class, "back_right_drive");Invirtiendo motores
Section titled “Invirtiendo motores”frontLeftDrive.setDirection(DcMotor.Direction.REVERSE);backLeftDrive.setDirection(DcMotor.Direction.REVERSE);frontRightDrive.setDirection(DcMotor.Direction.FORWARD);backRightDrive.setDirection(DcMotor.Direction.FORWARD);Inicialización y espera de Start
Section titled “Inicialización y espera de Start”telemetry.addData("Status", "Initialized");telemetry.update();
waitForStart();El bucle principal
Section titled “El bucle principal”while (opModeIsActive()) {
}Este bucle se repite continuamente mientras el OpMode está corriendo, hasta que el driver presiona STOP.
Leyendo el gamepad
Section titled “Leyendo el gamepad”Dentro del bucle:
double axial = -gamepad1.left_stick_y;double lateral = gamepad1.left_stick_x;double yaw = gamepad1.right_stick_x;axial: avance/retroceso. Se invierte porque el stick entrega valores negativos hacia arriba.lateral: movimiento lateral (strafe), propio de un drivetrain mecanum.yaw: rotación del robot.
Calculando la potencia de cada motor
Section titled “Calculando la potencia de cada motor”double frontLeftPower = axial + lateral + yaw;double frontRightPower = axial - lateral - yaw;double backLeftPower = axial - lateral + yaw;double backRightPower = axial + lateral - yaw;Normalizando las potencias
Section titled “Normalizando las potencias”double max = Math.max(Math.abs(frontLeftPower), Math.abs(frontRightPower));max = Math.max(max, Math.abs(backLeftPower));max = Math.max(max, Math.abs(backRightPower));
if (max > 1.0) { frontLeftPower /= max; frontRightPower /= max; backLeftPower /= max; backRightPower /= max;}Enviando la potencia a los motores
Section titled “Enviando la potencia a los motores”frontLeftDrive.setPower(frontLeftPower);frontRightDrive.setPower(frontRightPower);backLeftDrive.setPower(backLeftPower);backRightDrive.setPower(backRightPower);Código completo del OpMode
Section titled “Código completo del OpMode”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="Mecanum Drive", group="TeleOp")public class MecanumDrive extends LinearOpMode {
private DcMotor frontLeftDrive = null; private DcMotor backLeftDrive = null; private DcMotor frontRightDrive = null; private DcMotor backRightDrive = null;
@Override public void runOpMode() {
// Get motors from hardware configuration frontLeftDrive = hardwareMap.get(DcMotor.class, "front_left_drive"); backLeftDrive = hardwareMap.get(DcMotor.class, "back_left_drive"); frontRightDrive = hardwareMap.get(DcMotor.class, "front_right_drive"); backRightDrive = hardwareMap.get(DcMotor.class, "back_right_drive");
// Invert left side frontLeftDrive.setDirection(DcMotor.Direction.REVERSE); backLeftDrive.setDirection(DcMotor.Direction.REVERSE); frontRightDrive.setDirection(DcMotor.Direction.FORWARD); backRightDrive.setDirection(DcMotor.Direction.FORWARD);
telemetry.addData("Status", "Initialized"); telemetry.update();
waitForStart();
while (opModeIsActive()) {
double axial = -gamepad1.left_stick_y; double lateral = gamepad1.left_stick_x; double yaw = gamepad1.right_stick_x;
double frontLeftPower = axial + lateral + yaw; double frontRightPower = axial - lateral - yaw; double backLeftPower = axial - lateral + yaw; double backRightPower = axial + lateral - yaw;
double max = Math.max(Math.abs(frontLeftPower), Math.abs(frontRightPower)); max = Math.max(max, Math.abs(backLeftPower)); max = Math.max(max, Math.abs(backRightPower));
if (max > 1.0) { frontLeftPower /= max; frontRightPower /= max; backLeftPower /= max; backRightPower /= max; }
frontLeftDrive.setPower(frontLeftPower); frontRightDrive.setPower(frontRightPower); backLeftDrive.setPower(backLeftPower); backRightDrive.setPower(backRightPower);
telemetry.addData("Front left/Right", "%4.2f, %4.2f", frontLeftPower, frontRightPower); telemetry.addData("Back left/Right", "%4.2f, %4.2f", backLeftPower, backRightPower); telemetry.update(); } }}Métodos y conceptos importantes
Section titled “Métodos y conceptos importantes”Método obligatorio de todo LinearOpMode. Contiene toda la lógica del OpMode: inicialización,
espera de Start y el bucle principal. Se ejecuta una sola vez cuando el driver selecciona y
corre el OpMode.
Pausa la ejecución hasta que el driver presiona START en Driver Station. Todo lo que va antes de esta línea corre durante INIT.
Controla el bucle principal. Devuelve true mientras el OpMode sigue corriendo, y se vuelve
false en cuanto el driver presiona STOP.
Conecta tu código con el hardware físico configurado en Configure Robot. Es el equivalente en FTC a declarar un CAN ID o una línea PWM en otros sistemas de control.
Compilar y correr el código
Section titled “Compilar y correr el código”- Guarda el archivo.
- Si usas OnBot Java: presiona Build. Si usas Android Studio: presiona Run (▶).
- Abre Driver Station.
- Selecciona
Mecanum Driveen el dropdown de TeleOp. - Presiona
INITy luegoSTART.
Verificar comunicación
Section titled “Verificar comunicación”Abre Driver Station y verifica:
- El Robot Controller aparece conectado
- El OpMode
Mecanum Driveaparece en el dropdown - No hay errores rojos al presionar INIT
Problemas comunes
Section titled “Problemas comunes”- Revisa errores de sintaxis señalados en rojo
- Confirma que los nombres de los motores coincidan con Configure Robot
- Reinicia OnBot Java o Android Studio
- El nombre en
hardwareMap.get()no coincide con Configure Robot - El motor no está guardado en la configuración activa
- Revisa mayúsculas y guiones bajos exactos
- Revisa la inversión de motores
- Confirma que los 4 motores estén bien identificados (front/back, left/right)
- Verifica que las ruedas mecanum estén orientadas correctamente (rodillos formando una X)
- OpMode no está en STARTED (revisa que hayas presionado START, no solo INIT)
- Gamepad no detectado
- Driver Station sin comunicación con el Robot Controller
Siguientes pasos
Section titled “Siguientes pasos”Ahora puedes continuar con:
- Corriendo el programa
- Drivetrain Blocks, si quieres comparar ambas rutas
- Autónomo básico
- Sensores (IMU, encoders)
- Visión (AprilTags, TensorFlow)
FIRSTHub es un proyecto comunitario independiente. No está afiliado, patrocinado ni respaldado por FIRST. Las traducciones no sustituyen a la documentación oficial: ante cualquier diferencia, manda el documento original.