Skip to content

Commands

James Hagborg edited this page Jan 2, 2019 · 2 revisions

Our design philosophy is to have each subsystem provide small, simple commands, and then compose them to make more complex routines. For the former, HYPERLib provides the QuickCommand class to reduce the amount of boiler-plate around simple one-liners and common patterns like PID setpoints. For the latter, we have CommandBuilder, which functions like an improved CommandGroup, but adds control flow like if, for, and while, improved syntax for nesting parallel commands, and controlling the termination of parallel commands with release.

Part of this philosophy means separating out what a command does from the issues of when and for how long it does it. For example, QuickCommand.continuous makes a command that runs the same code repeatedly until it is canceled. By combining this with a waitFor in parallel, this can be adapted to run until an arbitrary condition is met. If the same command were bound to a button on the OI using @WhileHeld, it would run until the button is released. If instead it were bound using @WhenPressed, it would run indefinitely, only stopping when another command is issued to the same subsystem.

In practice, this means that a subsystem typically has several methods returning continuous commands, representing the various modes the subsystem can be in (e.g. lifting up, lifting down, holding in place, holding at various PID set points, etc.). These are then either bound to buttons on the OI, or built into more complex commands elsewhere.

Building Simple Commands

The QuickCommand class provides utility methods to create common types of commands from lambda expressions. The ones most commonly used on their own are

  • continuous: Run the given code in a loop until the command is interrupted. This is the first thing you should reach for when building "basic" commands like driving, running motors, and even stopping. For example:

    public class MyLifter extends Subsystem {
        private SpeedController myMotor;
        /* ... */
        public Command forwardCmd() {
            return QuickCommand.continuous(this, () -> myMotor.set(1.0));
        }
        public Command reverseCmd() {
            return QuickCommand.continuous(this, () -> myMotor.set(-1.0));
        }
        public Command stopCmd() {
            return QuickCommand.continuous(this, () -> myMotor.set(0.0));
        }
    }
  • oneShot: Run the given code once and then finish. This is mainly useful for miscellaneous tasks which do not require a subsystem, like turning a camera on/off, or toggling a setting.

    // Silly example.  null = doesn't require a subsystem
    Command sayHello = QuickCommand.oneShot(null, () -> System.out.println("Hello!"));
    // More realistic, assuming there's an object called `camera` with a
    // method called `setExposureLow`.
    Command setExposureLow = QuickCommand.oneShot(null, camera::setExposureLow);
  • pidMove: Move a given PIDController to a set point. Depending on the options passed, this either executes indefinitely, actively holding the set point, or it stops as soon as the set point is reached. If you're not sure which to use, your first guess should be to hold indefinitely. If you want to do something after the PID is in place, you can always waitFor the setpoint to be reached in parallel.

Clone this wiki locally