WPILibC++ 2023.4.3-108-ge5452e3
CommandScheduler.h
Go to the documentation of this file.
1// Copyright (c) FIRST and other WPILib contributors.
2// Open Source Software; you can modify and/or share it under the terms of
3// the WPILib BSD license file in the root directory of this project.
4
5#pragma once
6
7#include <concepts>
8#include <initializer_list>
9#include <memory>
10#include <span>
11#include <utility>
12
13#include <frc/Errors.h>
14#include <frc/Watchdog.h>
15#include <frc/event/EventLoop.h>
17#include <units/time.h>
18#include <wpi/FunctionExtras.h>
20
21namespace frc2 {
22class Command;
23class CommandPtr;
24class Subsystem;
25
26/**
27 * The scheduler responsible for running Commands. A Command-based robot should
28 * call Run() on the singleton instance in its periodic block in order to run
29 * commands synchronously from the main loop. Subsystems should be registered
30 * with the scheduler using RegisterSubsystem() in order for their Periodic()
31 * methods to be called and for their default commands to be scheduled.
32 *
33 * This class is provided by the NewCommands VendorDep
34 */
35class CommandScheduler final : public nt::NTSendable,
36 public wpi::SendableHelper<CommandScheduler> {
37 public:
38 /**
39 * Returns the Scheduler instance.
40 *
41 * @return the instance
42 */
44
48
49 using Action = std::function<void(const Command&)>;
50
51 /**
52 * Changes the period of the loop overrun watchdog. This should be kept in
53 * sync with the TimedRobot period.
54 */
55 void SetPeriod(units::second_t period);
56
57 /**
58 * Get the active button poll.
59 *
60 * @return a reference to the current {@link frc::EventLoop} object polling
61 * buttons.
62 */
64
65 /**
66 * Replace the button poll with another one.
67 *
68 * @param loop the new button polling loop object.
69 */
71
72 /**
73 * Get the default button poll.
74 *
75 * @return a reference to the default {@link frc::EventLoop} object polling
76 * buttons.
77 */
79
80 /**
81 * Schedules a command for execution. Does nothing if the command is already
82 * scheduled. If a command's requirements are not available, it will only be
83 * started if all the commands currently using those requirements are
84 * interruptible. If this is the case, they will be interrupted and the
85 * command will be scheduled.
86 *
87 * @param command the command to schedule
88 */
89 void Schedule(const CommandPtr& command);
90
91 /**
92 * Schedules a command for execution. Does nothing if the command is already
93 * scheduled. If a command's requirements are not available, it will only be
94 * started if all the commands currently using those requirements have been
95 * scheduled as interruptible. If this is the case, they will be interrupted
96 * and the command will be scheduled.
97 *
98 * @param command the command to schedule
99 */
100 void Schedule(Command* command);
101
102 /**
103 * Schedules multiple commands for execution. Does nothing for commands
104 * already scheduled.
105 *
106 * @param commands the commands to schedule
107 */
108 void Schedule(std::span<Command* const> commands);
109
110 /**
111 * Schedules multiple commands for execution. Does nothing for commands
112 * already scheduled.
113 *
114 * @param commands the commands to schedule
115 */
116 void Schedule(std::initializer_list<Command*> commands);
117
118 /**
119 * Runs a single iteration of the scheduler. The execution occurs in the
120 * following order:
121 *
122 * <p>Subsystem periodic methods are called.
123 *
124 * <p>Button bindings are polled, and new commands are scheduled from them.
125 *
126 * <p>Currently-scheduled commands are executed.
127 *
128 * <p>End conditions are checked on currently-scheduled commands, and commands
129 * that are finished have their end methods called and are removed.
130 *
131 * <p>Any subsystems not being used as requirements have their default methods
132 * started.
133 */
134 void Run();
135
136 /**
137 * Registers subsystems with the scheduler. This must be called for the
138 * subsystem's periodic block to run when the scheduler is run, and for the
139 * subsystem's default command to be scheduled. It is recommended to call
140 * this from the constructor of your subsystem implementations.
141 *
142 * @param subsystem the subsystem to register
143 */
144 void RegisterSubsystem(Subsystem* subsystem);
145
146 /**
147 * Un-registers subsystems with the scheduler. The subsystem will no longer
148 * have its periodic block called, and will not have its default command
149 * scheduled.
150 *
151 * @param subsystem the subsystem to un-register
152 */
154
155 void RegisterSubsystem(std::initializer_list<Subsystem*> subsystems);
156 void RegisterSubsystem(std::span<Subsystem* const> subsystems);
157
158 void UnregisterSubsystem(std::initializer_list<Subsystem*> subsystems);
159 void UnregisterSubsystem(std::span<Subsystem* const> subsystems);
160
161 /**
162 * Sets the default command for a subsystem. Registers that subsystem if it
163 * is not already registered. Default commands will run whenever there is no
164 * other command currently scheduled that requires the subsystem. Default
165 * commands should be written to never end (i.e. their IsFinished() method
166 * should return false), as they would simply be re-scheduled if they do.
167 * Default commands must also require their subsystem.
168 *
169 * @param subsystem the subsystem whose default command will be set
170 * @param defaultCommand the default command to associate with the subsystem
171 */
172 template <std::derived_from<Command> T>
173 void SetDefaultCommand(Subsystem* subsystem, T&& defaultCommand) {
174 if (!defaultCommand.HasRequirement(subsystem)) {
175 throw FRC_MakeError(frc::err::CommandIllegalUse,
176 "Default commands must require their subsystem!");
177 }
178 SetDefaultCommandImpl(subsystem, std::make_unique<std::decay_t<T>>(
179 std::forward<T>(defaultCommand)));
180 }
181
182 /**
183 * Sets the default command for a subsystem. Registers that subsystem if it
184 * is not already registered. Default commands will run whenever there is no
185 * other command currently scheduled that requires the subsystem. Default
186 * commands should be written to never end (i.e. their IsFinished() method
187 * should return false), as they would simply be re-scheduled if they do.
188 * Default commands must also require their subsystem.
189 *
190 * @param subsystem the subsystem whose default command will be set
191 * @param defaultCommand the default command to associate with the subsystem
192 */
193 void SetDefaultCommand(Subsystem* subsystem, CommandPtr&& defaultCommand);
194
195 /**
196 * Removes the default command for a subsystem. The current default command
197 * will run until another command is scheduled that requires the subsystem, at
198 * which point the current default command will not be re-scheduled.
199 *
200 * @param subsystem the subsystem whose default command will be removed
201 */
203
204 /**
205 * Gets the default command associated with this subsystem. Null if this
206 * subsystem has no default command associated with it.
207 *
208 * @param subsystem the subsystem to inquire about
209 * @return the default command associated with the subsystem
210 */
211 Command* GetDefaultCommand(const Subsystem* subsystem) const;
212
213 /**
214 * Cancels commands. The scheduler will only call Command::End()
215 * method of the canceled command with true, indicating they were
216 * canceled (as opposed to finishing normally).
217 *
218 * <p>Commands will be canceled even if they are not scheduled as
219 * interruptible.
220 *
221 * @param command the command to cancel
222 */
223 void Cancel(Command* command);
224
225 /**
226 * Cancels commands. The scheduler will only call Command::End()
227 * method of the canceled command with true, indicating they were
228 * canceled (as opposed to finishing normally).
229 *
230 * <p>Commands will be canceled even if they are not scheduled as
231 * interruptible.
232 *
233 * @param command the command to cancel
234 */
235 void Cancel(const CommandPtr& command);
236
237 /**
238 * Cancels commands. The scheduler will only call Command::End()
239 * method of the canceled command with true, indicating they were
240 * canceled (as opposed to finishing normally).
241 *
242 * <p>Commands will be canceled even if they are not scheduled as
243 * interruptible.
244 *
245 * @param commands the commands to cancel
246 */
247 void Cancel(std::span<Command* const> commands);
248
249 /**
250 * Cancels commands. The scheduler will only call Command::End()
251 * method of the canceled command with true, indicating they were
252 * canceled (as opposed to finishing normally).
253 *
254 * <p>Commands will be canceled even if they are not scheduled as
255 * interruptible.
256 *
257 * @param commands the commands to cancel
258 */
259 void Cancel(std::initializer_list<Command*> commands);
260
261 /**
262 * Cancels all commands that are currently scheduled.
263 */
264 void CancelAll();
265
266 /**
267 * Whether the given commands are running. Note that this only works on
268 * commands that are directly scheduled by the scheduler; it will not work on
269 * commands inside of CommandGroups, as the scheduler does not see them.
270 *
271 * @param commands the command to query
272 * @return whether the command is currently scheduled
273 */
274 bool IsScheduled(std::span<const Command* const> commands) const;
275
276 /**
277 * Whether the given commands are running. Note that this only works on
278 * commands that are directly scheduled by the scheduler; it will not work on
279 * commands inside of CommandGroups, as the scheduler does not see them.
280 *
281 * @param commands the command to query
282 * @return whether the command is currently scheduled
283 */
284 bool IsScheduled(std::initializer_list<const Command*> commands) const;
285
286 /**
287 * Whether a given command is running. Note that this only works on commands
288 * that are directly scheduled by the scheduler; it will not work on commands
289 * inside of CommandGroups, as the scheduler does not see them.
290 *
291 * @param command the command to query
292 * @return whether the command is currently scheduled
293 */
294 bool IsScheduled(const Command* command) const;
295
296 /**
297 * Whether a given command is running. Note that this only works on commands
298 * that are directly scheduled by the scheduler; it will not work on commands
299 * inside of CommandGroups, as the scheduler does not see them.
300 *
301 * @param command the command to query
302 * @return whether the command is currently scheduled
303 */
304 bool IsScheduled(const CommandPtr& command) const;
305
306 /**
307 * Returns the command currently requiring a given subsystem. Null if no
308 * command is currently requiring the subsystem
309 *
310 * @param subsystem the subsystem to be inquired about
311 * @return the command currently requiring the subsystem
312 */
313 Command* Requiring(const Subsystem* subsystem) const;
314
315 /**
316 * Disables the command scheduler.
317 */
318 void Disable();
319
320 /**
321 * Enables the command scheduler.
322 */
323 void Enable();
324
325 /**
326 * Adds an action to perform on the initialization of any command by the
327 * scheduler.
328 *
329 * @param action the action to perform
330 */
332
333 /**
334 * Adds an action to perform on the execution of any command by the scheduler.
335 *
336 * @param action the action to perform
337 */
339
340 /**
341 * Adds an action to perform on the interruption of any command by the
342 * scheduler.
343 *
344 * @param action the action to perform
345 */
347
348 /**
349 * Adds an action to perform on the finishing of any command by the scheduler.
350 *
351 * @param action the action to perform
352 */
354
355 /**
356 * Requires that the specified command hasn't been already added to a
357 * composition.
358 *
359 * @param command The command to check
360 * @throws if the given commands have already been composed.
361 */
362 void RequireUngrouped(const Command* command);
363
364 /**
365 * Requires that the specified commands not have been already added to a
366 * composition.
367 *
368 * @param commands The commands to check
369 * @throws if the given commands have already been composed.
370 */
371 void RequireUngrouped(std::span<const std::unique_ptr<Command>> commands);
372
373 /**
374 * Requires that the specified commands not have been already added to a
375 * composition.
376 *
377 * @param commands The commands to check
378 * @throws IllegalArgumentException if the given commands have already been
379 * composed.
380 */
381 void RequireUngrouped(std::initializer_list<const Command*> commands);
382
383 void InitSendable(nt::NTSendableBuilder& builder) override;
384
385 private:
386 // Constructor; private as this is a singleton
388
389 void SetDefaultCommandImpl(Subsystem* subsystem,
390 std::unique_ptr<Command> command);
391
392 class Impl;
393 std::unique_ptr<Impl> m_impl;
394
395 frc::Watchdog m_watchdog;
396
397 friend class CommandTestBase;
398
399 template <typename T>
401};
402} // namespace frc2
This file provides a collection of function (or more generally, callable) type erasure utilities supp...
A state machine representing a complete action to be performed by the robot.
Definition: Command.h:44
A wrapper around std::unique_ptr<Command> so commands have move-only semantics.
Definition: CommandPtr.h:29
The scheduler responsible for running Commands.
Definition: CommandScheduler.h:36
void Schedule(std::initializer_list< Command * > commands)
Schedules multiple commands for execution.
void RequireUngrouped(std::span< const std::unique_ptr< Command > > commands)
Requires that the specified commands not have been already added to a composition.
void CancelAll()
Cancels all commands that are currently scheduled.
void OnCommandFinish(Action action)
Adds an action to perform on the finishing of any command by the scheduler.
Command * GetDefaultCommand(const Subsystem *subsystem) const
Gets the default command associated with this subsystem.
bool IsScheduled(std::initializer_list< const Command * > commands) const
Whether the given commands are running.
bool IsScheduled(const CommandPtr &command) const
Whether a given command is running.
CommandScheduler & operator=(const CommandScheduler &)=delete
void SetPeriod(units::second_t period)
Changes the period of the loop overrun watchdog.
friend class CommandTestBase
Definition: CommandScheduler.h:397
void RegisterSubsystem(std::initializer_list< Subsystem * > subsystems)
void RequireUngrouped(const Command *command)
Requires that the specified command hasn't been already added to a composition.
void RegisterSubsystem(std::span< Subsystem *const > subsystems)
void Schedule(std::span< Command *const > commands)
Schedules multiple commands for execution.
void Schedule(Command *command)
Schedules a command for execution.
void UnregisterSubsystem(Subsystem *subsystem)
Un-registers subsystems with the scheduler.
bool IsScheduled(const Command *command) const
Whether a given command is running.
void RegisterSubsystem(Subsystem *subsystem)
Registers subsystems with the scheduler.
void Cancel(Command *command)
Cancels commands.
void OnCommandExecute(Action action)
Adds an action to perform on the execution of any command by the scheduler.
void OnCommandInitialize(Action action)
Adds an action to perform on the initialization of any command by the scheduler.
void InitSendable(nt::NTSendableBuilder &builder) override
Initializes this Sendable object.
std::function< void(const Command &)> Action
Definition: CommandScheduler.h:49
void SetActiveButtonLoop(frc::EventLoop *loop)
Replace the button poll with another one.
friend class CommandTestBaseWithParam
Definition: CommandScheduler.h:400
void Disable()
Disables the command scheduler.
void Cancel(std::span< Command *const > commands)
Cancels commands.
CommandScheduler(const CommandScheduler &)=delete
void UnregisterSubsystem(std::span< Subsystem *const > subsystems)
void RemoveDefaultCommand(Subsystem *subsystem)
Removes the default command for a subsystem.
void SetDefaultCommand(Subsystem *subsystem, CommandPtr &&defaultCommand)
Sets the default command for a subsystem.
void Cancel(std::initializer_list< Command * > commands)
Cancels commands.
void Schedule(const CommandPtr &command)
Schedules a command for execution.
~CommandScheduler() override
void Run()
Runs a single iteration of the scheduler.
Command * Requiring(const Subsystem *subsystem) const
Returns the command currently requiring a given subsystem.
void OnCommandInterrupt(Action action)
Adds an action to perform on the interruption of any command by the scheduler.
static CommandScheduler & GetInstance()
Returns the Scheduler instance.
frc::EventLoop * GetDefaultButtonLoop() const
Get the default button poll.
void UnregisterSubsystem(std::initializer_list< Subsystem * > subsystems)
void Cancel(const CommandPtr &command)
Cancels commands.
void Enable()
Enables the command scheduler.
void SetDefaultCommand(Subsystem *subsystem, T &&defaultCommand)
Sets the default command for a subsystem.
Definition: CommandScheduler.h:173
frc::EventLoop * GetActiveButtonLoop() const
Get the active button poll.
bool IsScheduled(std::span< const Command *const > commands) const
Whether the given commands are running.
void RequireUngrouped(std::initializer_list< const Command * > commands)
Requires that the specified commands not have been already added to a composition.
A robot subsystem.
Definition: Subsystem.h:39
The loop polling BooleanEvent objects and executing the actions bound to them.
Definition: EventLoop.h:15
A class that's a wrapper around a watchdog timer.
Definition: Watchdog.h:26
Definition: NTSendableBuilder.h:18
Interface for NetworkTable Sendable objects.
Definition: NTSendable.h:16
A helper class for use with objects that add themselves to SendableRegistry.
Definition: SendableHelper.h:19
Definition: ProfiledPIDCommand.h:18
#define FRC_MakeError(status, format,...)
Makes a runtime error exception object.
Definition: Errors.h:153