Class Coroutine

java.lang.Object
org.wpilib.commands3.Coroutine

public final class Coroutine extends Object
A coroutine object is injected into command's Command.run(Coroutine) method to allow commands to yield and compositions to run other commands. Commands are considered bound to a coroutine while they're scheduled; attempting to use a coroutine outside the command bound to it will result in an IllegalStateException being thrown.
  • Method Details

    • yield

      public boolean yield()
      Yields control back to the scheduler to allow other commands to execute. This can be thought of as "pausing" the currently executing command.
      Returns:
      true
      Throws:
      IllegalStateException - if called anywhere other than the coroutine's running command
    • park

      public void park()
      Parks the current command. No code in a command declared after calling park() will be executed. A parked command will never complete naturally and must be interrupted or canceled.
      Throws:
      IllegalStateException - if called anywhere other than the coroutine's running command
    • fork

      public void fork(Command... commands)
      Schedules a child command and then immediately returns. The child command will run until its natural completion, the parent command exits, or the parent command cancels it.

      This is a nonblocking operation. To fork and then wait for the child command to complete, use await(Command).

      The parent command will continue executing while the child command runs, and can resync with the child command using await(Command).

      
       Command example() {
         return Command.noRequirements().executing(coroutine -> {
           Command child = ...;
           coroutine.fork(child);
           // ... do more things
           // then sync back up with the child command
           coroutine.await(child);
         }).named("Example");
       }
       

      Note: forking a command that conflicts with a higher-priority command will fail. The forked command will not be scheduled, and the existing command will continue to run.

      Parameters:
      commands - The commands to fork.
      Throws:
      IllegalStateException - if called anywhere other than the coroutine's running command
      See Also:
    • fork

      public void fork(Collection<? extends Command> commands)
      Forks off some commands. Each command will run until its natural completion, the parent command exits, or the parent command cancels it. The parent command will continue executing while the forked commands run, and can resync with the forked commands using awaitAll(Collection).
      
       Command example() {
         return Command.noRequirements().executing(coroutine -> {
           Collection<Command> innerCommands = ...;
           coroutine.fork(innerCommands);
           // ... do more things
           // then sync back up with the inner commands
           coroutine.awaitAll(innerCommands);
         }).named("Example");
       }
       

      Note: forking a command that conflicts with a higher-priority command will fail. The forked command will not be scheduled, and the existing command will continue to run.

      Parameters:
      commands - The commands to fork.
      Throws:
      IllegalStateException - if called anywhere other than the coroutine's running command
    • await

      public void await(Command command)
      Awaits completion of a command. If the command is not currently scheduled or running, it will be scheduled automatically. This is a blocking operation and will not return until the command completes or has been interrupted by another command scheduled by the same parent.
      Parameters:
      command - the command to await
      Throws:
      IllegalStateException - if called anywhere other than the coroutine's running command
      See Also:
    • awaitAll

      public void awaitAll(Collection<? extends Command> commands)
      Awaits completion of all given commands. If any command is not current scheduled or running, it will be scheduled.
      Parameters:
      commands - the commands to await
      Throws:
      IllegalArgumentException - if any of the commands conflict with each other
      IllegalStateException - if called anywhere other than the coroutine's running command
    • awaitAll

      public void awaitAll(Command... commands)
      Awaits completion of all given commands. If any command is not current scheduled or running, it will be scheduled.
      Parameters:
      commands - the commands to await
      Throws:
      IllegalArgumentException - if any of the commands conflict with each other
      IllegalStateException - if called anywhere other than the coroutine's running command
    • awaitAny

      public void awaitAny(Collection<? extends Command> commands)
      Awaits completion of any given commands. Any command that's not already scheduled or running will be scheduled. After any of the given commands completes, the rest will be canceled.
      Parameters:
      commands - the commands to await
      Throws:
      IllegalArgumentException - if any of the commands conflict with each other
      IllegalStateException - if called anywhere other than the coroutine's running command
    • awaitAny

      public void awaitAny(Command... commands)
      Awaits completion of any given commands. Any command that's not already scheduled or running will be scheduled. After any of the given commands completes, the rest will be canceled.
      Parameters:
      commands - the commands to await
      Throws:
      IllegalArgumentException - if any of the commands conflict with each other
      IllegalStateException - if called anywhere other than the coroutine's running command
    • wait

      public void wait(Time duration)
      Waits for some duration of time to elapse. Returns immediately if the given duration is zero or negative. Call this within a command or command composition to introduce a simple delay.

      For example, a basic autonomous routine that drives straight for 5 seconds:

      
       Command timedDrive() {
         return drivebase.run(coroutine -> {
           drivebase.tankDrive(1, 1);
           coroutine.wait(Seconds.of(5));
           drivebase.stop();
         }).named("Timed Drive");
       }
       

      Note that the resolution of the wait period is equal to the period at which Scheduler.run() is called by the robot program. If using a 20 millisecond update period, the wait will be rounded up to the nearest 20 millisecond interval; in this scenario, calling wait(Milliseconds.of(1)) and wait(Milliseconds.of(19)) would have identical effects.

      Very small loop times near the loop period are sensitive to the order in which commands are executed. If a command waits for 10 ms at the end of a scheduler cycle, and then all the commands that ran before it complete or exit, and then the next cycle starts immediately, the wait will be evaluated at the start of that next cycle, which occurred less than 10 ms later. Therefore, the wait will see not enough time has passed and only exit after an additional cycle elapses, adding an unexpected extra 20 ms to the wait time. This becomes less of a problem with smaller loop periods, as the extra 1-loop delay becomes smaller.

      Parameters:
      duration - the duration of time to wait
      Throws:
      IllegalStateException - if called anywhere other than the coroutine's running command
    • waitUntil

      public void waitUntil(BooleanSupplier condition)
      Yields until a condition is met.
      Parameters:
      condition - The condition to wait for
      Throws:
      IllegalStateException - if called anywhere other than the coroutine's running command
    • scheduler

      public Scheduler scheduler()
      Advanced users only: this permits access to the backing command scheduler to run custom logic not provided by the standard coroutine methods. Any commands manually scheduled through this will be canceled when the parent command exits - it's not possible to "fork" a command that lives longer than the command that scheduled it.
      Returns:
      the command scheduler backing this coroutine
      Throws:
      IllegalStateException - if called anywhere other than the coroutine's running command