Class Coroutine
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.-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionfinal classRepresents the result of a fork operation that attempts to schedule multiple commands concurrently.static enumRepresents the result of a call towaitUntil(BooleanSupplier)orwaitUntil(BooleanSupplier, Time). -
Method Summary
Modifier and TypeMethodDescriptionAwaits completion of a command.awaitAll(Collection<? extends Command> commands) Awaits completion of all given commands.Awaits completion of all given commands.awaitAny(Collection<? extends Command> commands) Awaits completion of any given commands.Awaits completion of any given commands.fork(Collection<? extends Command> commands) Forks off some commands.Schedules child commands and then immediately returns.booleanChecks if the coroutine is currently configured to cancel itself if a child command couldn't be forked.voidpark()Parks the current command.voidRequests early cancellation of the coroutine and the command bound to it.Advanced users only: this permits access to the backing command scheduler to run custom logic not provided by the standard coroutine methods.voidsetCancelOnForkFailure(boolean cancelOnForkFailure) Configures the coroutine to cancel itself if a child command couldn't be forked.voidWaits for some duration of time to elapse.waitUntil(BooleanSupplier condition) Yields until a condition is met.waitUntil(BooleanSupplier condition, Time timeout) Yields until a condition is met, waiting for up to a specified duration.booleanyield()Yields control back to the scheduler to allow other commands to execute.
-
Method Details
-
setCancelOnForkFailure
public void setCancelOnForkFailure(boolean cancelOnForkFailure) Configures the coroutine to cancel itself if a child command couldn't be forked. This setting defaults totrue, but can be changed to allow the coroutine to continue running after a fork failure.This setting only affects commands forked by using the coroutine methods
fork,await,awaitAll, orawaitAny. Commands scheduled directly withScheduler.schedule(Command)or via inner trigger bindings will not be affected.- Parameters:
cancelOnForkFailure- true to make the coroutine cancel itself if a child command couldn't be forked, false to allow the coroutine to continue running after a fork failure- See Also:
-
isCancelOnForkFailure
public boolean isCancelOnForkFailure()Checks if the coroutine is currently configured to cancel itself if a child command couldn't be forked.- Returns:
- true if the coroutine will cancel itself if a child command couldn't be forked, false otherwise
- See Also:
-
requestCancellation
public void requestCancellation()Requests early cancellation of the coroutine and the command bound to it. Any child commands will be canceled as well, as commands can never outlive their parent, but the parent command will not be canceled.Team code shouldn't need to use this; instead, use a
returnstatement in your command's function body to exit early. This method is primarily to be used by internal APIs that don't have access to the command's function body. -
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 callingpark()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
Schedules child commands and then immediately returns. The child commands will run until their natural completion, the parent command exits, or the parent command cancels it.If any child command is unable to be scheduled per the contract of
Scheduler.isSchedulable(Command), then none of the commands will be scheduled and the method call will return aCoroutine.ForkResultcontaining the unschedulable commands. If the coroutine is configured to cancel on fork failure, then the coroutine will be canceled and user code will not get a chance to handle the failure result.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(coroutine -> { Command child = ...; ForkResult childTask = coroutine.fork(child); // ... do more things // then sync back up with the child command if (childTask.successful()) { childTask.awaitCompletion(); } }).named("Example"); }- Parameters:
commands- The commands to fork.- Returns:
- a result indicating whether the fork was successful or if the commands could not be forked
- Throws:
IllegalStateException- if called anywhere other than the coroutine's running command- See Also:
-
fork
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 usingawaitAll(Collection).If any child command is unable to be scheduled per the contract of
Scheduler.isSchedulable(Command), then none of the commands will be scheduled and the method call will return aCoroutine.ForkResultcontaining the unschedulable commands. If the coroutine is configured to cancel on fork failure, then the coroutine will be canceled and user code will not get a chance to handle the failure result.Command example() { return Command.noRequirements(coroutine -> { Collection<Command> innerCommands = ...; ForkResult childTask = coroutine.fork(innerCommands); // ... do more things // then sync back up with the inner commands if (childTask.successful()) { childTask.awaitCompletion(); } }).named("Example"); }- Parameters:
commands- The commands to fork.- Returns:
- a result indicating whether the fork was successful or if the commands could not be forked
- Throws:
IllegalStateException- if called anywhere other than the coroutine's running command- See Also:
-
await
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.If the child command is unable to be scheduled per the contract of
Scheduler.isSchedulable(Command), then it will not be scheduled and the method call will return aCoroutine.ForkResultcontaining the command. If the coroutine is configured to cancel on fork failure, then the coroutine will be canceled and user code will not get a chance to handle the failure result.- Parameters:
command- the command to await- Returns:
- a result indicating whether the await was successful or if the commands could not be awaited
- Throws:
IllegalStateException- if called anywhere other than the coroutine's running command- See Also:
-
awaitAll
Awaits completion of all given commands. If any command is not currently scheduled or running, it will be scheduled.If any child command is unable to be scheduled per the contract of
Scheduler.isSchedulable(Command), then none of the commands will be scheduled and the method call will return aCoroutine.ForkResultcontaining the unschedulable commands. If the coroutine is configured to cancel on fork failure, then the coroutine will be canceled and user code will not get a chance to handle the failure result.- Parameters:
commands- the commands to await- Returns:
- a result indicating whether the await was successful or if the commands could not be awaited
- Throws:
IllegalArgumentException- if any of the commands conflict with each otherIllegalStateException- if called anywhere other than the coroutine's running command- See Also:
-
awaitAll
Awaits completion of all given commands. If any command is not currently scheduled or running, it will be scheduled.If any child command is unable to be scheduled per the contract of
Scheduler.isSchedulable(Command), then none of the commands will be scheduled and the method call will return aCoroutine.ForkResultcontaining the unschedulable commands. If the coroutine is configured to cancel on fork failure, then the coroutine will be canceled and user code will not get a chance to handle the failure result.- Parameters:
commands- the commands to await- Returns:
- a result indicating whether the await was successful or if the commands could not be awaited
- Throws:
IllegalArgumentException- if any of the commands conflict with each otherIllegalStateException- if called anywhere other than the coroutine's running command- See Also:
-
awaitAny
Awaits completion of any given commands. Any command that's not already scheduled or running will be scheduled. After any of the given commands complete, the rest will be canceled.If any child command is unable to be scheduled per the contract of
Scheduler.isSchedulable(Command), then none of the commands will be scheduled and the method call will return aCoroutine.ForkResultcontaining the unschedulable commands. If the coroutine is configured to cancel on fork failure, then the coroutine will be canceled and user code will not get a chance to handle the failure result.- Parameters:
commands- the commands to await- Returns:
- a result indicating whether the await was successful or if the commands could not be awaited
- Throws:
IllegalArgumentException- if any of the commands conflict with each otherIllegalStateException- if called anywhere other than the coroutine's running command- See Also:
-
awaitAny
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.If any child command is unable to be scheduled per the contract of
Scheduler.isSchedulable(Command), then none of the commands will be scheduled and the method call will return aCoroutine.ForkResultcontaining the unschedulable commands. If the coroutine is configured to cancel on fork failure, then the coroutine will be canceled and user code will not get a chance to handle the failure result.- Parameters:
commands- the commands to await- Returns:
- a result indicating whether the await was successful or if the commands could not be awaited
- Throws:
IllegalArgumentException- if any of the commands conflict with each otherIllegalStateException- if called anywhere other than the coroutine's running command- See Also:
-
wait
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, callingwait(Milliseconds.of(1))andwait(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
Yields until a condition is met. This method will only return once the condition is met; if the condition never becomes true or is delayed longer than you expect, this method will block indefinitely.waitUntil(BooleanSupplier, Time)is an alternative that will only wait up until a maximum duration before exiting.- Parameters:
condition- The condition to wait for- Returns:
Coroutine.WaitResult.CONDITION_MET- Throws:
IllegalStateException- if called anywhere other than the coroutine's running command- See Also:
-
waitUntil
Yields until a condition is met, waiting for up to a specified duration. If the condition is not met before the timeout duration elapses, this method stops waiting and returnsCoroutine.WaitResult.TIMED_OUT.Teams may use this method for waiting for conditions in autonomous or automated routines to be resilient to hardware faults (e.g., a mechanism not reaching a target state or a faulty sensor).
Command.noRequirements(coroutine -> { coroutine.fork(elevator.up()); Coroutine.WaitResult upResult = coroutine.waitUntil(elevator::atTop, Seconds.of(1.25)); if (upResult.timedOut()) { // We've waited 1.25 seconds and the elevator still has not reached the top. It may have // jammed or there may be a fault with the sensors. In this example, we set a driverstation // alert and exit early - team code may want to take other approaches like retrying the // command or falling back to a secondary behavior that doesn't need the elevator to be up. elevator.setJamAlert(); return; } // The elevator reached the top within 1.25 seconds. Clear the alert and continue. elevator.clearJamAlert(); // ... more commands ... })- Parameters:
condition- The condition to wait fortimeout- The maximum duration to wait- Returns:
Coroutine.WaitResult.CONDITION_METif the condition was met within the specified timeout, orCoroutine.WaitResult.TIMED_OUTif the timeout duration elapsed before the condition was met.- See Also:
-
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
-