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}