WPILibC++ 2023.4.3
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 <initializer_list>
8#include <memory>
9#include <span>
10#include <utility>
11
12#include <frc/Errors.h>
13#include <frc/Watchdog.h>
14#include <frc/event/EventLoop.h>
16#include <units/time.h>
17#include <wpi/FunctionExtras.h>
18#include <wpi/deprecated.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 * Removes all button bindings from the scheduler.
82 */
83 WPI_DEPRECATED("Call Clear on the EventLoop instance directly!")
85
86 /**
87 * Schedules a command for execution. Does nothing if the command is already
88 * scheduled. If a command's requirements are not available, it will only be
89 * started if all the commands currently using those requirements are
90 * interruptible. If this is the case, they will be interrupted and the
91 * command will be scheduled.
92 *
93 * @param command the command to schedule
94 */
95 void Schedule(const CommandPtr& command);
96
97 /**
98 * Schedules a command for execution. Does nothing if the command is already
99 * scheduled. If a command's requirements are not available, it will only be
100 * started if all the commands currently using those requirements have been
101 * scheduled as interruptible. If this is the case, they will be interrupted
102 * and the command will be scheduled.
103 *
104 * @param command the command to schedule
105 */
106 void Schedule(Command* command);
107
108 /**
109 * Schedules multiple commands for execution. Does nothing for commands
110 * already scheduled.
111 *
112 * @param commands the commands to schedule
113 */
114 void Schedule(std::span<Command* const> commands);
115
116 /**
117 * Schedules multiple commands for execution. Does nothing for commands
118 * already scheduled.
119 *
120 * @param commands the commands to schedule
121 */
122 void Schedule(std::initializer_list<Command*> commands);
123
124 /**
125 * Runs a single iteration of the scheduler. The execution occurs in the
126 * following order:
127 *
128 * <p>Subsystem periodic methods are called.
129 *
130 * <p>Button bindings are polled, and new commands are scheduled from them.
131 *
132 * <p>Currently-scheduled commands are executed.
133 *
134 * <p>End conditions are checked on currently-scheduled commands, and commands
135 * that are finished have their end methods called and are removed.
136 *
137 * <p>Any subsystems not being used as requirements have their default methods
138 * started.
139 */
140 void Run();
141
142 /**
143 * Registers subsystems with the scheduler. This must be called for the
144 * subsystem's periodic block to run when the scheduler is run, and for the
145 * subsystem's default command to be scheduled. It is recommended to call
146 * this from the constructor of your subsystem implementations.
147 *
148 * @param subsystem the subsystem to register
149 */
150 void RegisterSubsystem(Subsystem* subsystem);
151
152 /**
153 * Un-registers subsystems with the scheduler. The subsystem will no longer
154 * have its periodic block called, and will not have its default command
155 * scheduled.
156 *
157 * @param subsystem the subsystem to un-register
158 */
160
161 void RegisterSubsystem(std::initializer_list<Subsystem*> subsystems);
162 void RegisterSubsystem(std::span<Subsystem* const> subsystems);
163
164 void UnregisterSubsystem(std::initializer_list<Subsystem*> subsystems);
165 void UnregisterSubsystem(std::span<Subsystem* const> subsystems);
166
167 /**
168 * Sets the default command for a subsystem. Registers that subsystem if it
169 * is not already registered. Default commands will run whenever there is no
170 * other command currently scheduled that requires the subsystem. Default
171 * commands should be written to never end (i.e. their IsFinished() method
172 * should return false), as they would simply be re-scheduled if they do.
173 * Default commands must also require their subsystem.
174 *
175 * @param subsystem the subsystem whose default command will be set
176 * @param defaultCommand the default command to associate with the subsystem
177 */
178 template <class T, typename = std::enable_if_t<std::is_base_of_v<
180 void SetDefaultCommand(Subsystem* subsystem, T&& defaultCommand) {
181 if (!defaultCommand.HasRequirement(subsystem)) {
182 throw FRC_MakeError(frc::err::CommandIllegalUse,
183 "Default commands must require their subsystem!");
184 }
185 SetDefaultCommandImpl(subsystem,
186 std::make_unique<std::remove_reference_t<T>>(
187 std::forward<T>(defaultCommand)));
188 }
189
190 /**
191 * Sets the default command for a subsystem. Registers that subsystem if it
192 * is not already registered. Default commands will run whenever there is no
193 * other command currently scheduled that requires the subsystem. Default
194 * commands should be written to never end (i.e. their IsFinished() method
195 * should return false), as they would simply be re-scheduled if they do.
196 * Default commands must also require their subsystem.
197 *
198 * @param subsystem the subsystem whose default command will be set
199 * @param defaultCommand the default command to associate with the subsystem
200 */
201 void SetDefaultCommand(Subsystem* subsystem, CommandPtr&& defaultCommand);
202
203 /**
204 * Removes the default command for a subsystem. The current default command
205 * will run until another command is scheduled that requires the subsystem, at
206 * which point the current default command will not be re-scheduled.
207 *
208 * @param subsystem the subsystem whose default command will be removed
209 */
211
212 /**
213 * Gets the default command associated with this subsystem. Null if this
214 * subsystem has no default command associated with it.
215 *
216 * @param subsystem the subsystem to inquire about
217 * @return the default command associated with the subsystem
218 */
219 Command* GetDefaultCommand(const Subsystem* subsystem) const;
220
221 /**
222 * Cancels commands. The scheduler will only call Command::End()
223 * method of the canceled command with true, indicating they were
224 * canceled (as opposed to finishing normally).
225 *
226 * <p>Commands will be canceled even if they are not scheduled as
227 * interruptible.
228 *
229 * @param command the command to cancel
230 */
231 void Cancel(Command* command);
232
233 /**
234 * Cancels commands. The scheduler will only call Command::End()
235 * method of the canceled command with true, indicating they were
236 * canceled (as opposed to finishing normally).
237 *
238 * <p>Commands will be canceled even if they are not scheduled as
239 * interruptible.
240 *
241 * @param command the command to cancel
242 */
243 void Cancel(const CommandPtr& command);
244
245 /**
246 * Cancels commands. The scheduler will only call Command::End()
247 * method of the canceled command with true, indicating they were
248 * canceled (as opposed to finishing normally).
249 *
250 * <p>Commands will be canceled even if they are not scheduled as
251 * interruptible.
252 *
253 * @param commands the commands to cancel
254 */
255 void Cancel(std::span<Command* const> commands);
256
257 /**
258 * Cancels commands. The scheduler will only call Command::End()
259 * method of the canceled command with true, indicating they were
260 * canceled (as opposed to finishing normally).
261 *
262 * <p>Commands will be canceled even if they are not scheduled as
263 * interruptible.
264 *
265 * @param commands the commands to cancel
266 */
267 void Cancel(std::initializer_list<Command*> commands);
268
269 /**
270 * Cancels all commands that are currently scheduled.
271 */
272 void CancelAll();
273
274 /**
275 * Whether the given commands are running. Note that this only works on
276 * commands that are directly scheduled by the scheduler; it will not work on
277 * commands inside of CommandGroups, as the scheduler does not see them.
278 *
279 * @param commands the command to query
280 * @return whether the command is currently scheduled
281 */
282 bool IsScheduled(std::span<const Command* const> commands) const;
283
284 /**
285 * Whether the given commands are running. Note that this only works on
286 * commands that are directly scheduled by the scheduler; it will not work on
287 * commands inside of CommandGroups, as the scheduler does not see them.
288 *
289 * @param commands the command to query
290 * @return whether the command is currently scheduled
291 */
292 bool IsScheduled(std::initializer_list<const Command*> commands) const;
293
294 /**
295 * Whether a given command is running. Note that this only works on commands
296 * that are directly scheduled by the scheduler; it will not work on commands
297 * inside of CommandGroups, as the scheduler does not see them.
298 *
299 * @param command the command to query
300 * @return whether the command is currently scheduled
301 */
302 bool IsScheduled(const Command* command) const;
303
304 /**
305 * Whether a given command is running. Note that this only works on commands
306 * that are directly scheduled by the scheduler; it will not work on commands
307 * inside of CommandGroups, as the scheduler does not see them.
308 *
309 * @param command the command to query
310 * @return whether the command is currently scheduled
311 */
312 bool IsScheduled(const CommandPtr& command) const;
313
314 /**
315 * Returns the command currently requiring a given subsystem. Null if no
316 * command is currently requiring the subsystem
317 *
318 * @param subsystem the subsystem to be inquired about
319 * @return the command currently requiring the subsystem
320 */
321 Command* Requiring(const Subsystem* subsystem) const;
322
323 /**
324 * Disables the command scheduler.
325 */
326 void Disable();
327
328 /**
329 * Enables the command scheduler.
330 */
331 void Enable();
332
333 /**
334 * Adds an action to perform on the initialization of any command by the
335 * scheduler.
336 *
337 * @param action the action to perform
338 */
340
341 /**
342 * Adds an action to perform on the execution of any command by the scheduler.
343 *
344 * @param action the action to perform
345 */
347
348 /**
349 * Adds an action to perform on the interruption of any command by the
350 * scheduler.
351 *
352 * @param action the action to perform
353 */
355
356 /**
357 * Adds an action to perform on the finishing of any command by the scheduler.
358 *
359 * @param action the action to perform
360 */
362
363 /**
364 * Requires that the specified command hasn't been already added to a
365 * composition.
366 *
367 * @param command The command to check
368 * @throws if the given commands have already been composed.
369 */
370 void RequireUngrouped(const Command* command);
371
372 /**
373 * Requires that the specified commands not have been already added to a
374 * composition.
375 *
376 * @param commands The commands to check
377 * @throws if the given commands have already been composed.
378 */
379 void RequireUngrouped(std::span<const std::unique_ptr<Command>> commands);
380
381 /**
382 * Requires that the specified commands not have been already added to a
383 * composition.
384 *
385 * @param commands The commands to check
386 * @throws IllegalArgumentException if the given commands have already been
387 * composed.
388 */
389 void RequireUngrouped(std::initializer_list<const Command*> commands);
390
391 void InitSendable(nt::NTSendableBuilder& builder) override;
392
393 private:
394 // Constructor; private as this is a singleton
396
397 void SetDefaultCommandImpl(Subsystem* subsystem,
398 std::unique_ptr<Command> command);
399
400 class Impl;
401 std::unique_ptr<Impl> m_impl;
402
403 frc::Watchdog m_watchdog;
404
405 friend class CommandTestBase;
406
407 template <typename T>
409};
410} // 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:47
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:36
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:405
void RequireUngrouped(const Command *command)
Requires that the specified command hasn't been already added to a composition.
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:408
void Disable()
Disables the command scheduler.
void ClearButtons()
Removes all button bindings from the scheduler.
void Cancel(std::span< Command *const > commands)
Cancels commands.
CommandScheduler(const CommandScheduler &)=delete
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 SetDefaultCommand(Subsystem *subsystem, T &&defaultCommand)
Sets the default command for a subsystem.
Definition: CommandScheduler.h:180
void Cancel(const CommandPtr &command)
Cancels commands.
void Enable()
Enables the command scheduler.
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
typename std::enable_if< B, T >::type enable_if_t
Definition: core.h:298
typename std::remove_reference< T >::type remove_reference_t
Definition: core.h:303
Definition: InstantCommand.h:14
Definition: StdDeque.h:50
#define FRC_MakeError(status, format,...)
Makes a runtime error exception object.
Definition: Errors.h:152