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.util.ErrorMessages.requireNonNullParam; 008 009import edu.wpi.first.util.function.BooleanConsumer; 010import java.util.Set; 011import java.util.function.BooleanSupplier; 012 013/** 014 * A state machine representing a complete action to be performed by the robot. Commands are run by 015 * the {@link CommandScheduler}, and can be composed into CommandGroups to allow users to build 016 * complicated multistep actions without the need to roll the state machine logic themselves. 017 * 018 * <p>Commands are run synchronously from the main robot loop; no multithreading is used, unless 019 * specified explicitly from the command implementation. 020 * 021 * <p>This class is provided by the NewCommands VendorDep 022 */ 023public interface Command { 024 /** The initial subroutine of a command. Called once when the command is initially scheduled. */ 025 default void initialize() {} 026 027 /** The main body of a command. Called repeatedly while the command is scheduled. */ 028 default void execute() {} 029 030 /** 031 * The action to take when the command ends. Called when either the command finishes normally, or 032 * when it interrupted/canceled. 033 * 034 * <p>Do not schedule commands here that share requirements with this command. Use {@link 035 * #andThen(Command...)} instead. 036 * 037 * @param interrupted whether the command was interrupted/canceled 038 */ 039 default void end(boolean interrupted) {} 040 041 /** 042 * Whether the command has finished. Once a command finishes, the scheduler will call its end() 043 * method and un-schedule it. 044 * 045 * @return whether the command has finished. 046 */ 047 default boolean isFinished() { 048 return false; 049 } 050 051 /** 052 * Specifies the set of subsystems used by this command. Two commands cannot use the same 053 * subsystem at the same time. If another command is scheduled that shares a requirement, {@link 054 * #getInterruptionBehavior()} will be checked and followed. If no subsystems are required, return 055 * an empty set. 056 * 057 * <p>Note: it is recommended that user implementations contain the requirements as a field, and 058 * return that field here, rather than allocating a new set every time this is called. 059 * 060 * @return the set of subsystems that are required 061 * @see InterruptionBehavior 062 */ 063 Set<Subsystem> getRequirements(); 064 065 /** 066 * Decorates this command with a timeout. If the specified timeout is exceeded before the command 067 * finishes normally, the command will be interrupted and un-scheduled. Note that the timeout only 068 * applies to the command returned by this method; the calling command is not itself changed. 069 * 070 * <p>Note: This decorator works by adding this command to a composition. The command the 071 * decorator was called on cannot be scheduled independently or be added to a different 072 * composition (namely, decorators), unless it is manually cleared from the list of composed 073 * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition 074 * returned from this method can be further decorated without issue. 075 * 076 * @param seconds the timeout duration 077 * @return the command with the timeout added 078 */ 079 default ParallelRaceGroup withTimeout(double seconds) { 080 return raceWith(new WaitCommand(seconds)); 081 } 082 083 /** 084 * Decorates this command with an interrupt condition. If the specified condition becomes true 085 * before the command finishes normally, the command will be interrupted and un-scheduled. Note 086 * that this only applies to the command returned by this method; the calling command is not 087 * itself changed. 088 * 089 * <p>Note: This decorator works by adding this command to a composition. The command the 090 * decorator was called on cannot be scheduled independently or be added to a different 091 * composition (namely, decorators), unless it is manually cleared from the list of composed 092 * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition 093 * returned from this method can be further decorated without issue. 094 * 095 * @param condition the interrupt condition 096 * @return the command with the interrupt condition added 097 */ 098 default ParallelRaceGroup until(BooleanSupplier condition) { 099 return raceWith(new WaitUntilCommand(condition)); 100 } 101 102 /** 103 * Decorates this command with an interrupt condition. If the specified condition becomes true 104 * before the command finishes normally, the command will be interrupted and un-scheduled. Note 105 * that this only applies to the command returned by this method; the calling command is not 106 * itself changed. 107 * 108 * <p>Note: This decorator works by adding this command to a composition. The command the 109 * decorator was called on cannot be scheduled independently or be added to a different 110 * composition (namely, decorators), unless it is manually cleared from the list of composed 111 * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition 112 * returned from this method can be further decorated without issue. 113 * 114 * @param condition the interrupt condition 115 * @return the command with the interrupt condition added 116 * @deprecated Replace with {@link #until(BooleanSupplier)} 117 */ 118 @Deprecated(since = "2023") 119 default ParallelRaceGroup withInterrupt(BooleanSupplier condition) { 120 return until(condition); 121 } 122 123 /** 124 * Decorates this command with a runnable to run before this command starts. 125 * 126 * <p>Note: This decorator works by adding this command to a composition. The command the 127 * decorator was called on cannot be scheduled independently or be added to a different 128 * composition (namely, decorators), unless it is manually cleared from the list of composed 129 * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition 130 * returned from this method can be further decorated without issue. 131 * 132 * @param toRun the Runnable to run 133 * @param requirements the required subsystems 134 * @return the decorated command 135 */ 136 default SequentialCommandGroup beforeStarting(Runnable toRun, Subsystem... requirements) { 137 return beforeStarting(new InstantCommand(toRun, requirements)); 138 } 139 140 /** 141 * Decorates this command with another command to run before this command starts. 142 * 143 * <p>Note: This decorator works by adding this command to a composition. The command the 144 * decorator was called on cannot be scheduled independently or be added to a different 145 * composition (namely, decorators), unless it is manually cleared from the list of composed 146 * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition 147 * returned from this method can be further decorated without issue. 148 * 149 * @param before the command to run before this one 150 * @return the decorated command 151 */ 152 default SequentialCommandGroup beforeStarting(Command before) { 153 return new SequentialCommandGroup(before, this); 154 } 155 156 /** 157 * Decorates this command with a runnable to run after the command finishes. 158 * 159 * <p>Note: This decorator works by adding this command to a composition. The command the 160 * decorator was called on cannot be scheduled independently or be added to a different 161 * composition (namely, decorators), unless it is manually cleared from the list of composed 162 * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition 163 * returned from this method can be further decorated without issue. 164 * 165 * @param toRun the Runnable to run 166 * @param requirements the required subsystems 167 * @return the decorated command 168 */ 169 default SequentialCommandGroup andThen(Runnable toRun, Subsystem... requirements) { 170 return andThen(new InstantCommand(toRun, requirements)); 171 } 172 173 /** 174 * Decorates this command with a set of commands to run after it in sequence. Often more 175 * convenient/less-verbose than constructing a new {@link SequentialCommandGroup} explicitly. 176 * 177 * <p>Note: This decorator works by adding this command to a composition. The command the 178 * decorator was called on cannot be scheduled independently or be added to a different 179 * composition (namely, decorators), unless it is manually cleared from the list of composed 180 * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition 181 * returned from this method can be further decorated without issue. 182 * 183 * @param next the commands to run next 184 * @return the decorated command 185 */ 186 default SequentialCommandGroup andThen(Command... next) { 187 SequentialCommandGroup group = new SequentialCommandGroup(this); 188 group.addCommands(next); 189 return group; 190 } 191 192 /** 193 * Decorates this command with a set of commands to run parallel to it, ending when the calling 194 * command ends and interrupting all the others. Often more convenient/less-verbose than 195 * constructing a new {@link ParallelDeadlineGroup} explicitly. 196 * 197 * <p>Note: This decorator works by adding this command to a composition. The command the 198 * decorator was called on cannot be scheduled independently or be added to a different 199 * composition (namely, decorators), unless it is manually cleared from the list of composed 200 * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition 201 * returned from this method can be further decorated without issue. 202 * 203 * @param parallel the commands to run in parallel 204 * @return the decorated command 205 */ 206 default ParallelDeadlineGroup deadlineWith(Command... parallel) { 207 return new ParallelDeadlineGroup(this, parallel); 208 } 209 210 /** 211 * Decorates this command with a set of commands to run parallel to it, ending when the last 212 * command ends. Often more convenient/less-verbose than constructing a new {@link 213 * ParallelCommandGroup} explicitly. 214 * 215 * <p>Note: This decorator works by adding this command to a composition. The command the 216 * decorator was called on cannot be scheduled independently or be added to a different 217 * composition (namely, decorators), unless it is manually cleared from the list of composed 218 * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition 219 * returned from this method can be further decorated without issue. 220 * 221 * @param parallel the commands to run in parallel 222 * @return the decorated command 223 */ 224 default ParallelCommandGroup alongWith(Command... parallel) { 225 ParallelCommandGroup group = new ParallelCommandGroup(this); 226 group.addCommands(parallel); 227 return group; 228 } 229 230 /** 231 * Decorates this command with a set of commands to run parallel to it, ending when the first 232 * command ends. Often more convenient/less-verbose than constructing a new {@link 233 * ParallelRaceGroup} explicitly. 234 * 235 * <p>Note: This decorator works by adding this command to a composition. The command the 236 * decorator was called on cannot be scheduled independently or be added to a different 237 * composition (namely, decorators), unless it is manually cleared from the list of composed 238 * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition 239 * returned from this method can be further decorated without issue. 240 * 241 * @param parallel the commands to run in parallel 242 * @return the decorated command 243 */ 244 default ParallelRaceGroup raceWith(Command... parallel) { 245 ParallelRaceGroup group = new ParallelRaceGroup(this); 246 group.addCommands(parallel); 247 return group; 248 } 249 250 /** 251 * Decorates this command to run perpetually, ignoring its ordinary end conditions. The decorated 252 * command can still be interrupted or canceled. 253 * 254 * <p>Note: This decorator works by adding this command to a composition. The command the 255 * decorator was called on cannot be scheduled independently or be added to a different 256 * composition (namely, decorators), unless it is manually cleared from the list of composed 257 * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition 258 * returned from this method can be further decorated without issue. 259 * 260 * @return the decorated command 261 * @deprecated PerpetualCommand violates the assumption that execute() doesn't get called after 262 * isFinished() returns true -- an assumption that should be valid. This was unsafe/undefined 263 * behavior from the start, and RepeatCommand provides an easy way to achieve similar end 264 * results with slightly different (and safe) semantics. 265 */ 266 @SuppressWarnings("removal") // PerpetualCommand 267 @Deprecated(forRemoval = true, since = "2023") 268 default PerpetualCommand perpetually() { 269 return new PerpetualCommand(this); 270 } 271 272 /** 273 * Decorates this command to run repeatedly, restarting it when it ends, until this command is 274 * interrupted. The decorated command can still be canceled. 275 * 276 * <p>Note: This decorator works by adding this command to a composition. The command the 277 * decorator was called on cannot be scheduled independently or be added to a different 278 * composition (namely, decorators), unless it is manually cleared from the list of composed 279 * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition 280 * returned from this method can be further decorated without issue. 281 * 282 * @return the decorated command 283 */ 284 default RepeatCommand repeatedly() { 285 return new RepeatCommand(this); 286 } 287 288 /** 289 * Decorates this command to run "by proxy" by wrapping it in a {@link ProxyCommand}. This is 290 * useful for "forking off" from command compositions when the user does not wish to extend the 291 * command's requirements to the entire command composition. 292 * 293 * @return the decorated command 294 */ 295 default ProxyCommand asProxy() { 296 return new ProxyCommand(this); 297 } 298 299 /** 300 * Decorates this command to only run if this condition is not met. If the command is already 301 * running and the condition changes to true, the command will not stop running. The requirements 302 * of this command will be kept for the new conditional command. 303 * 304 * @param condition the condition that will prevent the command from running 305 * @return the decorated command 306 */ 307 default ConditionalCommand unless(BooleanSupplier condition) { 308 return new ConditionalCommand(new InstantCommand(), this, condition); 309 } 310 311 /** 312 * Decorates this command to run or stop when disabled. 313 * 314 * @param doesRunWhenDisabled true to run when disabled. 315 * @return the decorated command 316 */ 317 default WrapperCommand ignoringDisable(boolean doesRunWhenDisabled) { 318 return new WrapperCommand(this) { 319 @Override 320 public boolean runsWhenDisabled() { 321 return doesRunWhenDisabled; 322 } 323 }; 324 } 325 326 /** 327 * Decorates this command to have a different {@link InterruptionBehavior interruption behavior}. 328 * 329 * @param interruptBehavior the desired interrupt behavior 330 * @return the decorated command 331 */ 332 default WrapperCommand withInterruptBehavior(InterruptionBehavior interruptBehavior) { 333 return new WrapperCommand(this) { 334 @Override 335 public InterruptionBehavior getInterruptionBehavior() { 336 return interruptBehavior; 337 } 338 }; 339 } 340 341 /** 342 * Decorates this command with a lambda to call on interrupt or end, following the command's 343 * inherent {@link #end(boolean)} method. 344 * 345 * @param end a lambda accepting a boolean parameter specifying whether the command was 346 * interrupted. 347 * @return the decorated command 348 */ 349 default WrapperCommand finallyDo(BooleanConsumer end) { 350 requireNonNullParam(end, "end", "Command.finallyDo()"); 351 return new WrapperCommand(this) { 352 @Override 353 public void end(boolean interrupted) { 354 super.end(interrupted); 355 end.accept(interrupted); 356 } 357 }; 358 } 359 360 /** 361 * Decorates this command with a lambda to call on interrupt, following the command's inherent 362 * {@link #end(boolean)} method. 363 * 364 * @param handler a lambda to run when the command is interrupted 365 * @return the decorated command 366 */ 367 default WrapperCommand handleInterrupt(Runnable handler) { 368 requireNonNullParam(handler, "handler", "Command.handleInterrupt()"); 369 return finallyDo( 370 interrupted -> { 371 if (interrupted) { 372 handler.run(); 373 } 374 }); 375 } 376 377 /** Schedules this command. */ 378 default void schedule() { 379 CommandScheduler.getInstance().schedule(this); 380 } 381 382 /** 383 * Cancels this command. Will call {@link #end(boolean) end(true)}. Commands will be canceled 384 * regardless of {@link InterruptionBehavior interruption behavior}. 385 * 386 * @see CommandScheduler#cancel(Command...) 387 */ 388 default void cancel() { 389 CommandScheduler.getInstance().cancel(this); 390 } 391 392 /** 393 * Whether the command is currently scheduled. Note that this does not detect whether the command 394 * is in a composition, only whether it is directly being run by the scheduler. 395 * 396 * @return Whether the command is scheduled. 397 */ 398 default boolean isScheduled() { 399 return CommandScheduler.getInstance().isScheduled(this); 400 } 401 402 /** 403 * Whether the command requires a given subsystem. 404 * 405 * @param requirement the subsystem to inquire about 406 * @return whether the subsystem is required 407 */ 408 default boolean hasRequirement(Subsystem requirement) { 409 return getRequirements().contains(requirement); 410 } 411 412 /** 413 * How the command behaves when another command with a shared requirement is scheduled. 414 * 415 * @return a variant of {@link InterruptionBehavior}, defaulting to {@link 416 * InterruptionBehavior#kCancelSelf kCancelSelf}. 417 */ 418 default InterruptionBehavior getInterruptionBehavior() { 419 return InterruptionBehavior.kCancelSelf; 420 } 421 422 /** 423 * Whether the given command should run when the robot is disabled. Override to return true if the 424 * command should run when disabled. 425 * 426 * @return whether the command should run when the robot is disabled 427 */ 428 default boolean runsWhenDisabled() { 429 return false; 430 } 431 432 /** 433 * Gets the name of this Command. Defaults to the simple class name if not overridden. 434 * 435 * @return The display name of the Command 436 */ 437 default String getName() { 438 return this.getClass().getSimpleName(); 439 } 440 441 /** 442 * Sets the name of this Command. Nullop if not overridden. 443 * 444 * @param name The display name of the Command. 445 */ 446 default void setName(String name) {} 447 448 /** 449 * Decorates this Command with a name. 450 * 451 * @param name name 452 * @return the decorated Command 453 */ 454 default WrapperCommand withName(String name) { 455 WrapperCommand wrapper = new WrapperCommand(Command.this) {}; 456 wrapper.setName(name); 457 return wrapper; 458 } 459 460 /** 461 * An enum describing the command's behavior when another command with a shared requirement is 462 * scheduled. 463 */ 464 enum InterruptionBehavior { 465 /** 466 * This command ends, {@link #end(boolean) end(true)} is called, and the incoming command is 467 * scheduled normally. 468 * 469 * <p>This is the default behavior. 470 */ 471 kCancelSelf, 472 /** This command continues, and the incoming command is not scheduled. */ 473 kCancelIncoming 474 } 475}