001// Copyright (c) FIRST and other WPILib contributors.
002// Open Source Software; you can modify and/or share it under the terms of
003// the WPILib BSD license file in the root directory of this project.
004
005package org.wpilib.command3;
006
007import static org.wpilib.util.ErrorMessages.requireNonNullParam;
008
009import java.util.Collection;
010import java.util.Collections;
011import java.util.Set;
012import java.util.function.BooleanSupplier;
013import java.util.function.Consumer;
014import org.wpilib.annotation.NoDiscard;
015import org.wpilib.units.measure.Time;
016
017/**
018 * Performs some task using one or more {@link Mechanism mechanisms}. Commands are fundamentally
019 * backed by a {@link Coroutine} that can be used to write imperative code that runs asynchronously.
020 *
021 * <p>Programmers familiar with the earlier versions of the command framework can think of a v3
022 * command similar to a v1 or v2 command that executes the lifecycle methods in a single method, as
023 * demonstrated in the example below. (Note, however, that more sophisticated code than this is
024 * possible!
025 *
026 * <pre>{@code
027 * coroutine -> {
028 *   initialize();
029 *   while (!isFinished()) {
030 *     execute();
031 *     coroutine.yield(); // be sure to yield at the end of the loop
032 *   }
033 *   end();
034 * }
035 * }</pre>
036 *
037 * <p><strong>Note:</strong> Because coroutines are <i>opt-in</i> collaborate constructs, every
038 * command implementation <strong>must</strong> call {@link Coroutine#yield()} within any periodic
039 * loop. Failure to do so may result in an unrecoverable infinite loop.
040 *
041 * <h2>Requirements</h2>
042 *
043 * <p>Commands require zero or more mechanisms. To prevent conflicting control requests from running
044 * simultaneously (for example, commanding an elevator to both raise and lower at the same time), a
045 * running command has <i>exclusive ownership</i> of all of its required mechanisms. If another
046 * command with an equal or greater {@link #priority()} is scheduled that requires one or more of
047 * those same mechanisms, it will interrupt and cancel the running command.
048 *
049 * <p>The recommended way to create a command is using {@link Mechanism#run(Consumer)} or a related
050 * factory method to create commands that require a single mechanism (for example, a command that
051 * drives an elevator up and down or rotates an arm). Commands may be <i>composed</i> into {@link
052 * ParallelGroup parallel groups} and {@link SequentialGroup sequences} to build more complex
053 * behavior out of fundamental building blocks. These built-in compositions will require every
054 * mechanism used by every command in them, even if those commands aren't always running, and thus
055 * can leave certain required mechanisms in an <i>uncommanded</i> state: owned, but not used, this
056 * can lead to mechanisms sagging under gravity or running the previous motor control request they
057 * were given.
058 *
059 * <h2>Advanced Usage</h2>
060 *
061 * <p>For example, a hypothetical drive-and-score sequence could be coded in two ways: one with a
062 * sequence chain, or one that uses the lower-level coroutine API. Coroutines can be used in an
063 * async/await style that you may be familiar with from languages like JavaScript, Python, or C#
064 * (note that there is no {@code async} keyword; commands are inherently asynchronous). Nested
065 * commands may be forked and awaited, but will not outlive the command that forked them; there is
066 * no analog for something like a {@code ScheduleCommand} from the v2 commands framework.
067 *
068 * <pre>{@code
069 * class Robot extends TimedRobot {
070 *   private final Drivetrain drivetrain = new Drivetrain();
071 *   private final Elevator elevator = new Elevator();
072 *   private final Gripper gripper = new Gripper();
073 *
074 *  // Basic sequence builder - owns all 3 mechanisms for the full duration,
075 *  // even when they're not being used
076 *  private Command basicScoringSequence() {
077 *     return drivetrain.driveToScoringLocation()
078 *       .andThen(elevator.moveToScoringHeight())
079 *       .andThen(gripper.release())
080 *       .named("Scoring Sequence (Basic)");
081 *   }
082 *
083 *   // Advanced sequence with async/await - only owns mechanisms while they're
084 *   // being used, allowing default commands or other user-triggered commands
085 *   // to run when not in use. Interrupting one of the inner commands while it's
086 *   // running will cancel the entire sequence.
087 *   private Command advancedScoringSequence() {
088 *     return Command.noRequirements(coroutine -> {
089 *       coroutine.await(drivetrain.driveToScoringLocation());
090 *       coroutine.await(elevator.moveToScoringHeight());
091 *       coroutine.await(gripper.release());
092 *     }).named("Scoring Sequence (Advanced)");
093 *   }
094 * }
095 * }</pre>
096 */
097@NoDiscard("Commands must be used! Did you mean to fork it or bind it to a trigger?")
098public interface Command {
099  /** The default command priority. */
100  int DEFAULT_PRIORITY = 0;
101
102  /**
103   * The lowest possible command priority. Commands with the lowest priority can be interrupted by
104   * any other command, including other minimum-priority commands.
105   */
106  int LOWEST_PRIORITY = Integer.MIN_VALUE;
107
108  /**
109   * The highest possible command priority. Commands with the highest priority can only be
110   * interrupted by other maximum-priority commands.
111   */
112  int HIGHEST_PRIORITY = Integer.MAX_VALUE;
113
114  /**
115   * Runs the command. Commands that need to periodically run until a goal state is reached should
116   * simply run a while loop like {@code while (!atGoal()) { ... } } and call {@link
117   * Coroutine#yield()} at the end of the loop.
118   *
119   * <p><strong>Warning:</strong> any loops in a command must call {@code coroutine.yield()}.
120   * Failure to do so will prevent anything else in your robot code from running. Commands are
121   * <i>opt-in</i> collaborative constructs; don't be greedy!
122   *
123   * @param coroutine the coroutine backing the command's execution
124   */
125  void run(Coroutine coroutine);
126
127  /**
128   * An optional lifecycle hook that can be implemented to execute some code whenever this command
129   * is canceled before it naturally completes. Commands should be careful to do a single-shot
130   * cleanup (for example, setting a motor to zero volts) and not do any complex looping logic here.
131   */
132  default void onCancel() {
133    // NOP by default
134  }
135
136  /**
137   * The name of the command.
138   *
139   * @return the name of the command
140   */
141  @NoDiscard
142  String name();
143
144  /**
145   * The mechanisms required by the command. This is used by the scheduler to determine if two
146   * commands conflict with each other. No mechanism may be required by more than one running
147   * command at a time.
148   *
149   * @return the set of mechanisms required by the command
150   */
151  @NoDiscard
152  Set<Mechanism> requirements();
153
154  /**
155   * The priority of the command. If a command is scheduled that conflicts with another running or
156   * pending command, their priority values are compared to determine which should run. If the
157   * scheduled command is lower priority than the running command, then it will not be scheduled and
158   * the running command will continue to run. If it is the same or higher priority, then the
159   * running command will be canceled and the scheduled command will start to run.
160   *
161   * @return the priority of the command
162   */
163  @NoDiscard
164  default int priority() {
165    return DEFAULT_PRIORITY;
166  }
167
168  /**
169   * Checks if this command has a lower {@link #priority() priority} than another command.
170   *
171   * @param other the command to compare with
172   * @return true if this command has a lower priority than the other one, false otherwise
173   */
174  @NoDiscard
175  default boolean isLowerPriorityThan(Command other) {
176    requireNonNullParam(other, "other", "Command.isLowerPriorityThan");
177
178    return priority() < other.priority();
179  }
180
181  /**
182   * Checks if this command requires a particular mechanism.
183   *
184   * @param mechanism the mechanism to check
185   * @return true if the mechanism is required, false if not
186   */
187  @NoDiscard
188  default boolean requires(Mechanism mechanism) {
189    return requirements().contains(mechanism);
190  }
191
192  /**
193   * Checks if this command conflicts with another command.
194   *
195   * @param other the commands to check against
196   * @return true if both commands require at least one of the same mechanism, false if both
197   *     commands have completely different requirements
198   */
199  @NoDiscard
200  default boolean conflictsWith(Command other) {
201    requireNonNullParam(other, "other", "Command.conflictsWith");
202
203    return !Collections.disjoint(requirements(), other.requirements());
204  }
205
206  /**
207   * Creates a new command that runs this one for a maximum duration, after which it is forcibly
208   * canceled. This is particularly useful for autonomous routines where you want to prevent your
209   * entire autonomous period spent stuck on a single action because a mechanism doesn't quite reach
210   * its setpoint (for example, spinning up a flywheel or driving to a particular location on the
211   * field). The resulting command will have the same name as this one, with the timeout period
212   * appended.
213   *
214   * @param timeout the maximum duration that the command is permitted to run. Negative or zero
215   *     values will result in the command running only once before being canceled.
216   * @return the timed out command.
217   */
218  default Command withTimeout(Time timeout) {
219    requireNonNullParam(timeout, "timeout", "Command.withTimeout");
220
221    return race(this, waitFor(timeout).named("Timeout: " + timeout.toLongString()))
222        .named(name() + " [" + timeout.toLongString() + " timeout]");
223  }
224
225  /**
226   * Creates a command that does not require any hardware; that is, it does not affect the state of
227   * any physical objects. This is useful for commands that do some cleanup or state management,
228   * such as resetting odometry or sensors, that you don't want to interrupt a command that's
229   * controlling the mechanisms it affects, or for a command composition that you don't want to
230   * inherit the requirements of its child commands.
231   *
232   * <p>More configuration options are needed after calling this function before the command can be
233   * created. See {@link StagedCommandBuilder} for details.
234   *
235   * @param body The command's body. Cannot be null.
236   * @return a builder that can be used to configure the resulting command
237   */
238  static NeedsNameBuilderStage noRequirements(Consumer<Coroutine> body) {
239    return new StagedCommandBuilder().noRequirements().executing(body);
240  }
241
242  /**
243   * Creates a command that requires one or more mechanisms.
244   *
245   * <p>More configuration options are needed after calling this function before the command can be
246   * created. See {@link StagedCommandBuilder} for details.
247   *
248   * @param requirement The first required mechanism
249   * @param rest Any other required mechanisms
250   * @return A command builder
251   */
252  static NeedsExecutionBuilderStage requiring(Mechanism requirement, Mechanism... rest) {
253    // parameters will be null checked by the builder
254    return new StagedCommandBuilder().requiring(requirement, rest);
255  }
256
257  /**
258   * Creates command that requires some number of mechanisms.
259   *
260   * <p>More configuration options are needed after calling this function before the command can be
261   * created. See {@link StagedCommandBuilder} for details.
262   *
263   * @param requirements The required mechanisms. May be empty, but cannot contain null values.
264   * @return A command builder
265   */
266  static NeedsExecutionBuilderStage requiring(Collection<Mechanism> requirements) {
267    // parameters will be null checked by the builder
268    return new StagedCommandBuilder().requiring(requirements);
269  }
270
271  /**
272   * Starts creating a command that runs a group of multiple commands in parallel. The command will
273   * complete when every command in the group has completed naturally.
274   *
275   * <p>More configuration options are needed after calling this function before the command can be
276   * created. See {@link ParallelGroupBuilder} for details.
277   *
278   * @param commands The commands to run in parallel
279   * @return A command builder
280   */
281  static ParallelGroupBuilder parallel(Command... commands) {
282    // parameters will be null checked by the builder
283    return new ParallelGroupBuilder().requiring(commands);
284  }
285
286  /**
287   * Starts creating a command that runs a group of multiple commands in parallel. The command will
288   * complete when any command in the group has completed naturally; all other commands in the group
289   * will be canceled.
290   *
291   * <p>More configuration options are needed after calling this function before the command can be
292   * created. See {@link ParallelGroupBuilder} for details.
293   *
294   * @param commands The commands to run in parallel
295   * @return A command builder
296   */
297  static ParallelGroupBuilder race(Command... commands) {
298    // parameters will be null checked by the builder
299    return new ParallelGroupBuilder().optional(commands);
300  }
301
302  /**
303   * Starts creating a command that runs a group of multiple commands in sequence. The command will
304   * complete when the last command in the group has completed naturally. Commands in the group will
305   * run in the order they're passed to this method.
306   *
307   * <p>More configuration options are needed after calling this function before the command can be
308   * created. See {@link SequentialGroupBuilder} for details.
309   *
310   * @param commands The commands to run in sequence.
311   * @return A command builder
312   */
313  static SequentialGroupBuilder sequence(Command... commands) {
314    // parameters will be null checked by the builder
315    return new SequentialGroupBuilder().andThen(commands);
316  }
317
318  /**
319   * Starts creating a command that simply waits for some condition to be met. The command will not
320   * require any mechanisms.
321   *
322   * <p>More configuration options are needed after calling this function before the command can be
323   * created. See {@link StagedCommandBuilder} for details.
324   *
325   * @param condition The condition to wait for
326   * @return A command builder
327   */
328  static NeedsNameBuilderStage waitUntil(BooleanSupplier condition) {
329    requireNonNullParam(condition, "condition", "Command.waitUntil");
330
331    return noRequirements(coroutine -> coroutine.waitUntil(condition));
332  }
333
334  /**
335   * Creates a command that simply waits for a given duration. The command will not require any
336   * mechanisms.
337   *
338   * @param duration How long to wait
339   * @return A command builder
340   */
341  static NeedsNameBuilderStage waitFor(Time duration) {
342    requireNonNullParam(duration, "duration", "Command.waitFor");
343
344    return noRequirements(coroutine -> coroutine.wait(duration));
345  }
346
347  /**
348   * Creates a command that runs this one and ends when the end condition is met (if this command
349   * has not already exited by then).
350   *
351   * <p>More configuration options are needed after calling this function before the command can be
352   * created. See {@link ParallelGroupBuilder} for details.
353   *
354   * @param endCondition The end condition to wait for.
355   * @return The waiting command
356   */
357  default ParallelGroupBuilder until(BooleanSupplier endCondition) {
358    requireNonNullParam(endCondition, "endCondition", "Command.until");
359
360    return new ParallelGroupBuilder()
361        .optional(this, Command.waitUntil(endCondition).named("Until Condition"));
362  }
363
364  /**
365   * Creates a command sequence, starting from this command and then running the next one. More
366   * commands can be added with the builder before naming and creating the sequence.
367   *
368   * <pre>{@code
369   * Sequence aThenBThenC =
370   *   commandA()
371   *     .andThen(commandB())
372   *     .andThen(commandC())
373   *     .withAutomaticName();
374   * }</pre>
375   *
376   * @param next The command to run after this one in the sequence
377   * @return A sequence builder
378   */
379  default SequentialGroupBuilder andThen(Command next) {
380    // parameter will be null checked by the builder
381    return new SequentialGroupBuilder().andThen(this).andThen(next);
382  }
383
384  /**
385   * Creates a parallel command group, running this command alongside one or more other commands.
386   * The group will exit once every command has finished.
387   *
388   * <p>More configuration options are needed after calling this function before the command can be
389   * created. See {@link ParallelGroupBuilder} for details.
390   *
391   * <pre>{@code
392   * ParallelGroup abc =
393   *   commandA()
394   *     .alongWith(commandB(), commandC())
395   *     .withAutomaticName();
396   * }</pre>
397   *
398   * @param parallel The commands to run in parallel with this one
399   * @return A parallel group builder
400   */
401  default ParallelGroupBuilder alongWith(Command... parallel) {
402    return new ParallelGroupBuilder().requiring(this).requiring(parallel);
403  }
404
405  /**
406   * Creates a parallel command group, running this command alongside one or more other commands.
407   * The group will exit after any command finishes.
408   *
409   * <p>More configuration options are needed after calling this function before the command can be
410   * created. See {@link ParallelGroupBuilder} for details.
411   *
412   * @param parallel The commands to run in parallel with this one
413   * @return A parallel group builder
414   */
415  default ParallelGroupBuilder raceWith(Command... parallel) {
416    return new ParallelGroupBuilder().optional(this).optional(parallel);
417  }
418}