Skip to documentation
Documentation / Programming

Commands & subsystems

Register a mechanism once, then bind its actions directly to gamepad buttons.

Register and bind

Inside configure(), register(...) returns the subsystem so creation and registration fit on one line. onPress accepts a Command; onPressDo accepts a one-shot Runnable. whileHeld accepts a Command. Button conditions are lambdas so they are read each loop.

Java · inside configure()
Intake intake = register(new Intake());
whileHeld(() -> gamepad1.a, intake.collect());
onPress(() -> gamepad1.b, intake.collect().withTimeout(2));
onPressDo(() -> gamepad1.x, () -> mark("pickup-confirmed"));

Write subsystem actions

Implement Subsystem and override stop() to make the mechanism safe. run(action) repeats every scheduler loop and automatically calls your stop() on cancellation, timeout or interruption. once(action) runs once; it does not automatically undo the action. Both declare this subsystem as a requirement.

For mechanisms, use subsystem actions rather than a bare onPressDo Runnable so conflicting commands cannot control the same hardware.

Java · methods inside Intake
public Command collect() {
    return run(() -> motor.setPower(1));
}

public Command reverseBriefly() {
    return run(() -> motor.setPower(-1)).withTimeout(0.5);
}

@Override public void stop() { motor.setPower(0); }

Set a default action

A default runs when the subsystem is free and resumes after a conflicting command finishes. The Runnable overload automatically requires and stops the subsystem. For an existing Command, use scheduler.defaultCommand(subsystem, command).

Java · inside configure()
defaultCommand(drive, () -> drive.mecanum(
    -gamepad1.left_stick_y,
    -gamepad1.left_stick_x,
    -gamepad1.right_stick_x));

Chain and time actions

withTimeout(seconds) interrupts the action at the time limit. then(next) runs the next action when the preceding command finishes normally; a timed command finishing its timeout also advances the sequence. Cancelling the entire sequence prevents later actions.

Use schedule(command) in onStarted() to begin immediately at Start. Binding buttons during configure() does not start their actions until pressed. Scheduling an action directly in configure() may run its initialization during Init.

Java · import dev.cubiclib.command.Commands
// Inside onStarted(), with intake stored as an OpMode field:
schedule(intake.collect().withTimeout(2)
    .then(Commands.instant(() -> mark("intake-ended"))));

Advanced API remains available

Existing scheduler, Trigger and Commands code still works. Commands.sequence, parallel, race and deadline compose multiple commands. Parallel groups reject overlapping subsystem requirements. Commands.functional provides custom initialize/execute/finish/end behavior.

whileHeld uses rising-edge scheduling and cancels on release. It does not restart a command that finishes or is interrupted while the button stays down. Do not share a mutable command between an active group and an independent binding. All callbacks and hardware access belong on the OpMode thread.