WPILibC++ 2027.0.0-alpha-4
Loading...
Searching...
No Matches
CommandScheduler.hpp
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 <functional>
9#include <initializer_list>
10#include <memory>
11#include <optional>
12#include <span>
13#include <utility>
14
16#include "wpi/system/Errors.hpp"
18#include "wpi/units/time.hpp"
22
23namespace wpi::cmd {
24class Command;
25class CommandPtr;
26class Subsystem;
27
28/**
29 * The scheduler responsible for running Commands. A Command-based robot should
30 * call Run() on the singleton instance in its periodic block in order to run
31 * commands synchronously from the main loop. Subsystems should be registered
32 * with the scheduler using RegisterSubsystem() in order for their Periodic()
33 * methods to be called and for their default commands to be scheduled.
34 *
35 * This class is provided by the NewCommands VendorDep
36 */
38 : public wpi::util::Sendable,
39 public wpi::util::SendableHelper<CommandScheduler> {
40 public:
41 /**
42 * Returns the Scheduler instance.
43 *
44 * @return the instance
45 */
47
51
52 using Action = std::function<void(const Command&)>;
54 std::function<void(const Command&, const std::optional<Command*>&)>;
55
56 /**
57 * Changes the period of the loop overrun watchdog. This should be kept in
58 * sync with the TimedRobot period.
59 */
60 void SetPeriod(wpi::units::second_t period);
61
62 /**
63 * Get the active button poll.
64 *
65 * @return a reference to the current {@link wpi::EventLoop} object polling
66 * buttons.
67 */
69
70 /**
71 * Replace the button poll with another one.
72 *
73 * @param loop the new button polling loop object.
74 */
76
77 /**
78 * Get the default button poll.
79 *
80 * @return a reference to the default {@link wpi::EventLoop} object polling
81 * buttons.
82 */
84
85 /**
86 * Schedules a command for execution. Does nothing if the command is already
87 * scheduled. If a command's requirements are not available, it will only be
88 * started if all the commands currently using those requirements are
89 * interruptible. If this is the case, they will be interrupted and the
90 * command will be scheduled.
91 *
92 * @warning Using this function directly can often lead to unexpected behavior
93 * and should be avoided. Instead Triggers should be used to schedule
94 * Commands.
95 *
96 * @param command the command to schedule
97 */
98 void Schedule(const CommandPtr& command);
99
100 /**
101 * Schedules a command for execution. Does nothing if the command is already
102 * scheduled. If a command's requirements are not available, it will only be
103 * started if all the commands currently using those requirements are
104 * interruptible. If this is the case, they will be interrupted and the
105 * command will be scheduled.
106 *
107 * @param command the command to schedule
108 */
109 void Schedule(CommandPtr&& command);
110
111 /**
112 * Schedules a command for execution. Does nothing if the command is already
113 * scheduled. If a command's requirements are not available, it will only be
114 * started if all the commands currently using those requirements have been
115 * scheduled as interruptible. If this is the case, they will be interrupted
116 * and the command will be scheduled.
117 *
118 * The pointer must remain valid through the entire lifecycle of the command.
119 *
120 * @warning Using this function directly can often lead to unexpected behavior
121 * and should be avoided. Instead Triggers should be used to schedule
122 * Commands.
123 *
124 * @param command the command to schedule
125 */
126 void Schedule(Command* command);
127
128 /**
129 * Schedules multiple commands for execution. Does nothing for commands
130 * already scheduled.
131 *
132 * @warning Using this function directly can often lead to unexpected behavior
133 * and should be avoided. Instead Triggers should be used to schedule
134 * Commands.
135 *
136 * @param commands the commands to schedule
137 */
138 void Schedule(std::span<Command* const> commands);
139
140 /**
141 * Schedules multiple commands for execution. Does nothing for commands
142 * already scheduled.
143 *
144 * @warning Using this function directly can often lead to unexpected behavior
145 * and should be avoided. Instead Triggers should be used to schedule
146 * Commands.
147 *
148 * @param commands the commands to schedule
149 */
150 void Schedule(std::initializer_list<Command*> commands);
151
152 /**
153 * Runs a single iteration of the scheduler. The execution occurs in the
154 * following order:
155 *
156 * <p>Subsystem periodic methods are called.
157 *
158 * <p>Button bindings are polled, and new commands are scheduled from them.
159 *
160 * <p>Currently-scheduled commands are executed.
161 *
162 * <p>End conditions are checked on currently-scheduled commands, and commands
163 * that are finished have their end methods called and are removed.
164 *
165 * <p>Any subsystems not being used as requirements have their default methods
166 * started.
167 */
168 void Run();
169
170 /**
171 * Registers subsystems with the scheduler. This must be called for the
172 * subsystem's periodic block to run when the scheduler is run, and for the
173 * subsystem's default command to be scheduled. It is recommended to call
174 * this from the constructor of your subsystem implementations.
175 *
176 * @param subsystem the subsystem to register
177 */
178 void RegisterSubsystem(Subsystem* subsystem);
179
180 /**
181 * Un-registers subsystems with the scheduler. The subsystem will no longer
182 * have its periodic block called, and will not have its default command
183 * scheduled.
184 *
185 * @param subsystem the subsystem to un-register
186 */
188
189 void RegisterSubsystem(std::initializer_list<Subsystem*> subsystems);
190 void RegisterSubsystem(std::span<Subsystem* const> subsystems);
191
192 void UnregisterSubsystem(std::initializer_list<Subsystem*> subsystems);
193 void UnregisterSubsystem(std::span<Subsystem* const> subsystems);
194
195 /**
196 * Un-registers all registered Subsystems with the scheduler. All currently
197 * registered subsystems will no longer have their periodic block called, and
198 * will not have their default command scheduled.
199 */
201
202 /**
203 * Sets the default command for a subsystem. Registers that subsystem if it
204 * is not already registered. Default commands will run whenever there is no
205 * other command currently scheduled that requires the subsystem. Default
206 * commands should be written to never end (i.e. their IsFinished() method
207 * should return false), as they would simply be re-scheduled if they do.
208 * Default commands must also require their subsystem.
209 *
210 * @param subsystem the subsystem whose default command will be set
211 * @param defaultCommand the default command to associate with the subsystem
212 */
213 template <std::derived_from<Command> T>
214 void SetDefaultCommand(Subsystem* subsystem, T&& defaultCommand) {
215 if (!defaultCommand.HasRequirement(subsystem)) {
216 throw WPILIB_MakeError(wpi::err::CommandIllegalUse,
217 "Default commands must require their subsystem!");
218 }
219 SetDefaultCommandImpl(subsystem, std::make_unique<std::decay_t<T>>(
220 std::forward<T>(defaultCommand)));
221 }
222
223 /**
224 * Sets the default command for a subsystem. Registers that subsystem if it
225 * is not already registered. Default commands will run whenever there is no
226 * other command currently scheduled that requires the subsystem. Default
227 * commands should be written to never end (i.e. their IsFinished() method
228 * should return false), as they would simply be re-scheduled if they do.
229 * Default commands must also require their subsystem.
230 *
231 * @param subsystem the subsystem whose default command will be set
232 * @param defaultCommand the default command to associate with the subsystem
233 */
234 void SetDefaultCommand(Subsystem* subsystem, CommandPtr&& defaultCommand);
235
236 /**
237 * Removes the default command for a subsystem. The current default command
238 * will run until another command is scheduled that requires the subsystem, at
239 * which point the current default command will not be re-scheduled.
240 *
241 * @param subsystem the subsystem whose default command will be removed
242 */
244
245 /**
246 * Gets the default command associated with this subsystem. Null if this
247 * subsystem has no default command associated with it.
248 *
249 * @param subsystem the subsystem to inquire about
250 * @return the default command associated with the subsystem
251 */
252 Command* GetDefaultCommand(const Subsystem* subsystem) const;
253
254 /**
255 * Cancels commands. The scheduler will only call Command::End()
256 * method of the canceled command with true, indicating they were
257 * canceled (as opposed to finishing normally).
258 *
259 * <p>Commands will be canceled even if they are not scheduled as
260 * interruptible.
261 *
262 * @param command the command to cancel
263 */
264 void Cancel(Command* command);
265
266 /**
267 * Cancels commands. The scheduler will only call Command::End()
268 * method of the canceled command with true, indicating they were
269 * canceled (as opposed to finishing normally).
270 *
271 * <p>Commands will be canceled even if they are not scheduled as
272 * interruptible.
273 *
274 * @param command the command to cancel
275 */
276 void Cancel(const CommandPtr& command);
277
278 /**
279 * Cancels commands. The scheduler will only call Command::End()
280 * method of the canceled command with true, indicating they were
281 * canceled (as opposed to finishing normally).
282 *
283 * <p>Commands will be canceled even if they are not scheduled as
284 * interruptible.
285 *
286 * @param commands the commands to cancel
287 */
288 void Cancel(std::span<Command* const> commands);
289
290 /**
291 * Cancels commands. The scheduler will only call Command::End()
292 * method of the canceled command with true, indicating they were
293 * canceled (as opposed to finishing normally).
294 *
295 * <p>Commands will be canceled even if they are not scheduled as
296 * interruptible.
297 *
298 * @param commands the commands to cancel
299 */
300 void Cancel(std::initializer_list<Command*> commands);
301
302 /**
303 * Cancels all commands that are currently scheduled.
304 */
305 void CancelAll();
306
307 /**
308 * Whether the given commands are running. Note that this only works on
309 * commands that are directly scheduled by the scheduler; it will not work on
310 * commands inside of CommandGroups, as the scheduler does not see them.
311 *
312 * @param commands the command to query
313 * @return whether the command is currently scheduled
314 */
315 bool IsScheduled(std::span<const Command* const> commands) const;
316
317 /**
318 * Whether the given commands are running. Note that this only works on
319 * commands that are directly scheduled by the scheduler; it will not work on
320 * commands inside of CommandGroups, as the scheduler does not see them.
321 *
322 * @param commands the command to query
323 * @return whether the command is currently scheduled
324 */
325 bool IsScheduled(std::initializer_list<const Command*> commands) const;
326
327 /**
328 * Whether a given command is running. Note that this only works on commands
329 * that are directly scheduled by the scheduler; it will not work on commands
330 * inside of CommandGroups, as the scheduler does not see them.
331 *
332 * @param command the command to query
333 * @return whether the command is currently scheduled
334 */
335 bool IsScheduled(const Command* command) const;
336
337 /**
338 * Whether a given command is running. Note that this only works on commands
339 * that are directly scheduled by the scheduler; it will not work on commands
340 * inside of CommandGroups, as the scheduler does not see them.
341 *
342 * @param command the command to query
343 * @return whether the command is currently scheduled
344 */
345 bool IsScheduled(const CommandPtr& command) const;
346
347 /**
348 * Returns the command currently requiring a given subsystem. Null if no
349 * command is currently requiring the subsystem
350 *
351 * @param subsystem the subsystem to be inquired about
352 * @return the command currently requiring the subsystem
353 */
354 Command* Requiring(const Subsystem* subsystem) const;
355
356 /**
357 * Disables the command scheduler.
358 */
359 void Disable();
360
361 /**
362 * Enables the command scheduler.
363 */
364 void Enable();
365
366 /**
367 * Prints list of epochs added so far and their times.
368 */
370
371 /**
372 * Adds an action to perform on the initialization of any command by the
373 * scheduler.
374 *
375 * @param action the action to perform
376 */
378
379 /**
380 * Adds an action to perform on the execution of any command by the scheduler.
381 *
382 * @param action the action to perform
383 */
385
386 /**
387 * Adds an action to perform on the interruption of any command by the
388 * scheduler.
389 *
390 * @param action the action to perform
391 */
393
394 /**
395 * Adds an action to perform on the interruption of any command by the
396 * scheduler. The action receives the interrupted command and an optional
397 * containing the interrupting command, or nullopt if it was not canceled by a
398 * command (e.g., by Cancel()).
399 *
400 * @param action the action to perform
401 */
403
404 /**
405 * Adds an action to perform on the finishing of any command by the scheduler.
406 *
407 * @param action the action to perform
408 */
410
411 /**
412 * Requires that the specified command hasn't already been added to a
413 * composition.
414 *
415 * @param command The command to check
416 * @throws if the given commands have already been composed.
417 */
418 void RequireUngrouped(const Command* command);
419
420 /**
421 * Requires that the specified commands have not already been added to a
422 * composition.
423 *
424 * @param commands The commands to check
425 * @throws if the given commands have already been composed.
426 */
427 void RequireUngrouped(std::span<const std::unique_ptr<Command>> commands);
428
429 /**
430 * Requires that the specified commands have not already been added to a
431 * composition.
432 *
433 * @param commands The commands to check
434 * @throws IllegalArgumentException if the given commands have already been
435 * composed.
436 */
437 void RequireUngrouped(std::initializer_list<const Command*> commands);
438
439 /**
440 * Requires that the specified command has not already been added to a
441 * composition and is not currently scheduled.
442 *
443 * @param command The command to check
444 * @throws IllegalArgumentException if the given command has already been
445 * composed or scheduled.
446 */
448
449 /**
450 * Requires that the specified commands have not already been added to a
451 * composition and are not currently scheduled.
452 *
453 * @param commands The commands to check
454 * @throws IllegalArgumentException if the given commands have already been
455 * composed.
456 */
458 std::span<const std::unique_ptr<Command>> commands);
459
460 /**
461 * Requires that the specified commands have not already been added to a
462 * composition and are not currently scheduled.
463 *
464 * @param commands The commands to check
465 * @throws IllegalArgumentException if the given commands have already been
466 * composed or scheduled.
467 */
469 std::initializer_list<const Command*> commands);
470
472
473 private:
474 // Constructor; private as this is a singleton
476
477 void SetDefaultCommandImpl(Subsystem* subsystem,
478 std::unique_ptr<Command> command);
479
480 void Cancel(Command* command, std::optional<Command*> interruptor);
481
482 class Impl;
483 std::unique_ptr<Impl> m_impl;
484
485 wpi::Watchdog m_watchdog;
486
487 friend class CommandTestBase;
488
489 template <typename T>
491};
492} // namespace wpi::cmd
#define WPILIB_MakeError(status, format,...)
Makes a runtime error exception object.
Definition Errors.hpp:164
This file provides a collection of function (or more generally, callable) type erasure utilities supp...
A declarative way to bind a set of actions to a loop and execute them when the loop is polled.
Definition EventLoop.hpp:15
A class that's a wrapper around a watchdog timer.
Definition Watchdog.hpp:25
A state machine representing a complete action to be performed by the robot.
Definition Command.hpp:41
A wrapper around std::unique_ptr<Command> so commands have move-only semantics.
Definition CommandPtr.hpp:28
void UnregisterSubsystem(std::span< Subsystem *const > subsystems)
wpi::EventLoop * GetActiveButtonLoop() const
Get the active button poll.
void Enable()
Enables the command scheduler.
bool IsScheduled(const Command *command) const
Whether a given command is running.
bool IsScheduled(std::initializer_list< const Command * > commands) const
Whether the given commands are running.
void UnregisterAllSubsystems()
Un-registers all registered Subsystems with the scheduler.
CommandScheduler & operator=(const CommandScheduler &)=delete
friend class CommandTestBase
Definition CommandScheduler.hpp:487
void Cancel(std::span< Command *const > commands)
Cancels commands.
void OnCommandInitialize(Action action)
Adds an action to perform on the initialization of any command by the scheduler.
void SetDefaultCommand(Subsystem *subsystem, T &&defaultCommand)
Sets the default command for a subsystem.
Definition CommandScheduler.hpp:214
void RequireUngrouped(std::initializer_list< const Command * > commands)
Requires that the specified commands have not already been added to a composition.
void RequireUngroupedAndUnscheduled(std::span< const std::unique_ptr< Command > > commands)
Requires that the specified commands have not already been added to a composition and are not current...
void RequireUngroupedAndUnscheduled(std::initializer_list< const Command * > commands)
Requires that the specified commands have not already been added to a composition and are not current...
void RequireUngrouped(std::span< const std::unique_ptr< Command > > commands)
Requires that the specified commands have not already been added to a composition.
friend class CommandTestBaseWithParam
Definition CommandScheduler.hpp:490
std::function< void(const Command &, const std::optional< Command * > &)> InterruptAction
Definition CommandScheduler.hpp:53
void Run()
Runs a single iteration of the scheduler.
void UnregisterSubsystem(Subsystem *subsystem)
Un-registers subsystems with the scheduler.
void UnregisterSubsystem(std::initializer_list< Subsystem * > subsystems)
void SetActiveButtonLoop(wpi::EventLoop *loop)
Replace the button poll with another one.
void Schedule(const CommandPtr &command)
Schedules a command for execution.
void PrintWatchdogEpochs()
Prints list of epochs added so far and their times.
CommandScheduler(const CommandScheduler &)=delete
void OnCommandInterrupt(InterruptAction action)
Adds an action to perform on the interruption of any command by the scheduler.
void Schedule(Command *command)
Schedules a command for execution.
Command * Requiring(const Subsystem *subsystem) const
Returns the command currently requiring a given subsystem.
void Schedule(CommandPtr &&command)
Schedules a command for execution.
void SetDefaultCommand(Subsystem *subsystem, CommandPtr &&defaultCommand)
Sets the default command for a subsystem.
void RequireUngroupedAndUnscheduled(const Command *command)
Requires that the specified command has not already been added to a composition and is not currently ...
void RegisterSubsystem(std::span< Subsystem *const > subsystems)
void CancelAll()
Cancels all commands that are currently scheduled.
void InitSendable(wpi::util::SendableBuilder &builder) override
Initializes this Sendable object.
void Disable()
Disables the command scheduler.
void RequireUngrouped(const Command *command)
Requires that the specified command hasn't already been added to a composition.
bool IsScheduled(std::span< const Command *const > commands) const
Whether the given commands are running.
void Cancel(Command *command)
Cancels commands.
void OnCommandExecute(Action action)
Adds an action to perform on the execution of any command by the scheduler.
std::function< void(const Command &)> Action
Definition CommandScheduler.hpp:52
static CommandScheduler & GetInstance()
Returns the Scheduler instance.
void Schedule(std::span< Command *const > commands)
Schedules multiple commands for execution.
bool IsScheduled(const CommandPtr &command) const
Whether a given command is running.
void RemoveDefaultCommand(Subsystem *subsystem)
Removes the default command for a subsystem.
wpi::EventLoop * GetDefaultButtonLoop() const
Get the default button poll.
Command * GetDefaultCommand(const Subsystem *subsystem) const
Gets the default command associated with this subsystem.
void OnCommandFinish(Action action)
Adds an action to perform on the finishing of any command by the scheduler.
void SetPeriod(wpi::units::second_t period)
Changes the period of the loop overrun watchdog.
void Cancel(const CommandPtr &command)
Cancels commands.
void RegisterSubsystem(std::initializer_list< Subsystem * > subsystems)
void RegisterSubsystem(Subsystem *subsystem)
Registers subsystems with the scheduler.
void Cancel(std::initializer_list< Command * > commands)
Cancels commands.
void OnCommandInterrupt(Action action)
Adds an action to perform on the interruption of any command by the scheduler.
void Schedule(std::initializer_list< Command * > commands)
Schedules multiple commands for execution.
A robot subsystem.
Definition Subsystem.hpp:42
Helper class for building Sendable dashboard representations.
Definition SendableBuilder.hpp:21
A helper class for use with objects that add themselves to SendableRegistry.
Definition SendableHelper.hpp:21
Interface for Sendable objects.
Definition Sendable.hpp:16
Definition CommandNiDsStadiaController.hpp:15