The Command Scheduler¶
The CommandScheduler
(Java, C++) is the class responsible for actually running commands. Each iteration (ordinarily once per 20ms), the scheduler polls all registered buttons, schedules commands for execution accordingly, runs the command bodies of all scheduled commands, and ends those commands that have finished or are interrupted.
The CommandScheduler
also runs the periodic()
method of each registered Subsystem
.
Using the Command Scheduler¶
The CommandScheduler
is a singleton, meaning that it is a globally-accessible class with only one instance. Accordingly, in order to access the scheduler, users must call the CommandScheduler.getInstance()
command.
For the most part, users do not have to call scheduler methods directly - almost all important scheduler methods have convenience wrappers elsewhere (e.g. in the Command
and Subsystem
interfaces).
However, there is one exception: users must call CommandScheduler.getInstance().run()
from the robotPeriodic()
method of their Robot
class. If this is not done, the scheduler will never run, and the command framework will not work. The provided command-based project template has this call already included.
The schedule()
Method¶
To schedule a command, users call the schedule()
method (Java, C++. This method takes a command (and, optionally, a specification as to whether that command is interruptible), and attempts to add it to list of currently-running commands, pending whether it is already running or whether its requirements are available. If it is added, its initialize()
method is called.
The Scheduler Run Sequence¶
Note
The initialize()
method of each Command
is called when the command is scheduled, which is not necessarily when the scheduler runs (unless that command is bound to a button).
What does a single iteration of the scheduler’s run()
method (Java, C++) actually do? The following section walks through the logic of a scheduler iteration.
Step 1: Run Subsystem Periodic Methods¶
First, the scheduler runs the periodic()
method of each registered Subsystem
.
Step 2: Poll Command Scheduling Triggers¶
Note
For more information on how trigger bindings work, see Binding Commands to Triggers
Secondly, the scheduler polls the state of all registered triggers to see if any new commands that have been bound to those triggers should be scheduled. If the conditions for scheduling a bound command are met, the command is scheduled and its Initialize()
method is run.
Step 3: Run/Finish Scheduled Commands¶
Thirdly, the scheduler calls the execute()
method of each currently-scheduled command, and then checks whether the command has finished by calling the isFinished()
method. If the command has finished, the end()
method is also called, and the command is de-scheduled and its required subsystems are freed.
Note that this sequence of calls is done in order for each command - thus, one command may have its end()
method called before another has its execute()
method called. Commands are handled in the order they were scheduled.
Step 4: Schedule Default Commands¶
Finally, any registered Subsystem
has its default command scheduled (if it has one). Note that the initialize()
method of the default command will be called at this time.
Disabling the Scheduler¶
The scheduler can be disabled by calling CommandScheduler.getInstance().disable()
. When disabled, the scheduler’s schedule()
and run()
commands will not do anything.
The scheduler may be re-enabled by calling CommandScheduler.getInstance().enable()
.
Command Event Methods¶
Occasionally, it is desirable to have the scheduler execute a custom action whenever a certain command event (initialization, execution, or ending) occurs. This can be done with the following three methods:
onCommandInitialize¶
The onCommandInitialize
method (Java, C++) runs a specified action whenever a command is initialized.
onCommandExecute¶
The onCommandExecute
method (Java, C++) runs a specified action whenever a command is executed.
onCommandFinish¶
The onCommandFinish
method (Java, C++) runs a specified action whenever a command finishes normally (i.e. the isFinished()
method returned true).
onCommandInterrupt¶
The onCommandInterrupt
method (Java, C++) runs a specified action whenever a command is interrupted (i.e. by being explicitly canceled or by another command that shares one of its requirements).
A typical use-case for these methods is adding markers in an event log whenever a command scheduling event takes place, as demonstrated in the SchedulerEventLogging example project (Java, C++):
48 49 50 51 52 53 54 | m_waitCommand.setName("Wait 5 Seconds Command");
// Set the scheduler to log Shuffleboard events for command initialize, interrupt, finish
CommandScheduler.getInstance().onCommandInitialize(command -> Shuffleboard.addEventMarker(
"Command initialized", command.getName(), EventImportance.kNormal));
CommandScheduler.getInstance().onCommandInterrupt(command -> Shuffleboard.addEventMarker(
"Command interrupted", command.getName(), EventImportance.kNormal));
|
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | // Set the scheduler to log Shuffleboard events for command initialize,
// interrupt, finish
frc2::CommandScheduler::GetInstance().OnCommandInitialize(
[](const frc2::Command& command) {
frc::Shuffleboard::AddEventMarker(
"Command Initialized", command.GetName(),
frc::ShuffleboardEventImportance::kNormal);
});
frc2::CommandScheduler::GetInstance().OnCommandInterrupt(
[](const frc2::Command& command) {
frc::Shuffleboard::AddEventMarker(
"Command Interrupted", command.GetName(),
frc::ShuffleboardEventImportance::kNormal);
});
frc2::CommandScheduler::GetInstance().OnCommandFinish(
[](const frc2::Command& command) {
frc::Shuffleboard::AddEventMarker(
"Command Finished", command.GetName(),
frc::ShuffleboardEventImportance::kNormal);
});
|