Interface Command

All Known Implementing Classes:
ParallelGroup, SequentialGroup

public interface Command
Performs some task using one or more 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 Details

    • DEFAULT_PRIORITY

      static final int DEFAULT_PRIORITY
      The default command priority.
      See Also:
    • LOWEST_PRIORITY

      static final int 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

      static final int 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

      void run(Coroutine coroutine)
      Runs the command. Commands that need to periodically run until a goal state is reached should simply run a while loop like while (!atGoal()) { ... } and call Coroutine.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

      default void 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

      default int 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

      default boolean isLowerPriorityThan(Command other)
      Checks if this command has a lower priority than 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

      default boolean requires(Mechanism mechanism)
      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

      default boolean conflictsWith(Command other)
      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

      default Command withTimeout(Time timeout)
      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 StagedCommandBuilder for details.

      Returns:
      a builder that can be used to configure the resulting command
    • requiring

      static NeedsExecutionBuilderStage requiring(Mechanism requirement, Mechanism... rest)
      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 StagedCommandBuilder for details.

      Parameters:
      requirement - The first required mechanism
      rest - 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 StagedCommandBuilder for details.

      Parameters:
      requirements - The required mechanisms. May be empty, but cannot contain null values.
      Returns:
      A command builder
    • parallel

      static ParallelGroupBuilder parallel(Command... commands)
      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 ParallelGroupBuilder for details.

      Parameters:
      commands - The commands to run in parallel
      Returns:
      A command builder
    • race

      static ParallelGroupBuilder race(Command... commands)
      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 ParallelGroupBuilder for details.

      Parameters:
      commands - The commands to run in parallel
      Returns:
      A command builder
    • sequence

      static SequentialGroupBuilder sequence(Command... commands)
      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 SequentialGroupBuilder for 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 StagedCommandBuilder for details.

      Parameters:
      condition - The condition to wait for
      Returns:
      A command builder
    • waitFor

      static NeedsNameBuilderStage waitFor(Time duration)
      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

      default ParallelGroupBuilder until(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).

      More configuration options are needed after calling this function before the command can be created. See ParallelGroupBuilder for 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

      default ParallelGroupBuilder alongWith(Command... parallel)
      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 ParallelGroupBuilder for 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

      default ParallelGroupBuilder raceWith(Command... parallel)
      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 ParallelGroupBuilder for details.

      Parameters:
      parallel - The commands to run in parallel with this one
      Returns:
      A parallel group builder