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;
019import org.wpilib.annotation.NoDiscard;
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 NewCommands 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
322   * @return the decorated command
323   * @deprecated Use {@link deadlineFor} instead.
324   */
325  @Deprecated(since = "2025", forRemoval = true)
326  public ParallelDeadlineGroup deadlineWith(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 calling
332   * command ends and interrupting all the others. Often more convenient/less-verbose than
333   * constructing a new {@link ParallelDeadlineGroup} 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. Note the parallel commands will be interrupted
342   *     when the deadline command ends
343   * @return the decorated command
344   * @see Command#withDeadline
345   */
346  public ParallelDeadlineGroup deadlineFor(Command... parallel) {
347    return new ParallelDeadlineGroup(this, parallel);
348  }
349
350  /**
351   * Decorates this command with a set of commands to run parallel to it, ending when the last
352   * command ends. Often more convenient/less-verbose than constructing a new {@link
353   * ParallelCommandGroup} 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 ParallelCommandGroup alongWith(Command... parallel) {
365    ParallelCommandGroup group = new ParallelCommandGroup(this);
366    group.addCommands(parallel);
367    return group;
368  }
369
370  /**
371   * Decorates this command with a set of commands to run parallel to it, ending when the first
372   * command ends. Often more convenient/less-verbose than constructing a new {@link
373   * ParallelRaceGroup} explicitly.
374   *
375   * <p>Note: This decorator works by adding this command to a composition. The command the
376   * decorator was called on cannot be scheduled independently or be added to a different
377   * composition (namely, decorators), unless it is manually cleared from the list of composed
378   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
379   * returned from this method can be further decorated without issue.
380   *
381   * @param parallel the commands to run in parallel
382   * @return the decorated command
383   */
384  public ParallelRaceGroup raceWith(Command... parallel) {
385    ParallelRaceGroup group = new ParallelRaceGroup(this);
386    group.addCommands(parallel);
387    return group;
388  }
389
390  /**
391   * Decorates this command to run repeatedly, restarting it when it ends, until this command is
392   * interrupted. The decorated command can still be canceled.
393   *
394   * <p>Note: This decorator works by adding this command to a composition. The command the
395   * decorator was called on cannot be scheduled independently or be added to a different
396   * composition (namely, decorators), unless it is manually cleared from the list of composed
397   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
398   * returned from this method can be further decorated without issue.
399   *
400   * @return the decorated command
401   */
402  public RepeatCommand repeatedly() {
403    return new RepeatCommand(this);
404  }
405
406  /**
407   * Decorates this command to run "by proxy" by wrapping it in a {@link ProxyCommand}. Use this for
408   * "forking off" from command compositions when the user does not wish to extend the command's
409   * requirements to the entire command composition. ProxyCommand has unique implications and
410   * semantics, see the WPILib docs for a full explanation.
411   *
412   * @return the decorated command
413   * @see ProxyCommand
414   * @see <a
415   *     href="https://docs.wpilib.org/en/stable/docs/software/commandbased/command-compositions.html#scheduling-other-commands">WPILib
416   *     docs</a>
417   */
418  public ProxyCommand asProxy() {
419    return new ProxyCommand(this);
420  }
421
422  /**
423   * Decorates this command to only run if this condition is not met. If the command is already
424   * running and the condition changes to true, the command will not stop running. The requirements
425   * of this command will be kept for the new conditional command.
426   *
427   * <p>Note: This decorator works by adding this command to a composition. The command the
428   * decorator was called on cannot be scheduled independently or be added to a different
429   * composition (namely, decorators), unless it is manually cleared from the list of composed
430   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
431   * returned from this method can be further decorated without issue.
432   *
433   * @param condition the condition that will prevent the command from running
434   * @return the decorated command
435   * @see #onlyIf(BooleanSupplier)
436   */
437  public ConditionalCommand unless(BooleanSupplier condition) {
438    return new ConditionalCommand(new InstantCommand(), this, condition);
439  }
440
441  /**
442   * Decorates this command to only run if this condition is met. If the command is already running
443   * and the condition changes to false, the command will not stop running. The requirements of this
444   * command will be kept for the new conditional command.
445   *
446   * <p>Note: This decorator works by adding this command to a composition. The command the
447   * decorator was called on cannot be scheduled independently or be added to a different
448   * composition (namely, decorators), unless it is manually cleared from the list of composed
449   * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition
450   * returned from this method can be further decorated without issue.
451   *
452   * @param condition the condition that will allow the command to run
453   * @return the decorated command
454   * @see #unless(BooleanSupplier)
455   */
456  public ConditionalCommand onlyIf(BooleanSupplier condition) {
457    return unless(() -> !condition.getAsBoolean());
458  }
459
460  /**
461   * Decorates this command to run or stop when disabled.
462   *
463   * @param doesRunWhenDisabled true to run when disabled.
464   * @return the decorated command
465   */
466  public WrapperCommand ignoringDisable(boolean doesRunWhenDisabled) {
467    return new WrapperCommand(this) {
468      @Override
469      public boolean runsWhenDisabled() {
470        return doesRunWhenDisabled;
471      }
472    };
473  }
474
475  /**
476   * Decorates this command to have a different {@link InterruptionBehavior interruption behavior}.
477   *
478   * @param interruptBehavior the desired interrupt behavior
479   * @return the decorated command
480   */
481  public WrapperCommand withInterruptBehavior(InterruptionBehavior interruptBehavior) {
482    return new WrapperCommand(this) {
483      @Override
484      public InterruptionBehavior getInterruptionBehavior() {
485        return interruptBehavior;
486      }
487    };
488  }
489
490  /**
491   * Decorates this command with a lambda to call on interrupt or end, following the command's
492   * inherent {@link #end(boolean)} method.
493   *
494   * @param end a lambda accepting a boolean parameter specifying whether the command was
495   *     interrupted.
496   * @return the decorated command
497   */
498  public WrapperCommand finallyDo(BooleanConsumer end) {
499    requireNonNullParam(end, "end", "Command.finallyDo()");
500    return new WrapperCommand(this) {
501      @Override
502      public void end(boolean interrupted) {
503        super.end(interrupted);
504        end.accept(interrupted);
505      }
506    };
507  }
508
509  /**
510   * Decorates this command with a lambda to call on interrupt or end, following the command's
511   * inherent {@link #end(boolean)} method. The provided lambda will run identically in both
512   * interrupt and end cases.
513   *
514   * @param end a lambda to run when the command ends, whether or not it was interrupted.
515   * @return the decorated command
516   */
517  public WrapperCommand finallyDo(Runnable end) {
518    return finallyDo(interrupted -> end.run());
519  }
520
521  /**
522   * Decorates this command with a lambda to call on interrupt, following the command's inherent
523   * {@link #end(boolean)} method.
524   *
525   * @param handler a lambda to run when the command is interrupted
526   * @return the decorated command
527   */
528  public WrapperCommand handleInterrupt(Runnable handler) {
529    requireNonNullParam(handler, "handler", "Command.handleInterrupt()");
530    return finallyDo(
531        interrupted -> {
532          if (interrupted) {
533            handler.run();
534          }
535        });
536  }
537
538  /**
539   * Schedules this command.
540   *
541   * @deprecated Use CommandScheduler.getInstance().schedule(Command...) instead
542   */
543  @Deprecated(since = "2025", forRemoval = true)
544  public void schedule() {
545    CommandScheduler.getInstance().schedule(this);
546  }
547
548  /**
549   * Cancels this command. Will call {@link #end(boolean) end(true)}. Commands will be canceled
550   * regardless of {@link InterruptionBehavior interruption behavior}.
551   *
552   * @see CommandScheduler#cancel(Command...)
553   */
554  public void cancel() {
555    CommandScheduler.getInstance().cancel(this);
556  }
557
558  /**
559   * Whether the command is currently scheduled. Note that this does not detect whether the command
560   * is in a composition, only whether it is directly being run by the scheduler.
561   *
562   * @return Whether the command is scheduled.
563   */
564  public boolean isScheduled() {
565    return CommandScheduler.getInstance().isScheduled(this);
566  }
567
568  /**
569   * Whether the command requires a given subsystem.
570   *
571   * @param requirement the subsystem to inquire about
572   * @return whether the subsystem is required
573   */
574  public boolean hasRequirement(Subsystem requirement) {
575    return getRequirements().contains(requirement);
576  }
577
578  /**
579   * How the command behaves when another command with a shared requirement is scheduled.
580   *
581   * @return a variant of {@link InterruptionBehavior}, defaulting to {@link
582   *     InterruptionBehavior#kCancelSelf kCancelSelf}.
583   */
584  public InterruptionBehavior getInterruptionBehavior() {
585    return InterruptionBehavior.kCancelSelf;
586  }
587
588  /**
589   * Whether the given command should run when the robot is disabled. Override to return true if the
590   * command should run when disabled.
591   *
592   * @return whether the command should run when the robot is disabled
593   */
594  public boolean runsWhenDisabled() {
595    return false;
596  }
597
598  /**
599   * Decorates this Command with a name.
600   *
601   * @param name name
602   * @return the decorated Command
603   */
604  public WrapperCommand withName(String name) {
605    WrapperCommand wrapper = new WrapperCommand(Command.this) {};
606    wrapper.setName(name);
607    return wrapper;
608  }
609
610  @Override
611  public void initSendable(SendableBuilder builder) {
612    builder.setSmartDashboardType("Command");
613    builder.addStringProperty(".name", this::getName, null);
614    builder.addBooleanProperty(
615        "running",
616        this::isScheduled,
617        value -> {
618          if (value) {
619            if (!isScheduled()) {
620              CommandScheduler.getInstance().schedule(this);
621            }
622          } else {
623            if (isScheduled()) {
624              cancel();
625            }
626          }
627        });
628    builder.addBooleanProperty(
629        ".isParented", () -> CommandScheduler.getInstance().isComposed(this), null);
630    builder.addStringProperty(
631        "interruptBehavior", () -> getInterruptionBehavior().toString(), null);
632    builder.addBooleanProperty("runsWhenDisabled", this::runsWhenDisabled, null);
633  }
634
635  /**
636   * An enum describing the command's behavior when another command with a shared requirement is
637   * scheduled.
638   */
639  public enum InterruptionBehavior {
640    /**
641     * This command ends, {@link #end(boolean) end(true)} is called, and the incoming command is
642     * scheduled normally.
643     *
644     * <p>This is the default behavior.
645     */
646    kCancelSelf,
647    /** This command continues, and the incoming command is not scheduled. */
648    kCancelIncoming
649  }
650}