Class CommandScheduler

Nested Relationships

Nested Types

Class Documentation

class CommandScheduler

Class for handling all the commands you would like to currently run. Interfaces with the Subsystem and Command classes to provide a means of safely scheduling multiple Commands and Subsystems. Checks are provided while scheduling such that multiple commands that require the same subsystem cannot run at the same time. Suppose for example that you have a Command that moves a mechanical arm Subsystem to some position and another Command that moves the same arm to a different position. Obvious issues arise if one attempts to tell the Subsystem to do two things at once. Using this class will disallow these two Commands from being executed at the same time.

For the the above reasons, you cannot map the same command instance to two different input states at the same time. You must declare a separate instance of the command (these can be the same class) for each mapping, or use a ComprisedCommand with your own scheduling logic.

This class contains a map of Subsystems -> Commands. The Subsystems will be refreshed each time the CommandScheduler is ran. If there are commands associated with the Subsystem, the CommandScheduler will execute these commands as well. Additional less important features are explained in more detail in the function definitions.

The goal of this class is for the user to interace directly as little as possible. Aside from calling run each time to update the scheduler, the user should be interacting with the Command, ComprisedCommand, Subsystem, and CommandMapper classes to add and remove commands from the scheduler.

The main use case will be to be refreshing all the main subsystems running on the robot. You should access the main scheduler via the global tap::Drivers * instance, which should have an instance of a CommandScheduler called commandScheduler. The below example code registers a subsystem (sub) and adds a command (cmd) to the scheduler. Then the scheduler is run over and over, in a loop.

// A class that has Subsystem as a base class.
CoolSubsystem sub;
// A class that has Command as a base class that requires
// the subsystem above. In the constructor of the ControlCoolCommand,
// you must call `addSubsystemRequirement(sub)`, where `sub` is the
// `CoolSubsystem` defined above.
ControlCoolCommand cmd(&sub);

drivers->commandScheduler.registerSubsystem(&sub);
drivers->commandScheduler.addCommand(&cmd);

while (1)
{
    // The subsystem will refresh forever and the command will execute until it
    // is finished.
    drivers->commandScheduler.run();
}

The second use case for a CommandScheduler is in the ComprisedCommand class. Here, you utilize the CommandScheduler to coordinate multiple commands inside a single command. The usage is exactly the same as using the main CommandScheduler.

Public Functions

CommandScheduler(Drivers *drivers, bool masterScheduler = false, SafeDisconnectFunction *safeDisconnectFunction = &CommandScheduler::defaultSafeDisconnectFunction)
~CommandScheduler()
void run()

Calls the refresh() function for all Subsystems and the associated execute() function for all Commands. A Subsystem is guarenteed to be refreshed no more than one time each time the mainScheduler’s run function is called. The same goes for a Command. This includes even if multiple CommandSchedulers are running in ComprisedCommands that have shared Subsystems.

If any Subsystem that is in the scheduler does not have a Command controlling it but does have a default command (via the Subsystem’s getDefaultCommand()), the default command is added to the scheduler.

If any Command is finished after execution, the Command is removed from the scheduler. The Command’s end() function is called, passing in isInterrupted = false.

Note

checks the run time of the scheduler. An error is added to the error handler if the time is greater than MAX_ALLOWABLE_SCHEDULER_RUNTIME (in microseconds).

void addCommand(Command *commandToAdd)

Attempts to add a Command to the scheduler. There are a number of ways this function can fail. If failure does occur, an error will be added to the error handler.

These are the following reasons why adding a Command fails:

  • The commandToAdd is nullptr

  • The commandToAdd has no Subsystem requirements.

  • The commandToAdd has Subsystems not in the CommandScheduler.

If a Command is successfully added to the CommandScheduler, any Subsystems that the commandToAdd requires that have Commands running will be ended (and the interrupted flag for that Command set to true).

If a Command is successfully added, the Command’s initialize() function will be called.

Note

If the commandToAdd was already scheduled, it will be interrupted (its end() will be called) and then the command will be rescheduled.

Parameters:

commandToAdd[in] the Command to be added to the scheduler.

void removeCommand(Command *command, bool interrupted)

Removes the given Command completely from the CommandScheduler. This means removing all instances of the command pointer from the Subsystem -> Command map (since a single Subsystem can map to multiple Commands).

Parameters:
  • command[in] the Command to remove. Must not be nullptr. If the Command is not in the scheduler, nothing is removed.

  • interrupted[in] an argument passed in to the Command’s end() function when removing the desired Command.

bool isCommandScheduled(const Command *command) const
Returns:

true if the CommandScheduler contains the requrested Command. false otherwise.

void registerSubsystem(Subsystem *subsystem)

Adds the given Subsystem to the CommandScheduler. The subsystem is added with the currently scheduled Command as nullptr.

Parameters:

subsystem[in] the Subsystem to add. Must be not nullptr and not registered already (check via isSubsystemRegistered()), otherwise an error is added to the error handler.

void setSafeDisconnectFunction(SafeDisconnectFunction *func)

Set the SafeDisconnectFunction to the given function.

Parameters:

func[in] the function that the CommandScheduler will use to determine what constitutes a “disconnected” state.

bool isSubsystemRegistered(const Subsystem *subsystem) const
Parameters:

subsystem[in] the subsystem to check

Returns:

true if the Subsystem is already scheduled, false otherwise.

void runAllHardwareTests()

Runs all hardware tests from subsystems that have a test command.

void runHardwareTest(const Subsystem *subsystem)

Runs the hardware test command, if available, for the specific subsystem.

Parameters:

subsystem[in] the subsystem to run

void stopAllHardwareTests()

Stop all hardware tests from subsystems that have a running test command.

void stopHardwareTest(const Subsystem *subsystem)

Stops the hardware test command, if running, for the specific subsystem.

Parameters:

subsystem[in] the subsystem to stop

int countRunningHardwareTests()
Returns:

the count of subsystems currently running a test.

bool isRunningTest(const Subsystem *subsystem)
Parameters:

subsystem[in] the subsystem to check

Returns:

true if the test command is running, false otherwise.

bool hasPassedTest(const Subsystem *subsystem)
Parameters:

subsystem[in] the subsystem to check

Returns:

true if the test command has passed, false otherwise.

int subsystemListSize() const
Returns:

The number of subsystems registered with the scheduler.

int commandListSize() const
Returns:

The number of commands added in the scheduler.

CommandIterator cmdMapBegin()
CommandIterator cmdMapEnd()
SubsystemIterator subMapBegin()
SubsystemIterator subMapEnd()
inline subsystem_scheduler_bitmap_t getRegisteredSubsystemBitmap() const
inline command_scheduler_bitmap_t getAddedCommandBitmap() const

Public Static Functions

static int constructCommand(Command *command)
static int constructSubsystem(Subsystem *subsystem)
static void destructCommand(Command *command)
static void destructSubsystem(Subsystem *subsystem)
struct CommandIterator

Iterator used for looking through the commands added to the scheduler

Public Types

using iterator_category = std::forward_iterator_tag
using difference_type = std::ptrdiff_t
using value_type = Command
using pointer = Command*
using reference = Command&

Public Functions

CommandIterator(CommandScheduler *scheduler, int i)
pointer operator*()
CommandIterator &operator++()
CommandIterator operator++(int)

Friends

friend bool operator==(const CommandIterator &a, const CommandIterator &b)
friend bool operator!=(const CommandIterator &a, const CommandIterator &b)
struct SubsystemIterator

Iterator used for looking through the subsystems registered in the scheduler

Public Types

using iterator_category = std::forward_iterator_tag
using difference_type = std::ptrdiff_t
using value_type = Subsystem
using pointer = Subsystem*
using reference = Subsystem&

Public Functions

SubsystemIterator(CommandScheduler *scheduler, int i)
pointer operator*()
SubsystemIterator &operator++()
SubsystemIterator operator++(int)

Friends

friend bool operator==(const SubsystemIterator &a, const SubsystemIterator &b)
friend bool operator!=(const SubsystemIterator &a, const SubsystemIterator &b)