Commands¶
A command is a unit of robot behavior: drive forward, run the intake, follow a path, wait for a sensor. Commands are scheduled by the CommandScheduler and may control one or more Subsystems for some period of time.
All commands implement the Command interface from com.vcs.valleylib.core.command.
The lifecycle¶
Every command goes through the same four phases:
scheduled ──▶ initialize() ──▶ execute() ──▶ isFinished()? ── no ──▶ execute() ...
│ │
│ yes ──▶ end(false)
│
canceled / preempted ──▶ end(true)
| Method | Called | Purpose |
|---|---|---|
initialize() |
Once, when the command is scheduled | Reset timers, sensors, and internal state |
execute() |
Every scheduler cycle while active | Actuator control logic (must be fast and non-blocking) |
isFinished() |
After each execute() |
Return true when the command has completed (defaults to false — runs forever until interrupted) |
end(boolean interrupted) |
Once, when the command ends | Stop motors safely; interrupted is true when canceled or preempted |
getRequirements() |
On scheduling | Declare exclusive subsystem access (defaults to none) |
Only execute() is abstract — everything else has a sensible default, so the simplest possible command is:
Requirements: preventing hardware conflicts¶
getRequirements() returns the set of subsystems a command needs exclusive access to. When a new command is scheduled that requires a subsystem already in use, the running command is interrupted (its end(true) is called) and the new one takes over.
Warning
Forgetting requirements is the most common command-based bug: two commands silently fight over the same motors. Declare every subsystem your command touches.
Built-in commands¶
InstantCommand¶
Runs a single action once, then immediately finishes. Ideal for toggles, state changes, and one-shot hardware calls.
WaitCommand¶
Does nothing for a fixed duration (seconds). The backbone of timed autonomous sequences. Like every timed behavior in the library it reads RobotClock, so it is deterministic under a manual clock in tests.
WaitUntilCommand¶
Finishes once a condition becomes true.
TimedCommand (valleyLib-ftc)¶
An abstract command that runs for a fixed duration with structured callbacks — preferred over raw timer bookkeeping in autos:
public class SpinUpCommand extends TimedCommand {
public SpinUpCommand() { super(1.5); } // run for 1.5 s
@Override protected void onStart() { shooter.enable(); }
@Override protected void onLoop(double elapsedSeconds) {
shooter.setPower(Math.min(1.0, elapsedSeconds)); // ramp up
}
@Override protected void onEnd(boolean interrupted) { shooter.hold(); }
}
FunctionalCommand¶
A command assembled from lambdas for each lifecycle phase, with any number of requirements. It is the primitive behind the Commands and subsystem factories, and the right tool when a command needs a little logic in several phases and touches more than one subsystem — but is still too small for its own class:
Command handoff = new FunctionalCommand(
() -> { intake.slow(); transfer.open(); }, // initialize
() -> {}, // execute
interrupted -> { intake.stop(); transfer.close(); }, // end
transfer::hasGamePiece, // isFinished
intake, transfer) // requirements
.withName("Handoff");
Command names¶
Every command has a getName() used by the command logger and useful in your own telemetry. Defaults are sensible — a class's simple name, Wait(0.5s), Intake.startEnd, StateMachine[SCORE] — and anonymous classes fall back to "Command". Name anything important explicitly:
Decorators report the wrapped command's name, so score.withTimeout(3) still logs as Score. FunctionalCommand.withName(...) sets the name in place (no wrapper); on any other command it returns a lightweight NamedCommand wrapper.
BaseCommand: a managed template¶
BaseCommand is an abstract convenience base that manages lifecycle state for you. Instead of overriding the interface methods directly, you override protected hooks:
| Hook | Replaces |
|---|---|
onInitialize() |
initialize() |
onExecute() |
execute() |
onIsFinished() |
isFinished() |
onEnd(boolean interrupted) |
end(...) |
In exchange you get extra state queries:
justFinished()—trueexactly once after the command ends (self-clearing), handy for chained state machines.wasInterrupted()— whether the last run ended by interruption.
BaseCommand also guards against execute() running after the command has finished.
CommandWrapper: decorating existing commands¶
CommandWrapper extends BaseCommand and delegates the whole lifecycle to an inner command. It is the base used to build custom decorators — subclass it and override just the behavior you want to change:
public class LoggedCommand extends CommandWrapper {
public LoggedCommand(Command inner) { super(inner); }
@Override
protected void onInitialize() {
System.out.println("starting " + inner.getClass().getSimpleName());
super.onInitialize();
}
}
The wrapper automatically forwards getRequirements() from the inner command.
Composing commands¶
You rarely subclass anything for day-to-day robot code. Most behavior is assembled from small pieces using:
- Decorators —
withTimeout,until,andThen,alongWith, ... - Command groups & factories —
Commands.sequence(...),Commands.parallel(...), ... - The AutoDsl — a declarative builder for autonomous routines.
For writing your own commands from scratch, see the Custom Commands guide.