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.command2;
006
007import static org.wpilib.units.Units.Seconds;
008import static org.wpilib.util.ErrorMessages.requireNonNullParam;
009
010import java.util.Collection;
011import java.util.HashSet;
012import java.util.Set;
013import java.util.function.BooleanSupplier;
014import org.wpilib.annotation.NoDiscard;
015import org.wpilib.units.measure.Time;
016import org.wpilib.util.function.BooleanConsumer;
017import org.wpilib.util.sendable.Sendable;
018import org.wpilib.util.sendable.SendableBuilder;
019import org.wpilib.util.sendable.SendableRegistry;
020
021/**
022 * A state machine representing a complete action to be performed by the robot. Commands are run by
023 * the {@link CommandScheduler}, and can be composed into CommandGroups to allow users to build
024 * complicated multistep actions without the need to roll the state machine logic themselves.
025 *
026 * <p>Commands are run synchronously from the main robot loop; no multithreading is used, unless
027 * specified explicitly from the command implementation.
028 *
029 * <p>This class is provided by the Commands v2 VendorDep
030 */
031@NoDiscard("Commands must be used! Did you mean to bind it to a trigger?")
032public abstract class Command implements Sendable {
033  /** Requirements set. */
034  private final Set<Subsystem> m_requirements = new HashSet<>();
035
036  /** Default constructor. */
037  @SuppressWarnings("this-escape")
038  protected Command() {
039    String name = getClass().getName();
040    SendableRegistry.add(this, name.substring(name.lastIndexOf('.') + 1));
041  }
042
043  /** The initial subroutine of a command. Called once when the command is initially scheduled. */
044  public void initialize() {}
045
046  /** The main body of a command. Called repeatedly while the command is scheduled. */
047  public void execute() {}
048
049  /**
050   * The action to take when the command ends. Called when either the command finishes normally, or
051   * when it interrupted/canceled.
052   *
053   * <p>Do not schedule commands here that share requirements with this command. Use {@link
054   * #andThen(Command...)} instead.
055   *
056   * @param interrupted whether the command was interrupted/canceled
057   */
058  public void end(boolean interrupted) {}
059
060  /**
061   * Whether the command has finished. Once a command finishes, the scheduler will call its end()
062   * method and un-schedule it.
063   *
064   * @return whether the command has finished.
065   */
066  public boolean isFinished() {
067    return false;
068  }
069
070  /**
071   * Specifies the set of subsystems used by this command. Two commands cannot use the same
072   * subsystem at the same time. If another command is scheduled that shares a requirement, {@link
073   * #getInterruptionBehavior()} will be checked and followed. If no subsystems are required, return
074   * an empty set.
075   *
076   * <p>Note: it is recommended that user implementations contain the requirements as a field, and
077   * return that field here, rather than allocating a new set every time this is called.
078   *
079   * @return the set of subsystems that are required
080   * @see InterruptionBehavior
081   */
082  public Set<Subsystem> getRequirements() {
083    return m_requirements;
084  }
085
086  /**
087   * Adds the specified subsystems to the requirements of the command. The scheduler will prevent
088   * two commands that require the same subsystem from being scheduled simultaneously.
089   *
090   * <p>Note that the scheduler determines the requirements of a command when it is scheduled, so
091   * this method should normally be called from the command's constructor.
092   *
093   * @param requirements the requirements to add
094   */
095  public final void addRequirements(Subsystem... requirements) {
096    for (Subsystem requirement : requirements) {
097      m_requirements.add(requireNonNullParam(requirement, "requirement", "addRequirements"));
098    }
099  }
100
101  /**
102   * Adds the specified subsystems to the requirements of the command. The scheduler will prevent
103   * two commands that require the same subsystem from being scheduled simultaneously.
104   *
105   * <p>Note that the scheduler determines the requirements of a command when it is scheduled, so
106   * this method should normally be called from the command's constructor.
107   *
108   * @param requirements the requirements to add
109   */
110  public final void addRequirements(Collection<Subsystem> requirements) {
111    m_requirements.addAll(requirements);
112  }
113
114  /**
115   * Gets the name of this Command.
116   *
117   * <p>By default, the simple class name is used. This can be changed with {@link
118   * #setName(String)}.
119   *
120   * @return The display name of the Command
121   */
122  public String getName() {
123    return SendableRegistry.getName(this);
124  }
125
126  /**
127   * Sets the name of this Command.
128   *
129   * @param name The display name of the Command.
130   */
131  public void setName(String name) {
132    SendableRegistry.setName(this, name);
133  }
134
135  /**
136   * Gets the subsystem name of this Command.
137   *
138   * @return Subsystem name
139   */
140  public String getSubsystem() {
141    return SendableRegistry.getSubsystem(this);
142  }
143
144  /**
145   * Sets the subsystem name of this Command.
146   *
147   * @param subsystem subsystem name
148   */
149  public void setSubsystem(String subsystem) {
150    SendableRegistry.setSubsystem(this, subsystem);
151  }
152
153  /**
154   * Decorates this command with a timeout. If the specified timeout is exceeded before the command
155   * finishes normally, the command will be interrupted and un-scheduled.
156   *
157   * <p>Note: This decorator works by adding this command to a composition. The command the
158   * decorator was called on cannot be scheduled independently or be added to a different
159   * composition (namely, decorators), unless it is manually cleared from the list of composed
160   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
161   * returned from this method can be further decorated without issue.
162   *
163   * @param seconds the timeout duration
164   * @return the command with the timeout added
165   */
166  public ParallelRaceGroup withTimeout(double seconds) {
167    return raceWith(new WaitCommand(seconds));
168  }
169
170  /**
171   * Decorates this command with a timeout. If the specified timeout is exceeded before the command
172   * finishes normally, the command will be interrupted and un-scheduled.
173   *
174   * <p>Note: This decorator works by adding this command to a composition. The command the
175   * decorator was called on cannot be scheduled independently or be added to a different
176   * composition (namely, decorators), unless it is manually cleared from the list of composed
177   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
178   * returned from this method can be further decorated without issue.
179   *
180   * @param time the timeout duration
181   * @return the command with the timeout added
182   */
183  public ParallelRaceGroup withTimeout(Time time) {
184    return withTimeout(time.in(Seconds));
185  }
186
187  /**
188   * Decorates this command with an interrupt condition. If the specified condition becomes true
189   * before the command finishes normally, the command will be interrupted and un-scheduled.
190   *
191   * <p>Note: This decorator works by adding this command to a composition. The command the
192   * decorator was called on cannot be scheduled independently or be added to a different
193   * composition (namely, decorators), unless it is manually cleared from the list of composed
194   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
195   * returned from this method can be further decorated without issue.
196   *
197   * @param condition the interrupt condition
198   * @return the command with the interrupt condition added
199   * @see #onlyWhile(BooleanSupplier)
200   */
201  public ParallelRaceGroup until(BooleanSupplier condition) {
202    return raceWith(new WaitUntilCommand(condition));
203  }
204
205  /**
206   * Decorates this command with a run condition. If the specified condition becomes false before
207   * the command finishes normally, the command will be interrupted and un-scheduled.
208   *
209   * <p>Note: This decorator works by adding this command to a composition. The command the
210   * decorator was called on cannot be scheduled independently or be added to a different
211   * composition (namely, decorators), unless it is manually cleared from the list of composed
212   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
213   * returned from this method can be further decorated without issue.
214   *
215   * @param condition the run condition
216   * @return the command with the run condition added
217   * @see #until(BooleanSupplier)
218   */
219  public ParallelRaceGroup onlyWhile(BooleanSupplier condition) {
220    return until(() -> !condition.getAsBoolean());
221  }
222
223  /**
224   * Decorates this command with a runnable to run before this command starts.
225   *
226   * <p>Note: This decorator works by adding this command to a composition. The command the
227   * decorator was called on cannot be scheduled independently or be added to a different
228   * composition (namely, decorators), unless it is manually cleared from the list of composed
229   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
230   * returned from this method can be further decorated without issue.
231   *
232   * @param toRun the Runnable to run
233   * @param requirements the required subsystems
234   * @return the decorated command
235   */
236  public SequentialCommandGroup beforeStarting(Runnable toRun, Subsystem... requirements) {
237    return beforeStarting(new InstantCommand(toRun, requirements));
238  }
239
240  /**
241   * Decorates this command with another command to run before this command starts.
242   *
243   * <p>Note: This decorator works by adding this command to a composition. The command the
244   * decorator was called on cannot be scheduled independently or be added to a different
245   * composition (namely, decorators), unless it is manually cleared from the list of composed
246   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
247   * returned from this method can be further decorated without issue.
248   *
249   * @param before the command to run before this one
250   * @return the decorated command
251   */
252  public SequentialCommandGroup beforeStarting(Command before) {
253    return new SequentialCommandGroup(before, this);
254  }
255
256  /**
257   * Decorates this command with a runnable to run after the command finishes.
258   *
259   * <p>Note: This decorator works by adding this command to a composition. The command the
260   * decorator was called on cannot be scheduled independently or be added to a different
261   * composition (namely, decorators), unless it is manually cleared from the list of composed
262   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
263   * returned from this method can be further decorated without issue.
264   *
265   * @param toRun the Runnable to run
266   * @param requirements the required subsystems
267   * @return the decorated command
268   */
269  public SequentialCommandGroup andThen(Runnable toRun, Subsystem... requirements) {
270    return andThen(new InstantCommand(toRun, requirements));
271  }
272
273  /**
274   * Decorates this command with a set of commands to run after it in sequence. Often more
275   * convenient/less-verbose than constructing a new {@link SequentialCommandGroup} explicitly.
276   *
277   * <p>Note: This decorator works by adding this command to a composition. The command the
278   * decorator was called on cannot be scheduled independently or be added to a different
279   * composition (namely, decorators), unless it is manually cleared from the list of composed
280   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
281   * returned from this method can be further decorated without issue.
282   *
283   * @param next the commands to run next
284   * @return the decorated command
285   */
286  public SequentialCommandGroup andThen(Command... next) {
287    SequentialCommandGroup group = new SequentialCommandGroup(this);
288    group.addCommands(next);
289    return group;
290  }
291
292  /**
293   * Creates a new command that runs this command and the deadline in parallel, finishing (and
294   * interrupting this command) when the deadline finishes.
295   *
296   * <p>Note: This decorator works by adding this command to a composition. The command the
297   * decorator was called on cannot be scheduled independently or be added to a different
298   * composition (namely, decorators), unless it is manually cleared from the list of composed
299   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
300   * returned from this method can be further decorated without issue.
301   *
302   * @param deadline the deadline of the command group
303   * @return the decorated command
304   * @see Command#deadlineFor
305   */
306  public ParallelDeadlineGroup withDeadline(Command deadline) {
307    return new ParallelDeadlineGroup(deadline, this);
308  }
309
310  /**
311   * Decorates this command with a set of commands to run parallel to it, ending when the calling
312   * command ends and interrupting all the others. Often more convenient/less-verbose than
313   * constructing a new {@link ParallelDeadlineGroup} explicitly.
314   *
315   * <p>Note: This decorator works by adding this command to a composition. The command the
316   * decorator was called on cannot be scheduled independently or be added to a different
317   * composition (namely, decorators), unless it is manually cleared from the list of composed
318   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
319   * returned from this method can be further decorated without issue.
320   *
321   * @param parallel the commands to run in parallel. Note the parallel commands will be interrupted
322   *     when the deadline command ends
323   * @return the decorated command
324   * @see Command#withDeadline
325   */
326  public ParallelDeadlineGroup deadlineFor(Command... parallel) {
327    return new ParallelDeadlineGroup(this, parallel);
328  }
329
330  /**
331   * Decorates this command with a set of commands to run parallel to it, ending when the last
332   * command ends. Often more convenient/less-verbose than constructing a new {@link
333   * ParallelCommandGroup} explicitly.
334   *
335   * <p>Note: This decorator works by adding this command to a composition. The command the
336   * decorator was called on cannot be scheduled independently or be added to a different
337   * composition (namely, decorators), unless it is manually cleared from the list of composed
338   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
339   * returned from this method can be further decorated without issue.
340   *
341   * @param parallel the commands to run in parallel
342   * @return the decorated command
343   */
344  public ParallelCommandGroup alongWith(Command... parallel) {
345    ParallelCommandGroup group = new ParallelCommandGroup(this);
346    group.addCommands(parallel);
347    return group;
348  }
349
350  /**
351   * Decorates this command with a set of commands to run parallel to it, ending when the first
352   * command ends. Often more convenient/less-verbose than constructing a new {@link
353   * ParallelRaceGroup} explicitly.
354   *
355   * <p>Note: This decorator works by adding this command to a composition. The command the
356   * decorator was called on cannot be scheduled independently or be added to a different
357   * composition (namely, decorators), unless it is manually cleared from the list of composed
358   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
359   * returned from this method can be further decorated without issue.
360   *
361   * @param parallel the commands to run in parallel
362   * @return the decorated command
363   */
364  public ParallelRaceGroup raceWith(Command... parallel) {
365    ParallelRaceGroup group = new ParallelRaceGroup(this);
366    group.addCommands(parallel);
367    return group;
368  }
369
370  /**
371   * Decorates this command to run repeatedly, restarting it when it ends, until this command is
372   * interrupted. The decorated command can still be canceled.
373   *
374   * <p>Note: This decorator works by adding this command to a composition. The command the
375   * decorator was called on cannot be scheduled independently or be added to a different
376   * composition (namely, decorators), unless it is manually cleared from the list of composed
377   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
378   * returned from this method can be further decorated without issue.
379   *
380   * @return the decorated command
381   */
382  public RepeatCommand repeatedly() {
383    return new RepeatCommand(this);
384  }
385
386  /**
387   * Decorates this command to run "by proxy" by wrapping it in a {@link ProxyCommand}. Use this for
388   * "forking off" from command compositions when the user does not wish to extend the command's
389   * requirements to the entire command composition. ProxyCommand has unique implications and
390   * semantics, see the WPILib docs for a full explanation.
391   *
392   * @return the decorated command
393   * @see ProxyCommand
394   * @see <a
395   *     href="https://docs.wpilib.org/en/stable/docs/software/commandbased/command-compositions.html#scheduling-other-commands">WPILib
396   *     docs</a>
397   */
398  public ProxyCommand asProxy() {
399    return new ProxyCommand(this);
400  }
401
402  /**
403   * Decorates this command to only run if this condition is not met. If the command is already
404   * running and the condition changes to true, the command will not stop running. The requirements
405   * of this command will be kept for the new conditional command.
406   *
407   * <p>Note: This decorator works by adding this command to a composition. The command the
408   * decorator was called on cannot be scheduled independently or be added to a different
409   * composition (namely, decorators), unless it is manually cleared from the list of composed
410   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
411   * returned from this method can be further decorated without issue.
412   *
413   * @param condition the condition that will prevent the command from running
414   * @return the decorated command
415   * @see #onlyIf(BooleanSupplier)
416   */
417  public ConditionalCommand unless(BooleanSupplier condition) {
418    return new ConditionalCommand(new InstantCommand(), this, condition);
419  }
420
421  /**
422   * Decorates this command to only run if this condition is met. If the command is already running
423   * and the condition changes to false, the command will not stop running. The requirements of this
424   * command will be kept for the new conditional command.
425   *
426   * <p>Note: This decorator works by adding this command to a composition. The command the
427   * decorator was called on cannot be scheduled independently or be added to a different
428   * composition (namely, decorators), unless it is manually cleared from the list of composed
429   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
430   * returned from this method can be further decorated without issue.
431   *
432   * @param condition the condition that will allow the command to run
433   * @return the decorated command
434   * @see #unless(BooleanSupplier)
435   */
436  public ConditionalCommand onlyIf(BooleanSupplier condition) {
437    return unless(() -> !condition.getAsBoolean());
438  }
439
440  /**
441   * Decorates this command to run or stop when disabled.
442   *
443   * @param doesRunWhenDisabled true to run when disabled.
444   * @return the decorated command
445   */
446  public WrapperCommand ignoringDisable(boolean doesRunWhenDisabled) {
447    return new WrapperCommand(this) {
448      @Override
449      public boolean runsWhenDisabled() {
450        return doesRunWhenDisabled;
451      }
452    };
453  }
454
455  /**
456   * Decorates this command to have a different {@link InterruptionBehavior interruption behavior}.
457   *
458   * @param interruptBehavior the desired interrupt behavior
459   * @return the decorated command
460   */
461  public WrapperCommand withInterruptBehavior(InterruptionBehavior interruptBehavior) {
462    return new WrapperCommand(this) {
463      @Override
464      public InterruptionBehavior getInterruptionBehavior() {
465        return interruptBehavior;
466      }
467    };
468  }
469
470  /**
471   * Decorates this command with a lambda to call on interrupt or end, following the command's
472   * inherent {@link #end(boolean)} method.
473   *
474   * @param end a lambda accepting a boolean parameter specifying whether the command was
475   *     interrupted.
476   * @return the decorated command
477   */
478  public WrapperCommand finallyDo(BooleanConsumer end) {
479    requireNonNullParam(end, "end", "Command.finallyDo()");
480    return new WrapperCommand(this) {
481      @Override
482      public void end(boolean interrupted) {
483        super.end(interrupted);
484        end.accept(interrupted);
485      }
486    };
487  }
488
489  /**
490   * Decorates this command with a lambda to call on interrupt or end, following the command's
491   * inherent {@link #end(boolean)} method. The provided lambda will run identically in both
492   * interrupt and end cases.
493   *
494   * @param end a lambda to run when the command ends, whether or not it was interrupted.
495   * @return the decorated command
496   */
497  public WrapperCommand finallyDo(Runnable end) {
498    return finallyDo(interrupted -> end.run());
499  }
500
501  /**
502   * Decorates this command with a lambda to call on interrupt, following the command's inherent
503   * {@link #end(boolean)} method.
504   *
505   * @param handler a lambda to run when the command is interrupted
506   * @return the decorated command
507   */
508  public WrapperCommand handleInterrupt(Runnable handler) {
509    requireNonNullParam(handler, "handler", "Command.handleInterrupt()");
510    return finallyDo(
511        interrupted -> {
512          if (interrupted) {
513            handler.run();
514          }
515        });
516  }
517
518  /**
519   * Cancels this command. Will call {@link #end(boolean) end(true)}. Commands will be canceled
520   * regardless of {@link InterruptionBehavior interruption behavior}.
521   *
522   * @see CommandScheduler#cancel(Command...)
523   */
524  public void cancel() {
525    CommandScheduler.getInstance().cancel(this);
526  }
527
528  /**
529   * Whether the command is currently scheduled. Note that this does not detect whether the command
530   * is in a composition, only whether it is directly being run by the scheduler.
531   *
532   * @return Whether the command is scheduled.
533   */
534  public boolean isScheduled() {
535    return CommandScheduler.getInstance().isScheduled(this);
536  }
537
538  /**
539   * Whether the command requires a given subsystem.
540   *
541   * @param requirement the subsystem to inquire about
542   * @return whether the subsystem is required
543   */
544  public boolean hasRequirement(Subsystem requirement) {
545    return getRequirements().contains(requirement);
546  }
547
548  /**
549   * How the command behaves when another command with a shared requirement is scheduled.
550   *
551   * @return a variant of {@link InterruptionBehavior}, defaulting to {@link
552   *     InterruptionBehavior#kCancelSelf kCancelSelf}.
553   */
554  public InterruptionBehavior getInterruptionBehavior() {
555    return InterruptionBehavior.kCancelSelf;
556  }
557
558  /**
559   * Whether the given command should run when the robot is disabled. Override to return true if the
560   * command should run when disabled.
561   *
562   * @return whether the command should run when the robot is disabled
563   */
564  public boolean runsWhenDisabled() {
565    return false;
566  }
567
568  /**
569   * Decorates this Command with a name.
570   *
571   * @param name name
572   * @return the decorated Command
573   */
574  public WrapperCommand withName(String name) {
575    WrapperCommand wrapper = new WrapperCommand(Command.this) {};
576    wrapper.setName(name);
577    return wrapper;
578  }
579
580  @Override
581  public void initSendable(SendableBuilder builder) {
582    builder.setSmartDashboardType("Command");
583    builder.addStringProperty(".name", this::getName, null);
584    builder.addBooleanProperty(
585        "running",
586        this::isScheduled,
587        value -> {
588          if (value) {
589            if (!isScheduled()) {
590              CommandScheduler.getInstance().schedule(this);
591            }
592          } else {
593            if (isScheduled()) {
594              cancel();
595            }
596          }
597        });
598    builder.addBooleanProperty(
599        ".isParented", () -> CommandScheduler.getInstance().isComposed(this), null);
600    builder.addStringProperty(
601        "interruptBehavior", () -> getInterruptionBehavior().toString(), null);
602    builder.addBooleanProperty("runsWhenDisabled", this::runsWhenDisabled, null);
603  }
604
605  /**
606   * An enum describing the command's behavior when another command with a shared requirement is
607   * scheduled.
608   */
609  public enum InterruptionBehavior {
610    /**
611     * This command ends, {@link #end(boolean) end(true)} is called, and the incoming command is
612     * scheduled normally.
613     *
614     * <p>This is the default behavior.
615     */
616    kCancelSelf,
617    /** This command continues, and the incoming command is not scheduled. */
618    kCancelIncoming
619  }
620}