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