WPILibC++ 2023.4.3
Command.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 <functional>
8#include <initializer_list>
9#include <memory>
10#include <span>
11#include <string>
12
13#include <units/time.h>
14#include <wpi/Demangle.h>
15#include <wpi/SmallSet.h>
16#include <wpi/deprecated.h>
17
19
20namespace frc2 {
21
22template <typename T>
23std::string GetTypeName(const T& type) {
24 return wpi::Demangle(typeid(type).name());
25}
26
27class PerpetualCommand;
28
29/**
30 * A state machine representing a complete action to be performed by the robot.
31 * Commands are run by the CommandScheduler, and can be composed into
32 * CommandGroups to allow users to build complicated multi-step actions without
33 * the need to roll the state machine logic themselves.
34 *
35 * <p>Commands are run synchronously from the main robot loop; no
36 * multithreading is used, unless specified explicitly from the command
37 * implementation.
38 *
39 * <p>Note: ALWAYS create a subclass by extending CommandHelper<Base, Subclass>,
40 * or decorators will not function!
41 *
42 * This class is provided by the NewCommands VendorDep
43 *
44 * @see CommandScheduler
45 * @see CommandHelper
46 */
47class Command {
48 public:
49 Command() = default;
50 virtual ~Command();
51
52 Command(const Command&) = default;
54 Command(Command&&) = default;
55 Command& operator=(Command&&) = default;
56
57 /**
58 * The initial subroutine of a command. Called once when the command is
59 * initially scheduled.
60 */
61 virtual void Initialize();
62
63 /**
64 * The main body of a command. Called repeatedly while the command is
65 * scheduled.
66 */
67 virtual void Execute();
68
69 /**
70 * The action to take when the command ends. Called when either the command
71 * finishes normally, or when it interrupted/canceled.
72 *
73 * @param interrupted whether the command was interrupted/canceled
74 */
75 virtual void End(bool interrupted);
76
77 /**
78 * Whether the command has finished. Once a command finishes, the scheduler
79 * will call its end() method and un-schedule it.
80 *
81 * @return whether the command has finished.
82 */
83 virtual bool IsFinished() { return false; }
84
85 /**
86 * Specifies the set of subsystems used by this command. Two commands cannot
87 * use the same subsystem at the same time. If another command is scheduled
88 * that shares a requirement, GetInterruptionBehavior() will be checked and
89 * followed. If no subsystems are required, return an empty set.
90 *
91 * <p>Note: it is recommended that user implementations contain the
92 * requirements as a field, and return that field here, rather than allocating
93 * a new set every time this is called.
94 *
95 * @return the set of subsystems that are required
96 * @see InterruptionBehavior
97 */
99
100 /**
101 * An enum describing the command's behavior when another command with a
102 * shared requirement is scheduled.
103 */
105 /**
106 * This command ends, End(true) is called, and the incoming command is
107 * scheduled normally.
108 *
109 * <p>This is the default behavior.
110 */
111 kCancelSelf,
112 /** This command continues, and the incoming command is not scheduled. */
113 kCancelIncoming
114 };
115
116 friend class CommandPtr;
117
118 /**
119 * Decorates this command with a timeout. If the specified timeout is
120 * exceeded before the command finishes normally, the command will be
121 * interrupted and un-scheduled. Note that the timeout only applies to the
122 * command returned by this method; the calling command is not itself changed.
123 *
124 * @param duration the timeout duration
125 * @return the command with the timeout added
126 */
127 [[nodiscard]] CommandPtr WithTimeout(units::second_t duration) &&;
128
129 /**
130 * Decorates this command with an interrupt condition. If the specified
131 * condition becomes true before the command finishes normally, the command
132 * will be interrupted and un-scheduled. Note that this only applies to the
133 * command returned by this method; the calling command is not itself changed.
134 *
135 * @param condition the interrupt condition
136 * @return the command with the interrupt condition added
137 */
138 [[nodiscard]] CommandPtr Until(std::function<bool()> condition) &&;
139
140 /**
141 * Decorates this command with an interrupt condition. If the specified
142 * condition becomes true before the command finishes normally, the command
143 * will be interrupted and un-scheduled. Note that this only applies to the
144 * command returned by this method; the calling command is not itself changed.
145 *
146 * @param condition the interrupt condition
147 * @return the command with the interrupt condition added
148 * @deprecated Replace with Until()
149 */
150 WPI_DEPRECATED("Replace with Until()")
151 [[nodiscard]] CommandPtr WithInterrupt(std::function<bool()> condition) &&;
152
153 /**
154 * Decorates this command with a runnable to run before this command starts.
155 *
156 * @param toRun the Runnable to run
157 * @param requirements the required subsystems
158 * @return the decorated command
159 */
161 std::function<void()> toRun,
162 std::initializer_list<Subsystem*> requirements) &&;
163
164 /**
165 * Decorates this command with a runnable to run before this command starts.
166 *
167 * @param toRun the Runnable to run
168 * @param requirements the required subsystems
169 * @return the decorated command
170 */
172 std::function<void()> toRun,
173 std::span<Subsystem* const> requirements = {}) &&;
174
175 /**
176 * Decorates this command with a runnable to run after the command finishes.
177 *
178 * @param toRun the Runnable to run
179 * @param requirements the required subsystems
180 * @return the decorated command
181 */
182 [[nodiscard]] CommandPtr AndThen(
183 std::function<void()> toRun,
184 std::initializer_list<Subsystem*> requirements) &&;
185
186 /**
187 * Decorates this command with a runnable to run after the command finishes.
188 *
189 * @param toRun the Runnable to run
190 * @param requirements the required subsystems
191 * @return the decorated command
192 */
193 [[nodiscard]] CommandPtr AndThen(
194 std::function<void()> toRun,
195 std::span<Subsystem* const> requirements = {}) &&;
196
197 /**
198 * Decorates this command to run perpetually, ignoring its ordinary end
199 * conditions. The decorated command can still be interrupted or canceled.
200 *
201 * @return the decorated command
202 * @deprecated PerpetualCommand violates the assumption that execute() doesn't
203get called after isFinished() returns true -- an assumption that should be
204valid. This was unsafe/undefined behavior from the start, and RepeatCommand
205provides an easy way to achieve similar end results with slightly different (and
206safe) semantics.
207 */
208 WPI_DEPRECATED(
209 "PerpetualCommand violates the assumption that execute() doesn't get "
210 "called after isFinished() returns true -- an assumption that should be "
211 "valid."
212 "This was unsafe/undefined behavior from the start, and RepeatCommand "
213 "provides an easy way to achieve similar end results with slightly "
214 "different (and safe) semantics.")
216
217 /**
218 * Decorates this command to run repeatedly, restarting it when it ends, until
219 * this command is interrupted. The decorated command can still be canceled.
220 *
221 * @return the decorated command
222 */
223 [[nodiscard]] CommandPtr Repeatedly() &&;
224
225 /**
226 * Decorates this command to run "by proxy" by wrapping it in a
227 * ProxyCommand. This is useful for "forking off" from command groups
228 * when the user does not wish to extend the command's requirements to the
229 * entire command group.
230 *
231 * <p>This overload transfers command ownership to the returned CommandPtr.
232 *
233 * @return the decorated command
234 */
235 [[nodiscard]] CommandPtr AsProxy() &&;
236
237 /**
238 * Decorates this command to only run if this condition is not met. If the
239 * command is already running and the condition changes to true, the command
240 * will not stop running. The requirements of this command will be kept for
241 * the new conditional command.
242 *
243 * @param condition the condition that will prevent the command from running
244 * @return the decorated command
245 */
246 [[nodiscard]] CommandPtr Unless(std::function<bool()> condition) &&;
247
248 /**
249 * Decorates this command to run or stop when disabled.
250 *
251 * @param doesRunWhenDisabled true to run when disabled.
252 * @return the decorated command
253 */
254 [[nodiscard]] CommandPtr IgnoringDisable(bool doesRunWhenDisabled) &&;
255
256 /**
257 * Decorates this command to run or stop when disabled.
258 *
259 * @param interruptBehavior true to run when disabled.
260 * @return the decorated command
261 */
263 Command::InterruptionBehavior interruptBehavior) &&;
264
265 /**
266 * Decorates this command with a lambda to call on interrupt or end, following
267 * the command's inherent Command::End(bool) method.
268 *
269 * @param end a lambda accepting a boolean parameter specifying whether the
270 * command was interrupted.
271 * @return the decorated command
272 */
273 [[nodiscard]] CommandPtr FinallyDo(std::function<void(bool)> end) &&;
274
275 /**
276 * Decorates this command with a lambda to call on interrupt, following the
277 * command's inherent Command::End(bool) method.
278 *
279 * @param handler a lambda to run when the command is interrupted
280 * @return the decorated command
281 */
282 [[nodiscard]] CommandPtr HandleInterrupt(std::function<void()> handler) &&;
283
284 /**
285 * Decorates this Command with a name.
286 *
287 * @param name name
288 * @return the decorated Command
289 */
291
292 /**
293 * Schedules this command.
294 */
295 void Schedule();
296
297 /**
298 * Cancels this command. Will call End(true). Commands will be canceled
299 * regardless of interruption behavior.
300 */
301 void Cancel();
302
303 /**
304 * Whether or not the command is currently scheduled. Note that this does not
305 * detect whether the command is in a composition, only whether it is directly
306 * being run by the scheduler.
307 *
308 * @return Whether the command is scheduled.
309 */
310 bool IsScheduled() const;
311
312 /**
313 * Whether the command requires a given subsystem. Named "HasRequirement"
314 * rather than "requires" to avoid confusion with Command::Requires(Subsystem)
315 * -- this may be able to be changed in a few years.
316 *
317 * @param requirement the subsystem to inquire about
318 * @return whether the subsystem is required
319 */
320 bool HasRequirement(Subsystem* requirement) const;
321
322 /**
323 * Whether the command is currently grouped in a command group. Used as extra
324 * insurance to prevent accidental independent use of grouped commands.
325 */
326 bool IsComposed() const;
327
328 /**
329 * Sets whether the command is currently composed in a command composition.
330 * Can be used to "reclaim" a command if a composition is no longer going to
331 * use it. NOT ADVISED!
332 */
333 void SetComposed(bool isComposed);
334
335 /**
336 * Whether the command is currently grouped in a command group. Used as extra
337 * insurance to prevent accidental independent use of grouped commands.
338 *
339 * @deprecated Moved to IsComposed()
340 */
341 WPI_DEPRECATED("Moved to IsComposed()")
342 bool IsGrouped() const;
343
344 /**
345 * Sets whether the command is currently grouped in a command group. Can be
346 * used to "reclaim" a command if a group is no longer going to use it. NOT
347 * ADVISED!
348 *
349 * @deprecated Moved to SetComposed()
350 */
351 WPI_DEPRECATED("Moved to SetComposed()")
352 void SetGrouped(bool grouped);
353
354 /**
355 * Whether the given command should run when the robot is disabled. Override
356 * to return true if the command should run when disabled.
357 *
358 * @return whether the command should run when the robot is disabled
359 */
360 virtual bool RunsWhenDisabled() const { return false; }
361
362 /**
363 * How the command behaves when another command with a shared requirement is
364 * scheduled.
365 *
366 * @return a variant of InterruptionBehavior, defaulting to kCancelSelf.
367 */
370 }
371
372 /**
373 * Gets the name of this Command. Defaults to the simple class name if not
374 * overridden.
375 *
376 * @return The display name of the Command
377 */
378 virtual std::string GetName() const;
379
380 /**
381 * Sets the name of this Command. Nullop if not overridden.
382 *
383 * @param name The display name of the Command.
384 */
386
387 /**
388 * Transfers ownership of this command to a unique pointer. Used for
389 * decorator methods.
390 */
391 virtual CommandPtr ToPtr() && = 0;
392
393 protected:
394 /**
395 * Transfers ownership of this command to a unique pointer. Used for
396 * decorator methods.
397 */
398 virtual std::unique_ptr<Command> TransferOwnership() && = 0;
399
400 bool m_isComposed = false;
401};
402
403/**
404 * Checks if two commands have disjoint requirement sets.
405 *
406 * @param first The first command to check.
407 * @param second The second command to check.
408 * @return False if first and second share a requirement.
409 */
411} // namespace frc2
This file defines the SmallSet class.
A state machine representing a complete action to be performed by the robot.
Definition: Command.h:47
bool IsScheduled() const
Whether or not the command is currently scheduled.
void Cancel()
Cancels this command.
CommandPtr AsProxy() &&
Decorates this command to run "by proxy" by wrapping it in a ProxyCommand.
virtual void End(bool interrupted)
The action to take when the command ends.
Command(Command &&)=default
CommandPtr HandleInterrupt(std::function< void()> handler) &&
Decorates this command with a lambda to call on interrupt, following the command's inherent Command::...
CommandPtr WithTimeout(units::second_t duration) &&
Decorates this command with a timeout.
CommandPtr WithInterrupt(std::function< bool()> condition) &&
Decorates this command with an interrupt condition.
CommandPtr BeforeStarting(std::function< void()> toRun, std::initializer_list< Subsystem * > requirements) &&
Decorates this command with a runnable to run before this command starts.
virtual ~Command()
virtual std::string GetName() const
Gets the name of this Command.
virtual wpi::SmallSet< Subsystem *, 4 > GetRequirements() const =0
Specifies the set of subsystems used by this command.
CommandPtr Repeatedly() &&
Decorates this command to run repeatedly, restarting it when it ends, until this command is interrupt...
virtual bool RunsWhenDisabled() const
Whether the given command should run when the robot is disabled.
Definition: Command.h:360
CommandPtr WithInterruptBehavior(Command::InterruptionBehavior interruptBehavior) &&
Decorates this command to run or stop when disabled.
CommandPtr FinallyDo(std::function< void(bool)> end) &&
Decorates this command with a lambda to call on interrupt or end, following the command's inherent Co...
CommandPtr WithName(std::string_view name) &&
Decorates this Command with a name.
bool IsComposed() const
Whether the command is currently grouped in a command group.
bool m_isComposed
Definition: Command.h:400
Command(const Command &)=default
CommandPtr BeforeStarting(std::function< void()> toRun, std::span< Subsystem *const > requirements={}) &&
Decorates this command with a runnable to run before this command starts.
CommandPtr Until(std::function< bool()> condition) &&
Decorates this command with an interrupt condition.
CommandPtr AndThen(std::function< void()> toRun, std::span< Subsystem *const > requirements={}) &&
Decorates this command with a runnable to run after the command finishes.
Command()=default
virtual void Execute()
The main body of a command.
bool IsGrouped() const
Whether the command is currently grouped in a command group.
void SetGrouped(bool grouped)
Sets whether the command is currently grouped in a command group.
CommandPtr AndThen(std::function< void()> toRun, std::initializer_list< Subsystem * > requirements) &&
Decorates this command with a runnable to run after the command finishes.
Command & operator=(const Command &rhs)
virtual void SetName(std::string_view name)
Sets the name of this Command.
virtual InterruptionBehavior GetInterruptionBehavior() const
How the command behaves when another command with a shared requirement is scheduled.
Definition: Command.h:368
PerpetualCommand Perpetually() &&
virtual CommandPtr ToPtr() &&=0
Transfers ownership of this command to a unique pointer.
CommandPtr IgnoringDisable(bool doesRunWhenDisabled) &&
Decorates this command to run or stop when disabled.
void SetComposed(bool isComposed)
Sets whether the command is currently composed in a command composition.
bool HasRequirement(Subsystem *requirement) const
Whether the command requires a given subsystem.
virtual void Initialize()
The initial subroutine of a command.
void Schedule()
Schedules this command.
InterruptionBehavior
An enum describing the command's behavior when another command with a shared requirement is scheduled...
Definition: Command.h:104
@ kCancelSelf
This command ends, End(true) is called, and the incoming command is scheduled normally.
Command & operator=(Command &&)=default
virtual std::unique_ptr< Command > TransferOwnership() &&=0
Transfers ownership of this command to a unique pointer.
virtual bool IsFinished()
Whether the command has finished.
Definition: Command.h:83
CommandPtr Unless(std::function< bool()> condition) &&
Decorates this command to only run if this condition is not met.
A wrapper around std::unique_ptr<Command> so commands have move-only semantics.
Definition: CommandPtr.h:28
A command that runs another command in perpetuity, ignoring that command's end conditions.
Definition: PerpetualCommand.h:37
A robot subsystem.
Definition: Subsystem.h:39
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
Definition: SmallSet.h:135
basic_string_view< char > string_view
Definition: core.h:520
type
Definition: core.h:575
EIGEN_CONSTEXPR Index first(const T &x) EIGEN_NOEXCEPT
Definition: IndexedViewHelper.h:81
static EIGEN_DEPRECATED const end_t end
Definition: IndexedViewHelper.h:181
Definition: InstantCommand.h:14
std::string GetTypeName(const T &type)
Definition: Command.h:23
bool RequirementsDisjoint(Command *first, Command *second)
Checks if two commands have disjoint requirement sets.
Definition: StdDeque.h:50
std::string Demangle(std::string_view mangledSymbol)
Demangle a C++ symbol.