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