Interface Command
- All Known Implementing Classes:
ParallelGroup,SequentialGroup
mechanisms. Commands are fundamentally
backed by a Coroutine that can be used to write imperative code that runs asynchronously.
Programmers familiar with the earlier versions of the command framework can think of a v3 command similar to a v1 or v2 command that executes the lifecycle methods in a single method, as demonstrated in the example below. (Note, however, that more sophisticated code than this is possible!
coroutine -> {
initialize();
while (!isFinished()) {
execute();
coroutine.yield(); // be sure to yield at the end of the loop
}
end();
}
Note: Because coroutines are opt-in collaborate constructs, every
command implementation must call Coroutine.yield() within any periodic
loop. Failure to do so may result in an unrecoverable infinite loop.
Requirements
Commands require zero or more mechanisms. To prevent conflicting control requests from running
simultaneously (for example, commanding an elevator to both raise and lower at the same time), a
running command has exclusive ownership of all of its required mechanisms. If another
command with an equal or greater priority() is scheduled that requires one or more of
those same mechanisms, it will interrupt and cancel the running command.
The recommended way to create a command is using Mechanism.run(Consumer) or a related
factory method to create commands that require a single mechanism (for example, a command that
drives an elevator up and down or rotates an arm). Commands may be composed into parallel groups and sequences to build more complex
behavior out of fundamental building blocks. These built-in compositions will require every
mechanism used by every command in them, even if those commands aren't always running, and thus
can leave certain required mechanisms in an uncommanded state: owned, but not used, this
can lead to mechanisms sagging under gravity or running the previous motor control request they
were given.
Advanced Usage
For example, a hypothetical drive-and-score sequence could be coded in two ways: one with a
sequence chain, or one that uses the lower-level coroutine API. Coroutines can be used in an
async/await style that you may be familiar with from languages like JavaScript, Python, or C#
(note that there is no async keyword; commands are inherently asynchronous). Nested
commands may be forked and awaited, but will not outlive the command that forked them; there is
no analog for something like a ScheduleCommand from the v2 commands framework.
class Robot extends TimedRobot {
private final Drivetrain drivetrain = new Drivetrain();
private final Elevator elevator = new Elevator();
private final Gripper gripper = new Gripper();
// Basic sequence builder - owns all 3 mechanisms for the full duration,
// even when they're not being used
private Command basicScoringSequence() {
return drivetrain.driveToScoringLocation()
.andThen(elevator.moveToScoringHeight())
.andThen(gripper.release())
.named("Scoring Sequence (Basic)");
}
// Advanced sequence with async/await - only owns mechanisms while they're
// being used, allowing default commands or other user-triggered commands
// to run when not in use. Interrupting one of the inner commands while it's
// running will cancel the entire sequence.
private Command advancedScoringSequence() {
return Command.noRequirements().executing(coroutine -> {
coroutine.await(drivetrain.driveToScoringLocation());
coroutine.await(elevator.moveToScoringHeight());
coroutine.await(gripper.release());
}).named("Scoring Sequence (Advanced)");
}
}
-
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final intThe default command priority.static final intThe highest possible command priority.static final intThe lowest possible command priority. -
Method Summary
Modifier and TypeMethodDescriptiondefault ParallelGroupBuilderCreates a parallel command group, running this command alongside one or more other commands.default SequentialGroupBuilderCreates a command sequence, starting from this command and then running the next one.default booleanconflictsWith(Command other) Checks if this command conflicts with another command.default booleanisLowerPriorityThan(Command other) Checks if this command has a lowerprioritythan another command.name()The name of the command.static NeedsExecutionBuilderStageCreates a command that does not require any hardware; that is, it does not affect the state of any physical objects.default voidonCancel()An optional lifecycle hook that can be implemented to execute some code whenever this command is canceled before it naturally completes.static ParallelGroupBuilderStarts creating a command that runs a group of multiple commands in parallel.default intpriority()The priority of the command.static ParallelGroupBuilderStarts creating a command that runs a group of multiple commands in parallel.default ParallelGroupBuilderCreates a parallel command group, running this command alongside one or more other commands.The mechanisms required by the command.default booleanChecks if this command requires a particular mechanism.static NeedsExecutionBuilderStagerequiring(Collection<Mechanism> requirements) Creates command that requires some number of mechanisms.static NeedsExecutionBuilderStageCreates a command that requires one or more mechanisms.voidRuns the command.static SequentialGroupBuilderStarts creating a command that runs a group of multiple commands in sequence.default ParallelGroupBuilderuntil(BooleanSupplier endCondition) Creates a command that runs this one and ends when the end condition is met (if this command has not already exited by then).static NeedsNameBuilderStageCreates a command that simply waits for a given duration.static NeedsNameBuilderStagewaitUntil(BooleanSupplier condition) Starts creating a command that simply waits for some condition to be met.default CommandwithTimeout(Time timeout) Creates a new command that runs this one for a maximum duration, after which it is forcibly canceled.
-
Field Details
-
DEFAULT_PRIORITY
The default command priority.- See Also:
-
LOWEST_PRIORITY
The lowest possible command priority. Commands with the lowest priority can be interrupted by any other command, including other minimum-priority commands.- See Also:
-
HIGHEST_PRIORITY
The highest possible command priority. Commands with the highest priority can only be interrupted by other maximum-priority commands.- See Also:
-
-
Method Details
-
run
Runs the command. Commands that need to periodically run until a goal state is reached should simply run a while loop likewhile (!atGoal()) { ... }and callCoroutine.yield()at the end of the loop.Warning: any loops in a command must call
coroutine.yield(). Failure to do so will prevent anything else in your robot code from running. Commands are opt-in collaborative constructs; don't be greedy!- Parameters:
coroutine- the coroutine backing the command's execution
-
onCancel
An optional lifecycle hook that can be implemented to execute some code whenever this command is canceled before it naturally completes. Commands should be careful to do a single-shot cleanup (for example, setting a motor to zero volts) and not do any complex looping logic here. -
name
The name of the command.- Returns:
- the name of the command
-
requirements
The mechanisms required by the command. This is used by the scheduler to determine if two commands conflict with each other. No mechanism may be required by more than one running command at a time.- Returns:
- the set of mechanisms required by the command
-
priority
The priority of the command. If a command is scheduled that conflicts with another running or pending command, their priority values are compared to determine which should run. If the scheduled command is lower priority than the running command, then it will not be scheduled and the running command will continue to run. If it is the same or higher priority, then the running command will be canceled and the scheduled command will start to run.- Returns:
- the priority of the command
-
isLowerPriorityThan
Checks if this command has a lowerprioritythan another command.- Parameters:
other- the command to compare with- Returns:
- true if this command has a lower priority than the other one, false otherwise
-
requires
Checks if this command requires a particular mechanism.- Parameters:
mechanism- the mechanism to check- Returns:
- true if the mechanism is required, false if not
-
conflictsWith
Checks if this command conflicts with another command.- Parameters:
other- the commands to check against- Returns:
- true if both commands require at least one of the same mechanism, false if both commands have completely different requirements
-
withTimeout
Creates a new command that runs this one for a maximum duration, after which it is forcibly canceled. This is particularly useful for autonomous routines where you want to prevent your entire autonomous period spent stuck on a single action because a mechanism doesn't quite reach its setpoint (for example, spinning up a flywheel or driving to a particular location on the field). The resulting command will have the same name as this one, with the timeout period appended.- Parameters:
timeout- the maximum duration that the command is permitted to run. Negative or zero values will result in the command running only once before being canceled.- Returns:
- the timed out command.
-
noRequirements
Creates a command that does not require any hardware; that is, it does not affect the state of any physical objects. This is useful for commands that do some cleanup or state management, such as resetting odometry or sensors, that you don't want to interrupt a command that's controlling the mechanisms it affects.More configuration options are needed after calling this function before the command can be created. See
StagedCommandBuilderfor details.- Returns:
- a builder that can be used to configure the resulting command
-
requiring
Creates a command that requires one or more mechanisms.More configuration options are needed after calling this function before the command can be created. See
StagedCommandBuilderfor details.- Parameters:
requirement- The first required mechanismrest- Any other required mechanisms- Returns:
- A command builder
-
requiring
Creates command that requires some number of mechanisms.More configuration options are needed after calling this function before the command can be created. See
StagedCommandBuilderfor details.- Parameters:
requirements- The required mechanisms. May be empty, but cannot contain null values.- Returns:
- A command builder
-
parallel
Starts creating a command that runs a group of multiple commands in parallel. The command will complete when every command in the group has completed naturally.More configuration options are needed after calling this function before the command can be created. See
ParallelGroupBuilderfor details.- Parameters:
commands- The commands to run in parallel- Returns:
- A command builder
-
race
Starts creating a command that runs a group of multiple commands in parallel. The command will complete when any command in the group has completed naturally; all other commands in the group will be canceled.More configuration options are needed after calling this function before the command can be created. See
ParallelGroupBuilderfor details.- Parameters:
commands- The commands to run in parallel- Returns:
- A command builder
-
sequence
Starts creating a command that runs a group of multiple commands in sequence. The command will complete when the last command in the group has completed naturally. Commands in the group will run in the order they're passed to this method.More configuration options are needed after calling this function before the command can be created. See
SequentialGroupBuilderfor details.- Parameters:
commands- The commands to run in sequence.- Returns:
- A command builder
-
waitUntil
Starts creating a command that simply waits for some condition to be met. The command will not require any mechanisms.More configuration options are needed after calling this function before the command can be created. See
StagedCommandBuilderfor details.- Parameters:
condition- The condition to wait for- Returns:
- A command builder
-
waitFor
Creates a command that simply waits for a given duration. The command will not require any mechanisms.- Parameters:
duration- How long to wait- Returns:
- A command builder
-
until
Creates a command that runs this one and ends when the end condition is met (if this command has not already exited by then).More configuration options are needed after calling this function before the command can be created. See
ParallelGroupBuilderfor details.- Parameters:
endCondition- The end condition to wait for.- Returns:
- The waiting command
-
andThen
Creates a command sequence, starting from this command and then running the next one. More commands can be added with the builder before naming and creating the sequence.Sequence aThenBThenC = commandA() .andThen(commandB()) .andThen(commandC()) .withAutomaticName();- Parameters:
next- The command to run after this one in the sequence- Returns:
- A sequence builder
-
alongWith
Creates a parallel command group, running this command alongside one or more other commands. The group will exit once every command has finished.More configuration options are needed after calling this function before the command can be created. See
ParallelGroupBuilderfor details.ParallelGroup abc = commandA() .alongWith(commandB(), commandC()) .withAutomaticName();- Parameters:
parallel- The commands to run in parallel with this one- Returns:
- A parallel group builder
-
raceWith
Creates a parallel command group, running this command alongside one or more other commands. The group will exit after any command finishes.More configuration options are needed after calling this function before the command can be created. See
ParallelGroupBuilderfor details.- Parameters:
parallel- The commands to run in parallel with this one- Returns:
- A parallel group builder
-