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. 068 * 069 * <p>Note: This decorator works by adding this command to a composition. The command the 070 * decorator was called on cannot be scheduled independently or be added to a different 071 * composition (namely, decorators), unless it is manually cleared from the list of composed 072 * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition 073 * returned from this method can be further decorated without issue. 074 * 075 * @param seconds the timeout duration 076 * @return the command with the timeout added 077 */ 078 default ParallelRaceGroup withTimeout(double seconds) { 079 return raceWith(new WaitCommand(seconds)); 080 } 081 082 /** 083 * Decorates this command with an interrupt condition. If the specified condition becomes true 084 * before the command finishes normally, the command will be interrupted and un-scheduled. 085 * 086 * <p>Note: This decorator works by adding this command to a composition. The command the 087 * decorator was called on cannot be scheduled independently or be added to a different 088 * composition (namely, decorators), unless it is manually cleared from the list of composed 089 * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition 090 * returned from this method can be further decorated without issue. 091 * 092 * @param condition the interrupt condition 093 * @return the command with the interrupt condition added 094 * @see #onlyWhile(BooleanSupplier) 095 */ 096 default ParallelRaceGroup until(BooleanSupplier condition) { 097 return raceWith(new WaitUntilCommand(condition)); 098 } 099 100 /** 101 * Decorates this command with a run condition. If the specified condition becomes false before 102 * the command finishes normally, the command will be interrupted and un-scheduled. 103 * 104 * <p>Note: This decorator works by adding this command to a composition. The command the 105 * decorator was called on cannot be scheduled independently or be added to a different 106 * composition (namely, decorators), unless it is manually cleared from the list of composed 107 * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition 108 * returned from this method can be further decorated without issue. 109 * 110 * @param condition the run condition 111 * @return the command with the run condition added 112 * @see #until(BooleanSupplier) 113 */ 114 default ParallelRaceGroup onlyWhile(BooleanSupplier condition) { 115 return until(() -> !condition.getAsBoolean()); 116 } 117 118 /** 119 * Decorates this command with a runnable to run before this command starts. 120 * 121 * <p>Note: This decorator works by adding this command to a composition. The command the 122 * decorator was called on cannot be scheduled independently or be added to a different 123 * composition (namely, decorators), unless it is manually cleared from the list of composed 124 * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition 125 * returned from this method can be further decorated without issue. 126 * 127 * @param toRun the Runnable to run 128 * @param requirements the required subsystems 129 * @return the decorated command 130 */ 131 default SequentialCommandGroup beforeStarting(Runnable toRun, Subsystem... requirements) { 132 return beforeStarting(new InstantCommand(toRun, requirements)); 133 } 134 135 /** 136 * Decorates this command with another command to run before this command starts. 137 * 138 * <p>Note: This decorator works by adding this command to a composition. The command the 139 * decorator was called on cannot be scheduled independently or be added to a different 140 * composition (namely, decorators), unless it is manually cleared from the list of composed 141 * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition 142 * returned from this method can be further decorated without issue. 143 * 144 * @param before the command to run before this one 145 * @return the decorated command 146 */ 147 default SequentialCommandGroup beforeStarting(Command before) { 148 return new SequentialCommandGroup(before, this); 149 } 150 151 /** 152 * Decorates this command with a runnable to run after the command finishes. 153 * 154 * <p>Note: This decorator works by adding this command to a composition. The command the 155 * decorator was called on cannot be scheduled independently or be added to a different 156 * composition (namely, decorators), unless it is manually cleared from the list of composed 157 * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition 158 * returned from this method can be further decorated without issue. 159 * 160 * @param toRun the Runnable to run 161 * @param requirements the required subsystems 162 * @return the decorated command 163 */ 164 default SequentialCommandGroup andThen(Runnable toRun, Subsystem... requirements) { 165 return andThen(new InstantCommand(toRun, requirements)); 166 } 167 168 /** 169 * Decorates this command with a set of commands to run after it in sequence. Often more 170 * convenient/less-verbose than constructing a new {@link SequentialCommandGroup} explicitly. 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 next the commands to run next 179 * @return the decorated command 180 */ 181 default SequentialCommandGroup andThen(Command... next) { 182 SequentialCommandGroup group = new SequentialCommandGroup(this); 183 group.addCommands(next); 184 return group; 185 } 186 187 /** 188 * Decorates this command with a set of commands to run parallel to it, ending when the calling 189 * command ends and interrupting all the others. Often more convenient/less-verbose than 190 * constructing a new {@link ParallelDeadlineGroup} explicitly. 191 * 192 * <p>Note: This decorator works by adding this command to a composition. The command the 193 * decorator was called on cannot be scheduled independently or be added to a different 194 * composition (namely, decorators), unless it is manually cleared from the list of composed 195 * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition 196 * returned from this method can be further decorated without issue. 197 * 198 * @param parallel the commands to run in parallel 199 * @return the decorated command 200 */ 201 default ParallelDeadlineGroup deadlineWith(Command... parallel) { 202 return new ParallelDeadlineGroup(this, parallel); 203 } 204 205 /** 206 * Decorates this command with a set of commands to run parallel to it, ending when the last 207 * command ends. Often more convenient/less-verbose than constructing a new {@link 208 * ParallelCommandGroup} explicitly. 209 * 210 * <p>Note: This decorator works by adding this command to a composition. The command the 211 * decorator was called on cannot be scheduled independently or be added to a different 212 * composition (namely, decorators), unless it is manually cleared from the list of composed 213 * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition 214 * returned from this method can be further decorated without issue. 215 * 216 * @param parallel the commands to run in parallel 217 * @return the decorated command 218 */ 219 default ParallelCommandGroup alongWith(Command... parallel) { 220 ParallelCommandGroup group = new ParallelCommandGroup(this); 221 group.addCommands(parallel); 222 return group; 223 } 224 225 /** 226 * Decorates this command with a set of commands to run parallel to it, ending when the first 227 * command ends. Often more convenient/less-verbose than constructing a new {@link 228 * ParallelRaceGroup} explicitly. 229 * 230 * <p>Note: This decorator works by adding this command to a composition. The command the 231 * decorator was called on cannot be scheduled independently or be added to a different 232 * composition (namely, decorators), unless it is manually cleared from the list of composed 233 * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition 234 * returned from this method can be further decorated without issue. 235 * 236 * @param parallel the commands to run in parallel 237 * @return the decorated command 238 */ 239 default ParallelRaceGroup raceWith(Command... parallel) { 240 ParallelRaceGroup group = new ParallelRaceGroup(this); 241 group.addCommands(parallel); 242 return group; 243 } 244 245 /** 246 * Decorates this command to run repeatedly, restarting it when it ends, until this command is 247 * interrupted. The decorated command can still be canceled. 248 * 249 * <p>Note: This decorator works by adding this command to a composition. The command the 250 * decorator was called on cannot be scheduled independently or be added to a different 251 * composition (namely, decorators), unless it is manually cleared from the list of composed 252 * commands with {@link CommandScheduler#removeComposedCommand(Command)}. The command composition 253 * returned from this method can be further decorated without issue. 254 * 255 * @return the decorated command 256 */ 257 default RepeatCommand repeatedly() { 258 return new RepeatCommand(this); 259 } 260 261 /** 262 * Decorates this command to run "by proxy" by wrapping it in a {@link ProxyCommand}. This is 263 * useful for "forking off" from command compositions when the user does not wish to extend the 264 * command's requirements to the entire command composition. 265 * 266 * @return the decorated command 267 */ 268 default ProxyCommand asProxy() { 269 return new ProxyCommand(this); 270 } 271 272 /** 273 * Decorates this command to only run if this condition is not met. If the command is already 274 * running and the condition changes to true, the command will not stop running. The requirements 275 * of this command will be kept for the new conditional command. 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 condition the condition that will prevent the command from running 284 * @return the decorated command 285 * @see #onlyIf(BooleanSupplier) 286 */ 287 default ConditionalCommand unless(BooleanSupplier condition) { 288 return new ConditionalCommand(new InstantCommand(), this, condition); 289 } 290 291 /** 292 * Decorates this command to only run if this condition is met. If the command is already running 293 * and the condition changes to false, the command will not stop running. The requirements of this 294 * command will be kept for the new conditional command. 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 condition the condition that will allow the command to run 303 * @return the decorated command 304 * @see #unless(BooleanSupplier) 305 */ 306 default ConditionalCommand onlyIf(BooleanSupplier condition) { 307 return unless(() -> !condition.getAsBoolean()); 308 } 309 310 /** 311 * Decorates this command to run or stop when disabled. 312 * 313 * @param doesRunWhenDisabled true to run when disabled. 314 * @return the decorated command 315 */ 316 default WrapperCommand ignoringDisable(boolean doesRunWhenDisabled) { 317 return new WrapperCommand(this) { 318 @Override 319 public boolean runsWhenDisabled() { 320 return doesRunWhenDisabled; 321 } 322 }; 323 } 324 325 /** 326 * Decorates this command to have a different {@link InterruptionBehavior interruption behavior}. 327 * 328 * @param interruptBehavior the desired interrupt behavior 329 * @return the decorated command 330 */ 331 default WrapperCommand withInterruptBehavior(InterruptionBehavior interruptBehavior) { 332 return new WrapperCommand(this) { 333 @Override 334 public InterruptionBehavior getInterruptionBehavior() { 335 return interruptBehavior; 336 } 337 }; 338 } 339 340 /** 341 * Decorates this command with a lambda to call on interrupt or end, following the command's 342 * inherent {@link #end(boolean)} method. 343 * 344 * @param end a lambda accepting a boolean parameter specifying whether the command was 345 * interrupted. 346 * @return the decorated command 347 */ 348 default WrapperCommand finallyDo(BooleanConsumer end) { 349 requireNonNullParam(end, "end", "Command.finallyDo()"); 350 return new WrapperCommand(this) { 351 @Override 352 public void end(boolean interrupted) { 353 super.end(interrupted); 354 end.accept(interrupted); 355 } 356 }; 357 } 358 359 /** 360 * Decorates this command with a lambda to call on interrupt, following the command's inherent 361 * {@link #end(boolean)} method. 362 * 363 * @param handler a lambda to run when the command is interrupted 364 * @return the decorated command 365 */ 366 default WrapperCommand handleInterrupt(Runnable handler) { 367 requireNonNullParam(handler, "handler", "Command.handleInterrupt()"); 368 return finallyDo( 369 interrupted -> { 370 if (interrupted) { 371 handler.run(); 372 } 373 }); 374 } 375 376 /** Schedules this command. */ 377 default void schedule() { 378 CommandScheduler.getInstance().schedule(this); 379 } 380 381 /** 382 * Cancels this command. Will call {@link #end(boolean) end(true)}. Commands will be canceled 383 * regardless of {@link InterruptionBehavior interruption behavior}. 384 * 385 * @see CommandScheduler#cancel(Command...) 386 */ 387 default void cancel() { 388 CommandScheduler.getInstance().cancel(this); 389 } 390 391 /** 392 * Whether the command is currently scheduled. Note that this does not detect whether the command 393 * is in a composition, only whether it is directly being run by the scheduler. 394 * 395 * @return Whether the command is scheduled. 396 */ 397 default boolean isScheduled() { 398 return CommandScheduler.getInstance().isScheduled(this); 399 } 400 401 /** 402 * Whether the command requires a given subsystem. 403 * 404 * @param requirement the subsystem to inquire about 405 * @return whether the subsystem is required 406 */ 407 default boolean hasRequirement(Subsystem requirement) { 408 return getRequirements().contains(requirement); 409 } 410 411 /** 412 * How the command behaves when another command with a shared requirement is scheduled. 413 * 414 * @return a variant of {@link InterruptionBehavior}, defaulting to {@link 415 * InterruptionBehavior#kCancelSelf kCancelSelf}. 416 */ 417 default InterruptionBehavior getInterruptionBehavior() { 418 return InterruptionBehavior.kCancelSelf; 419 } 420 421 /** 422 * Whether the given command should run when the robot is disabled. Override to return true if the 423 * command should run when disabled. 424 * 425 * @return whether the command should run when the robot is disabled 426 */ 427 default boolean runsWhenDisabled() { 428 return false; 429 } 430 431 /** 432 * Gets the name of this Command. Defaults to the simple class name if not overridden. 433 * 434 * @return The display name of the Command 435 */ 436 default String getName() { 437 return this.getClass().getSimpleName(); 438 } 439 440 /** 441 * Sets the name of this Command. Nullop if not overridden. 442 * 443 * @param name The display name of the Command. 444 */ 445 default void setName(String name) {} 446 447 /** 448 * Decorates this Command with a name. 449 * 450 * @param name name 451 * @return the decorated Command 452 */ 453 default WrapperCommand withName(String name) { 454 WrapperCommand wrapper = new WrapperCommand(Command.this) {}; 455 wrapper.setName(name); 456 return wrapper; 457 } 458 459 /** 460 * An enum describing the command's behavior when another command with a shared requirement is 461 * scheduled. 462 */ 463 enum InterruptionBehavior { 464 /** 465 * This command ends, {@link #end(boolean) end(true)} is called, and the incoming command is 466 * scheduled normally. 467 * 468 * <p>This is the default behavior. 469 */ 470 kCancelSelf, 471 /** This command continues, and the incoming command is not scheduled. */ 472 kCancelIncoming 473 } 474}