Your first TeleOp
Two small files: a subsystem that owns hardware and an OpMode that binds buttons.
1. Create Intake.java
Copy this into TeamCode. Match “intake” to your robot configuration. The shared hardware map is ready before configure() runs, so the subsystem does not need a HardwareMap constructor parameter.
run(...) automatically requires this subsystem and calls stop() when the command ends or is interrupted.
package org.firstinspires.ftc.teamcode;
import com.qualcomm.robotcore.hardware.DcMotor;
import dev.cubiclib.command.Command;
import dev.cubiclib.command.Subsystem;
import static dev.cubiclib.ftc.GlobalObjects.hardwareMapEverywhere;
/** Construct inside configure(), after CubicLib makes the hardware map available. */
public final class Intake implements Subsystem {
private final DcMotor motor = hardwareMapEverywhere.get(DcMotor.class, "intake");
public Command collect() { return run(() -> motor.setPower(1)); }
@Override public void stop() { motor.setPower(0); }
}
2. Create SimpleTeleOp.java
Configure odometry in the dashboard, then Init and Start. Hold A to run the intake; release to stop. Press B to run it for two seconds. Press X only when a pickup is confirmed.
A and B commands share the intake requirement, so pressing one interrupts the other. A held binding does not restart after interruption until released and pressed again.
package org.firstinspires.ftc.teamcode;
import com.qualcomm.robotcore.eventloop.opmode.TeleOp;
import dev.cubiclib.ftc.CubicOpMode;
/** Copy with Intake.java into TeamCode; configure localization before Init. */
@TeleOp(name = "CubicLib Simple")
public final class SimpleTeleOp extends CubicOpMode {
@Override protected void configure() {
Intake intake = register(new Intake());
whileHeld(() -> gamepad1.a, intake.collect());
onPress(() -> gamepad1.b, intake.collect().withTimeout(2));
onPressDo(() -> gamepad1.x, () -> mark("pickup-confirmed"));
}
}
Lifecycle hooks
configure() runs during Init. Construct and register subsystems here, never as OpMode field initializers or static singletons. onStarted(), onLoop() and onStopped() are optional. The base class owns the final FTC lifecycle methods.
Each active loop updates localization, runs the scheduler, calls onLoop(), then samples telemetry. Stop cancels commands, stops subsystems, finalizes the log and clears the shared hardware map. Global hardware remains available during stop callbacks.
Complete mecanum example
Download CubicTeleOp.java below for a four-motor drivetrain, a default drive action and event markers. Set the motor names and verify directions with wheels lifted. This example uses the same short syntax.