2020-12-26 14:12:05 -08:00
|
|
|
// Copyright (c) FIRST and other WPILib contributors.
|
|
|
|
|
// Open Source Software; you can modify and/or share it under the terms of
|
|
|
|
|
// the WPILib BSD license file in the root directory of this project.
|
2019-08-25 23:55:59 -04:00
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
2019-11-05 20:52:49 -08:00
|
|
|
#include <initializer_list>
|
|
|
|
|
#include <memory>
|
2022-10-15 16:33:14 -07:00
|
|
|
#include <span>
|
2019-11-05 20:52:49 -08:00
|
|
|
#include <utility>
|
|
|
|
|
|
2021-04-18 20:35:29 -07:00
|
|
|
#include <frc/Errors.h>
|
2020-03-28 12:29:51 -04:00
|
|
|
#include <frc/Watchdog.h>
|
2022-06-09 08:16:51 +03:00
|
|
|
#include <frc/event/EventLoop.h>
|
2021-06-13 16:38:05 -07:00
|
|
|
#include <networktables/NTSendable.h>
|
2020-06-29 22:25:09 -07:00
|
|
|
#include <units/time.h>
|
2019-08-25 23:55:59 -04:00
|
|
|
#include <wpi/FunctionExtras.h>
|
2022-06-09 08:16:51 +03:00
|
|
|
#include <wpi/deprecated.h>
|
2021-06-13 16:38:05 -07:00
|
|
|
#include <wpi/sendable/SendableHelper.h>
|
2019-08-25 23:55:59 -04:00
|
|
|
|
|
|
|
|
namespace frc2 {
|
|
|
|
|
class Command;
|
2022-10-06 01:19:28 +03:00
|
|
|
class CommandPtr;
|
2019-08-25 23:55:59 -04:00
|
|
|
class Subsystem;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The scheduler responsible for running Commands. A Command-based robot should
|
|
|
|
|
* call Run() on the singleton instance in its periodic block in order to run
|
|
|
|
|
* commands synchronously from the main loop. Subsystems should be registered
|
|
|
|
|
* with the scheduler using RegisterSubsystem() in order for their Periodic()
|
|
|
|
|
* methods to be called and for their default commands to be scheduled.
|
2022-01-08 11:11:34 -08:00
|
|
|
*
|
|
|
|
|
* This class is provided by the NewCommands VendorDep
|
2019-08-25 23:55:59 -04:00
|
|
|
*/
|
2021-06-13 16:38:05 -07:00
|
|
|
class CommandScheduler final : public nt::NTSendable,
|
|
|
|
|
public wpi::SendableHelper<CommandScheduler> {
|
2019-08-25 23:55:59 -04:00
|
|
|
public:
|
|
|
|
|
/**
|
|
|
|
|
* Returns the Scheduler instance.
|
|
|
|
|
*
|
|
|
|
|
* @return the instance
|
|
|
|
|
*/
|
|
|
|
|
static CommandScheduler& GetInstance();
|
|
|
|
|
|
2020-12-28 00:10:13 -08:00
|
|
|
~CommandScheduler() override;
|
2019-11-05 20:52:49 -08:00
|
|
|
CommandScheduler(const CommandScheduler&) = delete;
|
|
|
|
|
CommandScheduler& operator=(const CommandScheduler&) = delete;
|
|
|
|
|
|
2019-08-25 23:55:59 -04:00
|
|
|
using Action = std::function<void(const Command&)>;
|
|
|
|
|
|
2020-03-28 12:29:51 -04:00
|
|
|
/**
|
|
|
|
|
* Changes the period of the loop overrun watchdog. This should be kept in
|
|
|
|
|
* sync with the TimedRobot period.
|
|
|
|
|
*/
|
|
|
|
|
void SetPeriod(units::second_t period);
|
|
|
|
|
|
2019-08-25 23:55:59 -04:00
|
|
|
/**
|
2022-06-09 08:16:51 +03:00
|
|
|
* Get the active button poll.
|
2019-08-25 23:55:59 -04:00
|
|
|
*
|
2022-06-09 08:16:51 +03:00
|
|
|
* @return a reference to the current {@link frc::EventLoop} object polling
|
|
|
|
|
* buttons.
|
2019-08-25 23:55:59 -04:00
|
|
|
*/
|
2022-06-09 08:16:51 +03:00
|
|
|
frc::EventLoop* GetActiveButtonLoop() const;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Replace the button poll with another one.
|
|
|
|
|
*
|
|
|
|
|
* @param loop the new button polling loop object.
|
|
|
|
|
*/
|
|
|
|
|
void SetActiveButtonLoop(frc::EventLoop* loop);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the default button poll.
|
|
|
|
|
*
|
|
|
|
|
* @return a reference to the default {@link frc::EventLoop} object polling
|
|
|
|
|
* buttons.
|
|
|
|
|
*/
|
|
|
|
|
frc::EventLoop* GetDefaultButtonLoop() const;
|
2019-08-25 23:55:59 -04:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Removes all button bindings from the scheduler.
|
|
|
|
|
*/
|
2022-06-09 08:16:51 +03:00
|
|
|
WPI_DEPRECATED("Call Clear on the EventLoop instance directly!")
|
2019-08-25 23:55:59 -04:00
|
|
|
void ClearButtons();
|
|
|
|
|
|
2022-10-06 01:19:28 +03:00
|
|
|
/**
|
|
|
|
|
* Schedules a command for execution. Does nothing if the command is already
|
|
|
|
|
* scheduled. If a command's requirements are not available, it will only be
|
|
|
|
|
* started if all the commands currently using those requirements are
|
|
|
|
|
* interruptible. If this is the case, they will be interrupted and the
|
|
|
|
|
* command will be scheduled.
|
|
|
|
|
*
|
|
|
|
|
* @param command the command to schedule
|
|
|
|
|
*/
|
|
|
|
|
void Schedule(const CommandPtr& command);
|
|
|
|
|
|
2019-08-25 23:55:59 -04:00
|
|
|
/**
|
2022-08-30 07:53:47 +03:00
|
|
|
* Schedules a command for execution. Does nothing if the command is already
|
2019-08-25 23:55:59 -04:00
|
|
|
* scheduled. If a command's requirements are not available, it will only be
|
|
|
|
|
* started if all the commands currently using those requirements have been
|
2022-08-30 07:53:47 +03:00
|
|
|
* scheduled as interruptible. If this is the case, they will be interrupted
|
2019-08-25 23:55:59 -04:00
|
|
|
* and the command will be scheduled.
|
|
|
|
|
*
|
|
|
|
|
* @param command the command to schedule
|
|
|
|
|
*/
|
|
|
|
|
void Schedule(Command* command);
|
|
|
|
|
|
|
|
|
|
/**
|
2022-08-30 07:53:47 +03:00
|
|
|
* Schedules multiple commands for execution. Does nothing for commands
|
|
|
|
|
* already scheduled.
|
2019-08-25 23:55:59 -04:00
|
|
|
*
|
|
|
|
|
* @param commands the commands to schedule
|
|
|
|
|
*/
|
2022-10-15 16:33:14 -07:00
|
|
|
void Schedule(std::span<Command* const> commands);
|
2019-08-25 23:55:59 -04:00
|
|
|
|
|
|
|
|
/**
|
2022-08-30 07:53:47 +03:00
|
|
|
* Schedules multiple commands for execution. Does nothing for commands
|
|
|
|
|
* already scheduled.
|
2019-08-25 23:55:59 -04:00
|
|
|
*
|
|
|
|
|
* @param commands the commands to schedule
|
|
|
|
|
*/
|
|
|
|
|
void Schedule(std::initializer_list<Command*> commands);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Runs a single iteration of the scheduler. The execution occurs in the
|
|
|
|
|
* following order:
|
|
|
|
|
*
|
|
|
|
|
* <p>Subsystem periodic methods are called.
|
|
|
|
|
*
|
|
|
|
|
* <p>Button bindings are polled, and new commands are scheduled from them.
|
|
|
|
|
*
|
|
|
|
|
* <p>Currently-scheduled commands are executed.
|
|
|
|
|
*
|
|
|
|
|
* <p>End conditions are checked on currently-scheduled commands, and commands
|
|
|
|
|
* that are finished have their end methods called and are removed.
|
|
|
|
|
*
|
|
|
|
|
* <p>Any subsystems not being used as requirements have their default methods
|
|
|
|
|
* started.
|
|
|
|
|
*/
|
|
|
|
|
void Run();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Registers subsystems with the scheduler. This must be called for the
|
|
|
|
|
* subsystem's periodic block to run when the scheduler is run, and for the
|
|
|
|
|
* subsystem's default command to be scheduled. It is recommended to call
|
|
|
|
|
* this from the constructor of your subsystem implementations.
|
|
|
|
|
*
|
|
|
|
|
* @param subsystem the subsystem to register
|
|
|
|
|
*/
|
|
|
|
|
void RegisterSubsystem(Subsystem* subsystem);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Un-registers subsystems with the scheduler. The subsystem will no longer
|
|
|
|
|
* have its periodic block called, and will not have its default command
|
|
|
|
|
* scheduled.
|
|
|
|
|
*
|
|
|
|
|
* @param subsystem the subsystem to un-register
|
|
|
|
|
*/
|
|
|
|
|
void UnregisterSubsystem(Subsystem* subsystem);
|
|
|
|
|
|
|
|
|
|
void RegisterSubsystem(std::initializer_list<Subsystem*> subsystems);
|
2022-10-15 16:33:14 -07:00
|
|
|
void RegisterSubsystem(std::span<Subsystem* const> subsystems);
|
2019-08-25 23:55:59 -04:00
|
|
|
|
|
|
|
|
void UnregisterSubsystem(std::initializer_list<Subsystem*> subsystems);
|
2022-10-15 16:33:14 -07:00
|
|
|
void UnregisterSubsystem(std::span<Subsystem* const> subsystems);
|
2019-08-25 23:55:59 -04:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sets the default command for a subsystem. Registers that subsystem if it
|
|
|
|
|
* is not already registered. Default commands will run whenever there is no
|
|
|
|
|
* other command currently scheduled that requires the subsystem. Default
|
|
|
|
|
* commands should be written to never end (i.e. their IsFinished() method
|
|
|
|
|
* should return false), as they would simply be re-scheduled if they do.
|
|
|
|
|
* Default commands must also require their subsystem.
|
|
|
|
|
*
|
|
|
|
|
* @param subsystem the subsystem whose default command will be set
|
|
|
|
|
* @param defaultCommand the default command to associate with the subsystem
|
|
|
|
|
*/
|
2019-09-13 20:14:37 -07:00
|
|
|
template <class T, typename = std::enable_if_t<std::is_base_of_v<
|
|
|
|
|
Command, std::remove_reference_t<T>>>>
|
2019-08-25 23:55:59 -04:00
|
|
|
void SetDefaultCommand(Subsystem* subsystem, T&& defaultCommand) {
|
|
|
|
|
if (!defaultCommand.HasRequirement(subsystem)) {
|
2022-10-19 10:49:27 -07:00
|
|
|
throw FRC_MakeError(frc::err::CommandIllegalUse,
|
2021-04-18 20:35:29 -07:00
|
|
|
"Default commands must require their subsystem!");
|
2019-08-25 23:55:59 -04:00
|
|
|
}
|
2019-11-05 20:52:49 -08:00
|
|
|
SetDefaultCommandImpl(subsystem,
|
|
|
|
|
std::make_unique<std::remove_reference_t<T>>(
|
|
|
|
|
std::forward<T>(defaultCommand)));
|
2019-08-25 23:55:59 -04:00
|
|
|
}
|
|
|
|
|
|
2022-10-21 16:35:58 +03:00
|
|
|
/**
|
|
|
|
|
* Sets the default command for a subsystem. Registers that subsystem if it
|
|
|
|
|
* is not already registered. Default commands will run whenever there is no
|
|
|
|
|
* other command currently scheduled that requires the subsystem. Default
|
|
|
|
|
* commands should be written to never end (i.e. their IsFinished() method
|
|
|
|
|
* should return false), as they would simply be re-scheduled if they do.
|
|
|
|
|
* Default commands must also require their subsystem.
|
|
|
|
|
*
|
|
|
|
|
* @param subsystem the subsystem whose default command will be set
|
|
|
|
|
* @param defaultCommand the default command to associate with the subsystem
|
|
|
|
|
*/
|
|
|
|
|
void SetDefaultCommand(Subsystem* subsystem, CommandPtr&& defaultCommand);
|
|
|
|
|
|
2019-08-25 23:55:59 -04:00
|
|
|
/**
|
|
|
|
|
* Gets the default command associated with this subsystem. Null if this
|
|
|
|
|
* subsystem has no default command associated with it.
|
|
|
|
|
*
|
|
|
|
|
* @param subsystem the subsystem to inquire about
|
|
|
|
|
* @return the default command associated with the subsystem
|
|
|
|
|
*/
|
|
|
|
|
Command* GetDefaultCommand(const Subsystem* subsystem) const;
|
|
|
|
|
|
|
|
|
|
/**
|
2020-05-21 07:00:34 +03:00
|
|
|
* Cancels commands. The scheduler will only call Command::End()
|
|
|
|
|
* method of the canceled command with true, indicating they were
|
|
|
|
|
* canceled (as opposed to finishing normally).
|
2019-08-25 23:55:59 -04:00
|
|
|
*
|
2020-05-21 07:00:34 +03:00
|
|
|
* <p>Commands will be canceled even if they are not scheduled as
|
|
|
|
|
* interruptible.
|
|
|
|
|
*
|
2021-10-14 18:09:38 -07:00
|
|
|
* @param command the command to cancel
|
2019-08-25 23:55:59 -04:00
|
|
|
*/
|
|
|
|
|
void Cancel(Command* command);
|
|
|
|
|
|
2022-10-06 01:19:28 +03:00
|
|
|
/**
|
|
|
|
|
* Cancels commands. The scheduler will only call Command::End()
|
|
|
|
|
* method of the canceled command with true, indicating they were
|
|
|
|
|
* canceled (as opposed to finishing normally).
|
|
|
|
|
*
|
|
|
|
|
* <p>Commands will be canceled even if they are not scheduled as
|
|
|
|
|
* interruptible.
|
|
|
|
|
*
|
|
|
|
|
* @param command the command to cancel
|
|
|
|
|
*/
|
|
|
|
|
void Cancel(const CommandPtr& command);
|
|
|
|
|
|
2019-08-25 23:55:59 -04:00
|
|
|
/**
|
2020-05-21 07:00:34 +03:00
|
|
|
* Cancels commands. The scheduler will only call Command::End()
|
|
|
|
|
* method of the canceled command with true, indicating they were
|
|
|
|
|
* canceled (as opposed to finishing normally).
|
|
|
|
|
*
|
|
|
|
|
* <p>Commands will be canceled even if they are not scheduled as
|
|
|
|
|
* interruptible.
|
2019-08-25 23:55:59 -04:00
|
|
|
*
|
|
|
|
|
* @param commands the commands to cancel
|
|
|
|
|
*/
|
2022-10-15 16:33:14 -07:00
|
|
|
void Cancel(std::span<Command* const> commands);
|
2019-08-25 23:55:59 -04:00
|
|
|
|
|
|
|
|
/**
|
2020-05-21 07:00:34 +03:00
|
|
|
* Cancels commands. The scheduler will only call Command::End()
|
|
|
|
|
* method of the canceled command with true, indicating they were
|
|
|
|
|
* canceled (as opposed to finishing normally).
|
|
|
|
|
*
|
|
|
|
|
* <p>Commands will be canceled even if they are not scheduled as
|
|
|
|
|
* interruptible.
|
2019-08-25 23:55:59 -04:00
|
|
|
*
|
|
|
|
|
* @param commands the commands to cancel
|
|
|
|
|
*/
|
|
|
|
|
void Cancel(std::initializer_list<Command*> commands);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Cancels all commands that are currently scheduled.
|
|
|
|
|
*/
|
|
|
|
|
void CancelAll();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Whether the given commands are running. Note that this only works on
|
|
|
|
|
* commands that are directly scheduled by the scheduler; it will not work on
|
|
|
|
|
* commands inside of CommandGroups, as the scheduler does not see them.
|
|
|
|
|
*
|
|
|
|
|
* @param commands the command to query
|
|
|
|
|
* @return whether the command is currently scheduled
|
|
|
|
|
*/
|
2022-10-15 16:33:14 -07:00
|
|
|
bool IsScheduled(std::span<const Command* const> commands) const;
|
2019-08-25 23:55:59 -04:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Whether the given commands are running. Note that this only works on
|
|
|
|
|
* commands that are directly scheduled by the scheduler; it will not work on
|
|
|
|
|
* commands inside of CommandGroups, as the scheduler does not see them.
|
|
|
|
|
*
|
|
|
|
|
* @param commands the command to query
|
|
|
|
|
* @return whether the command is currently scheduled
|
|
|
|
|
*/
|
|
|
|
|
bool IsScheduled(std::initializer_list<const Command*> commands) const;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Whether a given command is running. Note that this only works on commands
|
|
|
|
|
* that are directly scheduled by the scheduler; it will not work on commands
|
|
|
|
|
* inside of CommandGroups, as the scheduler does not see them.
|
|
|
|
|
*
|
2021-10-14 18:09:38 -07:00
|
|
|
* @param command the command to query
|
2019-08-25 23:55:59 -04:00
|
|
|
* @return whether the command is currently scheduled
|
|
|
|
|
*/
|
|
|
|
|
bool IsScheduled(const Command* command) const;
|
|
|
|
|
|
2022-10-06 01:19:28 +03:00
|
|
|
/**
|
|
|
|
|
* Whether a given command is running. Note that this only works on commands
|
|
|
|
|
* that are directly scheduled by the scheduler; it will not work on commands
|
|
|
|
|
* inside of CommandGroups, as the scheduler does not see them.
|
|
|
|
|
*
|
|
|
|
|
* @param command the command to query
|
|
|
|
|
* @return whether the command is currently scheduled
|
|
|
|
|
*/
|
|
|
|
|
bool IsScheduled(const CommandPtr& command) const;
|
|
|
|
|
|
2019-08-25 23:55:59 -04:00
|
|
|
/**
|
|
|
|
|
* Returns the command currently requiring a given subsystem. Null if no
|
|
|
|
|
* command is currently requiring the subsystem
|
|
|
|
|
*
|
|
|
|
|
* @param subsystem the subsystem to be inquired about
|
|
|
|
|
* @return the command currently requiring the subsystem
|
|
|
|
|
*/
|
|
|
|
|
Command* Requiring(const Subsystem* subsystem) const;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Disables the command scheduler.
|
|
|
|
|
*/
|
|
|
|
|
void Disable();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Enables the command scheduler.
|
|
|
|
|
*/
|
|
|
|
|
void Enable();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Adds an action to perform on the initialization of any command by the
|
|
|
|
|
* scheduler.
|
|
|
|
|
*
|
|
|
|
|
* @param action the action to perform
|
|
|
|
|
*/
|
|
|
|
|
void OnCommandInitialize(Action action);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Adds an action to perform on the execution of any command by the scheduler.
|
|
|
|
|
*
|
|
|
|
|
* @param action the action to perform
|
|
|
|
|
*/
|
|
|
|
|
void OnCommandExecute(Action action);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Adds an action to perform on the interruption of any command by the
|
|
|
|
|
* scheduler.
|
|
|
|
|
*
|
|
|
|
|
* @param action the action to perform
|
|
|
|
|
*/
|
|
|
|
|
void OnCommandInterrupt(Action action);
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Adds an action to perform on the finishing of any command by the scheduler.
|
|
|
|
|
*
|
|
|
|
|
* @param action the action to perform
|
|
|
|
|
*/
|
|
|
|
|
void OnCommandFinish(Action action);
|
|
|
|
|
|
2021-06-13 16:38:05 -07:00
|
|
|
void InitSendable(nt::NTSendableBuilder& builder) override;
|
2019-08-25 23:55:59 -04:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
// Constructor; private as this is a singleton
|
|
|
|
|
CommandScheduler();
|
|
|
|
|
|
2019-11-05 20:52:49 -08:00
|
|
|
void SetDefaultCommandImpl(Subsystem* subsystem,
|
|
|
|
|
std::unique_ptr<Command> command);
|
2019-10-18 10:56:12 -04:00
|
|
|
|
2019-11-05 20:52:49 -08:00
|
|
|
class Impl;
|
|
|
|
|
std::unique_ptr<Impl> m_impl;
|
2019-10-18 10:56:12 -04:00
|
|
|
|
2020-03-28 12:29:51 -04:00
|
|
|
frc::Watchdog m_watchdog;
|
|
|
|
|
|
2019-08-25 23:55:59 -04:00
|
|
|
friend class CommandTestBase;
|
2022-06-16 09:32:16 +03:00
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
|
friend class CommandTestBaseWithParam;
|
2019-08-25 23:55:59 -04:00
|
|
|
};
|
|
|
|
|
} // namespace frc2
|