WPILibC++ 2025.2.1
Loading...
Searching...
No Matches
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 * @warning Using this function directly can often lead to unexpected behavior
92 * and should be avoided. Instead Triggers should be used to schedule
93 * Commands.
94 *
95 * @param command the command to schedule
96 */
97 void Schedule(const CommandPtr& command);
98
99 /**
100 * Schedules a command for execution. Does nothing if the command is already
101 * scheduled. If a command's requirements are not available, it will only be
102 * started if all the commands currently using those requirements are
103 * interruptible. If this is the case, they will be interrupted and the
104 * command will be scheduled.
105 *
106 * @param command the command to schedule
107 */
108 void Schedule(CommandPtr&& command);
109
110 /**
111 * Schedules a command for execution. Does nothing if the command is already
112 * scheduled. If a command's requirements are not available, it will only be
113 * started if all the commands currently using those requirements have been
114 * scheduled as interruptible. If this is the case, they will be interrupted
115 * and the command will be scheduled.
116 *
117 * The pointer must remain valid through the entire lifecycle of the command.
118 *
119 * @warning Using this function directly can often lead to unexpected behavior
120 * and should be avoided. Instead Triggers should be used to schedule
121 * Commands.
122 *
123 * @param command the command to schedule
124 */
125 void Schedule(Command* command);
126
127 /**
128 * Schedules multiple commands for execution. Does nothing for commands
129 * already scheduled.
130 *
131 * @warning Using this function directly can often lead to unexpected behavior
132 * and should be avoided. Instead Triggers should be used to schedule
133 * Commands.
134 *
135 * @param commands the commands to schedule
136 */
137 void Schedule(std::span<Command* const> commands);
138
139 /**
140 * Schedules multiple commands for execution. Does nothing for commands
141 * already scheduled.
142 *
143 * @warning Using this function directly can often lead to unexpected behavior
144 * and should be avoided. Instead Triggers should be used to schedule
145 * Commands.
146 *
147 * @param commands the commands to schedule
148 */
149 void Schedule(std::initializer_list<Command*> commands);
150
151 /**
152 * Runs a single iteration of the scheduler. The execution occurs in the
153 * following order:
154 *
155 * <p>Subsystem periodic methods are called.
156 *
157 * <p>Button bindings are polled, and new commands are scheduled from them.
158 *
159 * <p>Currently-scheduled commands are executed.
160 *
161 * <p>End conditions are checked on currently-scheduled commands, and commands
162 * that are finished have their end methods called and are removed.
163 *
164 * <p>Any subsystems not being used as requirements have their default methods
165 * started.
166 */
167 void Run();
168
169 /**
170 * Registers subsystems with the scheduler. This must be called for the
171 * subsystem's periodic block to run when the scheduler is run, and for the
172 * subsystem's default command to be scheduled. It is recommended to call
173 * this from the constructor of your subsystem implementations.
174 *
175 * @param subsystem the subsystem to register
176 */
177 void RegisterSubsystem(Subsystem* subsystem);
178
179 /**
180 * Un-registers subsystems with the scheduler. The subsystem will no longer
181 * have its periodic block called, and will not have its default command
182 * scheduled.
183 *
184 * @param subsystem the subsystem to un-register
185 */
187
188 void RegisterSubsystem(std::initializer_list<Subsystem*> subsystems);
189 void RegisterSubsystem(std::span<Subsystem* const> subsystems);
190
191 void UnregisterSubsystem(std::initializer_list<Subsystem*> subsystems);
192 void UnregisterSubsystem(std::span<Subsystem* const> subsystems);
193
194 /**
195 * Un-registers all registered Subsystems with the scheduler. All currently
196 * registered subsystems will no longer have their periodic block called, and
197 * will not have their default command scheduled.
198 */
200
201 /**
202 * Sets the default command for a subsystem. Registers that subsystem if it
203 * is not already registered. Default commands will run whenever there is no
204 * other command currently scheduled that requires the subsystem. Default
205 * commands should be written to never end (i.e. their IsFinished() method
206 * should return false), as they would simply be re-scheduled if they do.
207 * Default commands must also require their subsystem.
208 *
209 * @param subsystem the subsystem whose default command will be set
210 * @param defaultCommand the default command to associate with the subsystem
211 */
212 template <std::derived_from<Command> T>
213 void SetDefaultCommand(Subsystem* subsystem, T&& defaultCommand) {
214 if (!defaultCommand.HasRequirement(subsystem)) {
215 throw FRC_MakeError(frc::err::CommandIllegalUse,
216 "Default commands must require their subsystem!");
217 }
218 SetDefaultCommandImpl(subsystem, std::make_unique<std::decay_t<T>>(
219 std::forward<T>(defaultCommand)));
220 }
221
222 /**
223 * Sets the default command for a subsystem. Registers that subsystem if it
224 * is not already registered. Default commands will run whenever there is no
225 * other command currently scheduled that requires the subsystem. Default
226 * commands should be written to never end (i.e. their IsFinished() method
227 * should return false), as they would simply be re-scheduled if they do.
228 * Default commands must also require their subsystem.
229 *
230 * @param subsystem the subsystem whose default command will be set
231 * @param defaultCommand the default command to associate with the subsystem
232 */
233 void SetDefaultCommand(Subsystem* subsystem, CommandPtr&& defaultCommand);
234
235 /**
236 * Removes the default command for a subsystem. The current default command
237 * will run until another command is scheduled that requires the subsystem, at
238 * which point the current default command will not be re-scheduled.
239 *
240 * @param subsystem the subsystem whose default command will be removed
241 */
243
244 /**
245 * Gets the default command associated with this subsystem. Null if this
246 * subsystem has no default command associated with it.
247 *
248 * @param subsystem the subsystem to inquire about
249 * @return the default command associated with the subsystem
250 */
251 Command* GetDefaultCommand(const Subsystem* subsystem) const;
252
253 /**
254 * Cancels commands. The scheduler will only call Command::End()
255 * method of the canceled command with true, indicating they were
256 * canceled (as opposed to finishing normally).
257 *
258 * <p>Commands will be canceled even if they are not scheduled as
259 * interruptible.
260 *
261 * @param command the command to cancel
262 */
263 void Cancel(Command* command);
264
265 /**
266 * Cancels commands. The scheduler will only call Command::End()
267 * method of the canceled command with true, indicating they were
268 * canceled (as opposed to finishing normally).
269 *
270 * <p>Commands will be canceled even if they are not scheduled as
271 * interruptible.
272 *
273 * @param command the command to cancel
274 */
275 void Cancel(const CommandPtr& command);
276
277 /**
278 * Cancels commands. The scheduler will only call Command::End()
279 * method of the canceled command with true, indicating they were
280 * canceled (as opposed to finishing normally).
281 *
282 * <p>Commands will be canceled even if they are not scheduled as
283 * interruptible.
284 *
285 * @param commands the commands to cancel
286 */
287 void Cancel(std::span<Command* const> commands);
288
289 /**
290 * Cancels commands. The scheduler will only call Command::End()
291 * method of the canceled command with true, indicating they were
292 * canceled (as opposed to finishing normally).
293 *
294 * <p>Commands will be canceled even if they are not scheduled as
295 * interruptible.
296 *
297 * @param commands the commands to cancel
298 */
299 void Cancel(std::initializer_list<Command*> commands);
300
301 /**
302 * Cancels all commands that are currently scheduled.
303 */
304 void CancelAll();
305
306 /**
307 * Whether the given commands are running. Note that this only works on
308 * commands that are directly scheduled by the scheduler; it will not work on
309 * commands inside of CommandGroups, as the scheduler does not see them.
310 *
311 * @param commands the command to query
312 * @return whether the command is currently scheduled
313 */
314 bool IsScheduled(std::span<const Command* const> commands) const;
315
316 /**
317 * Whether the given commands are running. Note that this only works on
318 * commands that are directly scheduled by the scheduler; it will not work on
319 * commands inside of CommandGroups, as the scheduler does not see them.
320 *
321 * @param commands the command to query
322 * @return whether the command is currently scheduled
323 */
324 bool IsScheduled(std::initializer_list<const Command*> commands) const;
325
326 /**
327 * Whether a given command is running. Note that this only works on commands
328 * that are directly scheduled by the scheduler; it will not work on commands
329 * inside of CommandGroups, as the scheduler does not see them.
330 *
331 * @param command the command to query
332 * @return whether the command is currently scheduled
333 */
334 bool IsScheduled(const Command* command) const;
335
336 /**
337 * Whether a given command is running. Note that this only works on commands
338 * that are directly scheduled by the scheduler; it will not work on commands
339 * inside of CommandGroups, as the scheduler does not see them.
340 *
341 * @param command the command to query
342 * @return whether the command is currently scheduled
343 */
344 bool IsScheduled(const CommandPtr& command) const;
345
346 /**
347 * Returns the command currently requiring a given subsystem. Null if no
348 * command is currently requiring the subsystem
349 *
350 * @param subsystem the subsystem to be inquired about
351 * @return the command currently requiring the subsystem
352 */
353 Command* Requiring(const Subsystem* subsystem) const;
354
355 /**
356 * Disables the command scheduler.
357 */
358 void Disable();
359
360 /**
361 * Enables the command scheduler.
362 */
363 void Enable();
364
365 /**
366 * Prints list of epochs added so far and their times.
367 */
369
370 /**
371 * Adds an action to perform on the initialization of any command by the
372 * scheduler.
373 *
374 * @param action the action to perform
375 */
377
378 /**
379 * Adds an action to perform on the execution of any command by the scheduler.
380 *
381 * @param action the action to perform
382 */
384
385 /**
386 * Adds an action to perform on the interruption of any command by the
387 * scheduler.
388 *
389 * @param action the action to perform
390 */
392
393 /**
394 * Adds an action to perform on the interruption of any command by the
395 * scheduler. The action receives the interrupted command and an optional
396 * containing the interrupting command, or nullopt if it was not canceled by a
397 * command (e.g., by Cancel()).
398 *
399 * @param action the action to perform
400 */
402
403 /**
404 * Adds an action to perform on the finishing of any command by the scheduler.
405 *
406 * @param action the action to perform
407 */
409
410 /**
411 * Requires that the specified command hasn't already been added to a
412 * composition.
413 *
414 * @param command The command to check
415 * @throws if the given commands have already been composed.
416 */
417 void RequireUngrouped(const Command* command);
418
419 /**
420 * Requires that the specified commands have not already been added to a
421 * composition.
422 *
423 * @param commands The commands to check
424 * @throws if the given commands have already been composed.
425 */
426 void RequireUngrouped(std::span<const std::unique_ptr<Command>> commands);
427
428 /**
429 * Requires that the specified commands have not already been added to a
430 * composition.
431 *
432 * @param commands The commands to check
433 * @throws IllegalArgumentException if the given commands have already been
434 * composed.
435 */
436 void RequireUngrouped(std::initializer_list<const Command*> commands);
437
438 /**
439 * Requires that the specified command has not already been added to a
440 * composition and is not currently scheduled.
441 *
442 * @param command The command to check
443 * @throws IllegalArgumentException if the given command has already been
444 * composed or scheduled.
445 */
447
448 /**
449 * Requires that the specified commands have not already been added to a
450 * composition and are not currently scheduled.
451 *
452 * @param commands The commands to check
453 * @throws IllegalArgumentException if the given commands have already been
454 * composed.
455 */
457 std::span<const std::unique_ptr<Command>> commands);
458
459 /**
460 * Requires that the specified commands have not already been added to a
461 * composition and are not currently scheduled.
462 *
463 * @param commands The commands to check
464 * @throws IllegalArgumentException if the given commands have already been
465 * composed or scheduled.
466 */
468 std::initializer_list<const Command*> commands);
469
470 void InitSendable(wpi::SendableBuilder& builder) override;
471
472 private:
473 // Constructor; private as this is a singleton
475
476 void SetDefaultCommandImpl(Subsystem* subsystem,
477 std::unique_ptr<Command> command);
478
479 void Cancel(Command* command, std::optional<Command*> interruptor);
480
481 class Impl;
482 std::unique_ptr<Impl> m_impl;
483
484 frc::Watchdog m_watchdog;
485
486 friend class CommandTestBase;
487
488 template <typename T>
490};
491} // 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:28
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:486
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(CommandPtr &&command)
Schedules a command 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:489
void Disable()
Disables the command scheduler.
void Cancel(std::span< Command *const > commands)
Cancels commands.
CommandScheduler(const CommandScheduler &)=delete
std::function< void(const Command &, const std::optional< Command * > &)> InterruptAction
Definition CommandScheduler.h:52
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.
void PrintWatchdogEpochs()
Prints list of epochs added so far and their times.
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:213
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:21
Interface for Sendable objects.
Definition Sendable.h:16
Definition FunctionalCommand.h:13
#define FRC_MakeError(status, format,...)
Makes a runtime error exception object.
Definition Errors.h:164