Skip to content

Suppliers in Command-Based

Let’s say that we define an Intake mechanism:

class Intake implements Mechanism {
// Placeholder for TalonFX, SparkMax or SparkFlex
private final ExampleMotor motor = new ExampleMotor();
public Command runAtThrottle(double throttle) {
return run(coroutine -> {
while (true) {
motor.setThrottle(throttle);
coroutine.yield();
}
})
.named("Run Intake");
}
}

And the following code in Robot.java:

class Robot {
public Robot() {
var xbox = new CommandXboxController(0);
var intake = new Intake();
double controllerOutput = xbox.getLeftY();
intake.setDefaultCommand(intake.runAtThrottle(controllerOutput));
}
}
Note

In case you forgot, getLeftY() returns a value between -1 and 1. If the left joystick isn’t pushed at all, getLeftY() returns 0; if it’s pushed all the way up, getLeftY() returns 1; and if it’s pushed all the way down, getLeftY() returns -1.

When you run the code above, what happens?

  1. The intake does a little dance before rejoicing your coding skills.
  2. The intake runs at a speed dependent on how far up or down the joystick on the left is pushed.
  3. The intake does nothing.

Solution #3: The intake does nothing.

Recall that the constructor of the Robot class is called when the robot code is first loaded, not when the robot is enabled. At this point, your hands aren’t even on the controller - so, the value of controllerOutput would be 0.

When the robot is enabled, the value of getLeftY() will change; however, the value of the throttle parameter passed into the runAtThrottle command cannot, because it’s value has already been determined before the command has even began.

In java, we use a DoubleSupplier to represent a value of type double that is constantly changing. We call getAsDouble() to fetch its current value.

public Command runAtThrottle(DoubleSupplier throttleSupplier) {
return run(coroutine -> {
while (true) {
double throttle = throttleSupplier.getAsDouble();
motor.setThrottle(throttle);
coroutine.yield();
}
})
.named("Run Intake");
}

DoubleSupplier instances are created with the syntax of () -> expression, with the caveat that the expression must return a double. Calling getAsDouble() will evaluate that expression.

DoubleSupplier supplier = () -> xbox.getLeftY();
double controllerOutput = supplier.getAsDouble();
Note

The () -> ... syntax for defining a DoubleSupplier is also called a lambda expression.

Here is how we would define and use a DoubleSupplier in our previous example:

class Robot {
public Robot() {
var xbox = new CommandXboxController(0);
var intake = new Intake();
intake.setDefaultCommand(intake.runAtThrottle(() -> xbox.getLeftY()));
}
}

BooleanSuppliers and the until() Command Modifier

Section titled “BooleanSuppliers and the until() Command Modifier”

You might recognize the () -> syntax used to define DoubleSuppliers. As it turns out, we define Triggers with that syntax:

new Trigger(() -> motor.speed() > 60);

Notice, however, that the expression to the left of the () -> statement is a boolean instead of a double. As it turns out, the constructor for a Trigger takes a BooleanSupplier.

Note

To fetch the latest value of a BooleanSupplier, you would call getAsBoolean() instead.

BooleanSuppliers are used in one other place: adding stop conditions to commands. You can use the until(BooleanSupplier) method to add an arbitrary stop condition to a command:

// From the Intake class mentioned earlier
public Command fullThrottleUntilRobotDisabled() {
return fullThrottle().until(() -> RobotState.isDisabled()).named("Full Throttle Until Disable");
}
private Command fullThrottle() {
return null; // placeholder for actual command
}