Spot the Error
The Purpose of this Section
Section titled “The Purpose of this Section”By looking through buggy code snippets that use command-based programming, you can hopefully get a better intuition on how to spot common bugs and write better code. If you are confident in your skills, you can skip ahead to the stage 1B exercise, but the authors still highly recommend it.
Unless otherwise mentioned, code snippets in this section do not have compile-time errors.
Exercise 1
Section titled “Exercise 1”This code is supposed to spin the intake while the left bumper is held. The intake should stop when the bumper is released. It also compiles fine.
new Trigger(() -> xbox.getLeftBumper()).onTrue(intake.runAtThrottle(0.5));Can you spot the error?
Reveal
The onTrue() binding schedules the command once, when the bumper is first pressed.
The command keeps running even after the bumper is released.
Use whileTrue() instead, which runs the command for as long as the trigger is active:
new Trigger(() -> xbox.getLeftBumper()).whileTrue(intake.runAtThrottle(0.5));Exercise 2
Section titled “Exercise 2”The aButtonTrigger is supposed to run a command while the A button is held.
The code compiles fine.
boolean aButton = xbox.getAButton();Trigger aButtonTrigger = new Trigger(() -> aButton);aButtonTrigger.whileTrue(intake.runAtThrottle(0.5));Can you spot the error?
Reveal
The button is read once, before the trigger is created.
The trigger always checks the same stored value, so it either runs forever or never runs at all.
Read the button inside the trigger’s lambda instead:
Trigger aButtonTrigger = new Trigger(() -> xbox.getAButton());aButtonTrigger.whileTrue(intake.runAtThrottle(0.5));Exercise 3
Section titled “Exercise 3”class Intake implements Mechanism { private final ExampleMotor motor = new ExampleMotor();
Command runAtThrottle(double throttle) { return Command.noRequirements(coroutine -> { while (false) { // Compile-time error: Unreachable statement motor.setThrottle(throttle); coroutine.yield(); } }) .named("Intake"); }}Can you fix the compile-time error and the logic error?
Reveal
The goal is for the commands to set the motor’s throttle forever, so
while (true) should be used instead of while (false). A
while (false) statement will never run!
Furthermore, the intake() Command needs to require the Intake mechanism.
So, run(coroutine -> {}) should be used in place of Command.noRequirements(coroutine -> {}).
class Intake implements Mechanism { private final ExampleMotor motor = new ExampleMotor();
Command runAtThrottle(double throttle) { return run(coroutine -> { while (true) { motor.setThrottle(throttle); coroutine.yield(); } }) .named("Intake"); }}Exercise 4
Section titled “Exercise 4”You’ve fixed the intake (reveal the answer to exercise 3 to see the full class), and have the following code to run it while the A button is held:
new Trigger(() -> xbox.getLeftBumper()).whileTrue(intake.runAtThrottle(0.5));You hold down the A button, and the intake starts spinning; but releasing it doesn’t stop the intake. Can you spot the error?
Hint
Setting the Intake’s default command might help you. But why?
Reveal
When you call motor.setThrottle(double), the motor will start spinning forever,
even if you aren’t calling setThrottle anymore. Even though releasing the A button
will cancel the runAtThrottle command, it won’t stop the motor.
To fix this, we set a default command. The default command for a mechanism will always run when no other commands are requiring that mechanism. In this case, “no other command to the intake” = “we want to stop the intake”, so the default command is setting the throttle to 0.
class Intake implements Mechanism { private final ExampleMotor motor = new ExampleMotor();
public Intake() { setDefaultCommand(runAtThrottle(0)); }
Command runAtThrottle(double throttle) { return run(coroutine -> { while (true) { motor.setThrottle(throttle); coroutine.yield(); } }) .named("Intake"); }}