mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-20 00:51:42 +00:00
[command] Rename trigger methods (#4210)
Motivation Feedback from 2022 showed that the Trigger API is rather confusing, mostly due to the following: - duplicate Trigger and Button APIs were available; users were confused searching for a nonexistent difference between them. - the when terminology was ambiguous and unclear whether it refers to the high state or specifically the rising edge. - the Active terminology didn't unambiguously refer to the high state; it wasn't unintuitive to understand it as "when the binding is active/polled". - whileHeld vs whenHeld was very confusing, and the difference between them wasn't obvious. The parallel Trigger verbs, whileActiveContinuously and whileActiveOnce are much less confusing. Solution Deprecating Button and its binding methods. The rationale for deprecating Button (and not Trigger) is because Button uses terminology that is needlessly more specific and restricting to the button use case, making the use case of arbitrary trigger conditions unintuitive. After consideration, deprecation of Button's subclasses was decided against: - NetworkButton (a trigger condition based on a boolean NT entry/topic) is a use case that is not necessarily intuitive for teams to implement themselves, so it is an abstraction that should be provided in the library. A parallel class for the BooleanEvent level, NetworkBooleanEvent, was also added as part of NT4. NT listeners were considered as a alternative solution, but they require attention to thread safety, and aren't interoperable with the EventLoop API. - JoystickButton/POVButton provide abstractions around HID buttons. The new Trigger-returning factories on the HID classes are an equal (if not more concise) alternative, but there is no reason not to keep them for those who find their use preferable. At a later date in the deprecation cycle (perhaps for 2024), when Button is removed, these subclasses should be changed to inherit directly from Trigger. Trigger's bindings are changed to use True/False terminology, as it should be unambiguous. Each binding type has both True and False variants; for brevity, only the True variants are listed here: - onTrue (replaces whenActive): schedule on rising edge. - whileTrue (replaces whileActiveOnce): schedule on rising edge, cancel on falling edge. - toggleOnTrue (replaces toggleWhenActive): on rising edge, schedule if unscheduled and cancel if scheduled. Two binding types are completely deprecated: - cancelWhenActive: this is a fairly niche use case which is better described as having the trigger's rising edge (Trigger.rising()) as an end condition for the command (using Command.until()). - whileActiveContinuously: however common, this relied on the no-op behavior of scheduling an already-scheduled command. The more correct way to repeat the command if it ends before the falling edge is using Command.repeatedly/RepeatCommand or a RunCommand -- the only difference is if the command is interrupted, but that is more likely to result in two commands perpetually canceling each other than achieve the desired behavior. Manually implementing a blindly-scheduling binding like whileActiveContinuously is still possible, though might not be intuitive. Notes It was considered to share BooleanEvent's digital signal terminology; however, once it was decided that Trigger should not inherit from BooleanEvent (due to overload incompatibility) the common terminology was not worth the unintuitiveness stemming from users' unfamiliarity with the signal processing terms.
This commit is contained in:
@@ -55,29 +55,32 @@ public class RobotContainer {
|
||||
private void configureButtonBindings() {
|
||||
// Move the arm to 2 radians above horizontal when the 'A' button is pressed.
|
||||
new JoystickButton(m_driverController, Button.kA.value)
|
||||
.whenPressed(
|
||||
() -> {
|
||||
m_robotArm.setGoal(2);
|
||||
m_robotArm.enable();
|
||||
},
|
||||
m_robotArm);
|
||||
.onTrue(
|
||||
new InstantCommand(
|
||||
() -> {
|
||||
m_robotArm.setGoal(2);
|
||||
m_robotArm.enable();
|
||||
},
|
||||
m_robotArm));
|
||||
|
||||
// Move the arm to neutral position when the 'B' button is pressed.
|
||||
new JoystickButton(m_driverController, Button.kB.value)
|
||||
.whenPressed(
|
||||
() -> {
|
||||
m_robotArm.setGoal(Constants.ArmConstants.kArmOffsetRads);
|
||||
m_robotArm.enable();
|
||||
},
|
||||
m_robotArm);
|
||||
.onTrue(
|
||||
new InstantCommand(
|
||||
() -> {
|
||||
m_robotArm.setGoal(Constants.ArmConstants.kArmOffsetRads);
|
||||
m_robotArm.enable();
|
||||
},
|
||||
m_robotArm));
|
||||
|
||||
// Disable the arm controller when Y is pressed.
|
||||
new JoystickButton(m_driverController, Button.kY.value).whenPressed(m_robotArm::disable);
|
||||
new JoystickButton(m_driverController, Button.kY.value)
|
||||
.onTrue(new InstantCommand(m_robotArm::disable));
|
||||
|
||||
// Drive at half speed when the bumper is held
|
||||
new JoystickButton(m_driverController, Button.kRightBumper.value)
|
||||
.whenPressed(() -> m_robotDrive.setMaxOutput(0.5))
|
||||
.whenReleased(() -> m_robotDrive.setMaxOutput(1));
|
||||
.onTrue(new InstantCommand(() -> m_robotDrive.setMaxOutput(0.5)))
|
||||
.onFalse(new InstantCommand(() -> m_robotDrive.setMaxOutput(1)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -55,16 +55,18 @@ public class RobotContainer {
|
||||
private void configureButtonBindings() {
|
||||
// Move the arm to 2 radians above horizontal when the 'A' button is pressed.
|
||||
new JoystickButton(m_driverController, Button.kA.value)
|
||||
.whenPressed(() -> m_robotArm.setGoal(2), m_robotArm);
|
||||
.onTrue(new InstantCommand(() -> m_robotArm.setGoal(2), m_robotArm));
|
||||
|
||||
// Move the arm to neutral position when the 'B' button is pressed.
|
||||
new JoystickButton(m_driverController, Button.kB.value)
|
||||
.whenPressed(() -> m_robotArm.setGoal(Constants.ArmConstants.kArmOffsetRads), m_robotArm);
|
||||
.onTrue(
|
||||
new InstantCommand(
|
||||
() -> m_robotArm.setGoal(Constants.ArmConstants.kArmOffsetRads), m_robotArm));
|
||||
|
||||
// Drive at half speed when the bumper is held
|
||||
new JoystickButton(m_driverController, Button.kRightBumper.value)
|
||||
.whenPressed(() -> m_robotDrive.setMaxOutput(0.5))
|
||||
.whenReleased(() -> m_robotDrive.setMaxOutput(1));
|
||||
.onTrue(new InstantCommand(() -> m_robotDrive.setMaxOutput(0.5)))
|
||||
.onFalse(new InstantCommand(() -> m_robotDrive.setMaxOutput(1)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -57,11 +57,11 @@ public class RobotContainer {
|
||||
private void configureButtonBindings() {
|
||||
// Drive forward by 3 meters when the 'A' button is pressed, with a timeout of 10 seconds
|
||||
new JoystickButton(m_driverController, Button.kA.value)
|
||||
.whenPressed(new DriveDistanceProfiled(3, m_robotDrive).withTimeout(10));
|
||||
.onTrue(new DriveDistanceProfiled(3, m_robotDrive).withTimeout(10));
|
||||
|
||||
// Do the same thing as above when the 'B' button is pressed, but defined inline
|
||||
new JoystickButton(m_driverController, Button.kB.value)
|
||||
.whenPressed(
|
||||
.onTrue(
|
||||
new TrapezoidProfileCommand(
|
||||
new TrapezoidProfile(
|
||||
// Limit the max acceleration and velocity
|
||||
@@ -79,8 +79,8 @@ public class RobotContainer {
|
||||
|
||||
// Drive at half speed when the bumper is held
|
||||
new JoystickButton(m_driverController, Button.kRightBumper.value)
|
||||
.whenPressed(() -> m_robotDrive.setMaxOutput(0.5))
|
||||
.whenReleased(() -> m_robotDrive.setMaxOutput(1));
|
||||
.onTrue(new InstantCommand(() -> m_robotDrive.setMaxOutput(0.5)))
|
||||
.onFalse(new InstantCommand(() -> m_robotDrive.setMaxOutput(1)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -80,15 +80,15 @@ public class RobotContainer {
|
||||
private void configureButtonBindings() {
|
||||
// Spin up the shooter when the 'A' button is pressed
|
||||
new JoystickButton(m_driverController, Button.kA.value)
|
||||
.whenPressed(new InstantCommand(m_shooter::enable, m_shooter));
|
||||
.onTrue(new InstantCommand(m_shooter::enable, m_shooter));
|
||||
|
||||
// Turn off the shooter when the 'B' button is pressed
|
||||
new JoystickButton(m_driverController, Button.kB.value)
|
||||
.whenPressed(new InstantCommand(m_shooter::disable, m_shooter));
|
||||
.onTrue(new InstantCommand(m_shooter::disable, m_shooter));
|
||||
|
||||
// Run the feeder when the 'X' button is held, but only if the shooter is at speed
|
||||
new JoystickButton(m_driverController, Button.kX.value)
|
||||
.whenPressed(
|
||||
.onTrue(
|
||||
new ConditionalCommand(
|
||||
// Run the feeder
|
||||
new InstantCommand(m_shooter::runFeeder, m_shooter),
|
||||
@@ -97,12 +97,12 @@ public class RobotContainer {
|
||||
// Determine which of the above to do based on whether the shooter has reached the
|
||||
// desired speed
|
||||
m_shooter::atSetpoint))
|
||||
.whenReleased(new InstantCommand(m_shooter::stopFeeder, m_shooter));
|
||||
.onFalse(new InstantCommand(m_shooter::stopFeeder, m_shooter));
|
||||
|
||||
// Drive at half speed when the bumper is held
|
||||
new JoystickButton(m_driverController, Button.kRightBumper.value)
|
||||
.whenPressed(() -> m_robotDrive.setMaxOutput(0.5))
|
||||
.whenReleased(() -> m_robotDrive.setMaxOutput(1));
|
||||
.onTrue(new InstantCommand(() -> m_robotDrive.setMaxOutput(0.5)))
|
||||
.onFalse(new InstantCommand(() -> m_robotDrive.setMaxOutput(1)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -88,15 +88,15 @@ public class RobotContainer {
|
||||
final JoystickButton r1 = new JoystickButton(m_joystick, 12);
|
||||
|
||||
// Connect the buttons to commands
|
||||
dpadUp.whenPressed(new SetElevatorSetpoint(0.25, m_elevator));
|
||||
dpadDown.whenPressed(new SetElevatorSetpoint(0.0, m_elevator));
|
||||
dpadRight.whenPressed(new CloseClaw(m_claw));
|
||||
dpadLeft.whenPressed(new OpenClaw(m_claw));
|
||||
dpadUp.onTrue(new SetElevatorSetpoint(0.25, m_elevator));
|
||||
dpadDown.onTrue(new SetElevatorSetpoint(0.0, m_elevator));
|
||||
dpadRight.onTrue(new CloseClaw(m_claw));
|
||||
dpadLeft.onTrue(new OpenClaw(m_claw));
|
||||
|
||||
r1.whenPressed(new PrepareToPickup(m_claw, m_wrist, m_elevator));
|
||||
r2.whenPressed(new Pickup(m_claw, m_wrist, m_elevator));
|
||||
l1.whenPressed(new Place(m_claw, m_wrist, m_elevator));
|
||||
l2.whenPressed(new Autonomous(m_drivetrain, m_claw, m_wrist, m_elevator));
|
||||
r1.onTrue(new PrepareToPickup(m_claw, m_wrist, m_elevator));
|
||||
r2.onTrue(new Pickup(m_claw, m_wrist, m_elevator));
|
||||
l1.onTrue(new Place(m_claw, m_wrist, m_elevator));
|
||||
l2.onTrue(new Autonomous(m_drivetrain, m_claw, m_wrist, m_elevator));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -58,12 +58,12 @@ public class RobotContainer {
|
||||
private void configureButtonBindings() {
|
||||
// Drive at half speed when the right bumper is held
|
||||
new JoystickButton(m_driverController, Button.kR1.value)
|
||||
.whenPressed(() -> m_robotDrive.setMaxOutput(0.5))
|
||||
.whenReleased(() -> m_robotDrive.setMaxOutput(1));
|
||||
.onTrue(new InstantCommand(() -> m_robotDrive.setMaxOutput(0.5)))
|
||||
.onFalse(new InstantCommand(() -> m_robotDrive.setMaxOutput(1)));
|
||||
|
||||
// Stabilize robot to drive straight with gyro when left bumper is held
|
||||
new JoystickButton(m_driverController, Button.kL1.value)
|
||||
.whenHeld(
|
||||
.whileTrue(
|
||||
new PIDCommand(
|
||||
new PIDController(
|
||||
DriveConstants.kStabilizationP,
|
||||
@@ -80,11 +80,11 @@ public class RobotContainer {
|
||||
|
||||
// Turn to 90 degrees when the 'X' button is pressed, with a 5 second timeout
|
||||
new JoystickButton(m_driverController, Button.kCross.value)
|
||||
.whenPressed(new TurnToAngle(90, m_robotDrive).withTimeout(5));
|
||||
.onTrue(new TurnToAngle(90, m_robotDrive).withTimeout(5));
|
||||
|
||||
// Turn to -90 degrees with a profile when the Circle button is pressed, with a 5 second timeout
|
||||
new JoystickButton(m_driverController, Button.kCircle.value)
|
||||
.whenPressed(new TurnToAngleProfiled(-90, m_robotDrive).withTimeout(5));
|
||||
.onTrue(new TurnToAngleProfiled(-90, m_robotDrive).withTimeout(5));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -89,14 +89,14 @@ public class RobotContainer {
|
||||
private void configureButtonBindings() {
|
||||
// Grab the hatch when the Circle button is pressed.
|
||||
new JoystickButton(m_driverController, Button.kCircle.value)
|
||||
.whenPressed(new InstantCommand(m_hatchSubsystem::grabHatch, m_hatchSubsystem));
|
||||
.onTrue(new InstantCommand(m_hatchSubsystem::grabHatch, m_hatchSubsystem));
|
||||
// Release the hatch when the Square button is pressed.
|
||||
new JoystickButton(m_driverController, Button.kSquare.value)
|
||||
.whenPressed(new InstantCommand(m_hatchSubsystem::releaseHatch, m_hatchSubsystem));
|
||||
.onTrue(new InstantCommand(m_hatchSubsystem::releaseHatch, m_hatchSubsystem));
|
||||
// While holding R1, drive at half speed
|
||||
new JoystickButton(m_driverController, Button.kR1.value)
|
||||
.whenPressed(() -> m_robotDrive.setMaxOutput(0.5))
|
||||
.whenReleased(() -> m_robotDrive.setMaxOutput(1));
|
||||
.onTrue(new InstantCommand(() -> m_robotDrive.setMaxOutput(0.5)))
|
||||
.onFalse(new InstantCommand(() -> m_robotDrive.setMaxOutput(1)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -78,14 +78,13 @@ public class RobotContainer {
|
||||
*/
|
||||
private void configureButtonBindings() {
|
||||
// Grab the hatch when the 'A' button is pressed.
|
||||
new JoystickButton(m_driverController, Button.kA.value)
|
||||
.whenPressed(new GrabHatch(m_hatchSubsystem));
|
||||
new JoystickButton(m_driverController, Button.kA.value).onTrue(new GrabHatch(m_hatchSubsystem));
|
||||
// Release the hatch when the 'B' button is pressed.
|
||||
new JoystickButton(m_driverController, Button.kB.value)
|
||||
.whenPressed(new ReleaseHatch(m_hatchSubsystem));
|
||||
.onTrue(new ReleaseHatch(m_hatchSubsystem));
|
||||
// While holding the shoulder button, drive at half speed
|
||||
new JoystickButton(m_driverController, Button.kRightBumper.value)
|
||||
.whenHeld(new HalveDriveSpeed(m_robotDrive));
|
||||
.whileTrue(new HalveDriveSpeed(m_robotDrive));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,6 +19,7 @@ import edu.wpi.first.wpilibj.examples.mecanumcontrollercommand.Constants.DriveCo
|
||||
import edu.wpi.first.wpilibj.examples.mecanumcontrollercommand.Constants.OIConstants;
|
||||
import edu.wpi.first.wpilibj.examples.mecanumcontrollercommand.subsystems.DriveSubsystem;
|
||||
import edu.wpi.first.wpilibj2.command.Command;
|
||||
import edu.wpi.first.wpilibj2.command.InstantCommand;
|
||||
import edu.wpi.first.wpilibj2.command.MecanumControllerCommand;
|
||||
import edu.wpi.first.wpilibj2.command.RunCommand;
|
||||
import edu.wpi.first.wpilibj2.command.button.JoystickButton;
|
||||
@@ -66,8 +67,8 @@ public class RobotContainer {
|
||||
private void configureButtonBindings() {
|
||||
// Drive at half speed when the right bumper is held
|
||||
new JoystickButton(m_driverController, Button.kRightBumper.value)
|
||||
.whenPressed(() -> m_robotDrive.setMaxOutput(0.5))
|
||||
.whenReleased(() -> m_robotDrive.setMaxOutput(1));
|
||||
.onTrue(new InstantCommand(() -> m_robotDrive.setMaxOutput(0.5)))
|
||||
.onFalse(new InstantCommand(() -> m_robotDrive.setMaxOutput(1)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,6 +22,7 @@ import edu.wpi.first.wpilibj.examples.ramsetecommand.Constants.DriveConstants;
|
||||
import edu.wpi.first.wpilibj.examples.ramsetecommand.Constants.OIConstants;
|
||||
import edu.wpi.first.wpilibj.examples.ramsetecommand.subsystems.DriveSubsystem;
|
||||
import edu.wpi.first.wpilibj2.command.Command;
|
||||
import edu.wpi.first.wpilibj2.command.InstantCommand;
|
||||
import edu.wpi.first.wpilibj2.command.RamseteCommand;
|
||||
import edu.wpi.first.wpilibj2.command.RunCommand;
|
||||
import edu.wpi.first.wpilibj2.command.button.JoystickButton;
|
||||
@@ -66,8 +67,8 @@ public class RobotContainer {
|
||||
private void configureButtonBindings() {
|
||||
// Drive at half speed when the right bumper is held
|
||||
new JoystickButton(m_driverController, Button.kRightBumper.value)
|
||||
.whenPressed(() -> m_robotDrive.setMaxOutput(0.5))
|
||||
.whenReleased(() -> m_robotDrive.setMaxOutput(1));
|
||||
.onTrue(new InstantCommand(() -> m_robotDrive.setMaxOutput(0.5)))
|
||||
.onFalse(new InstantCommand(() -> m_robotDrive.setMaxOutput(1)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,7 +17,7 @@ import edu.wpi.first.wpilibj.smartdashboard.SendableChooser;
|
||||
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
|
||||
import edu.wpi.first.wpilibj2.command.Command;
|
||||
import edu.wpi.first.wpilibj2.command.PrintCommand;
|
||||
import edu.wpi.first.wpilibj2.command.button.Button;
|
||||
import edu.wpi.first.wpilibj2.command.button.Trigger;
|
||||
|
||||
/**
|
||||
* This class is where the bulk of the robot should be declared. Since Command-based is a
|
||||
@@ -65,10 +65,10 @@ public class RobotContainer {
|
||||
m_drivetrain.setDefaultCommand(getArcadeDriveCommand());
|
||||
|
||||
// Example of how to use the onboard IO
|
||||
Button onboardButtonA = new Button(m_onboardIO::getButtonAPressed);
|
||||
Trigger onboardButtonA = new Trigger(m_onboardIO::getButtonAPressed);
|
||||
onboardButtonA
|
||||
.whenActive(new PrintCommand("Button A Pressed"))
|
||||
.whenInactive(new PrintCommand("Button A Released"));
|
||||
.onTrue(new PrintCommand("Button A Pressed"))
|
||||
.onFalse(new PrintCommand("Button A Released"));
|
||||
|
||||
// Setup SmartDashboard options
|
||||
m_chooser.setDefaultOption("Auto Routine Distance", new AutonomousDistance(m_drivetrain));
|
||||
|
||||
@@ -70,11 +70,11 @@ public class RobotContainer {
|
||||
*/
|
||||
private void configureButtonBindings() {
|
||||
// Run instant command 1 when the 'A' button is pressed
|
||||
new JoystickButton(m_driverController, Button.kA.value).whenPressed(m_instantCommand1);
|
||||
new JoystickButton(m_driverController, Button.kA.value).onTrue(m_instantCommand1);
|
||||
// Run instant command 2 when the 'X' button is pressed
|
||||
new JoystickButton(m_driverController, Button.kX.value).whenPressed(m_instantCommand2);
|
||||
new JoystickButton(m_driverController, Button.kX.value).onTrue(m_instantCommand2);
|
||||
// Run instant command 3 when the 'Y' button is held; release early to interrupt
|
||||
new JoystickButton(m_driverController, Button.kY.value).whenHeld(m_waitCommand);
|
||||
new JoystickButton(m_driverController, Button.kY.value).whileTrue(m_waitCommand);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,6 +18,7 @@ import edu.wpi.first.wpilibj.XboxController;
|
||||
import edu.wpi.first.wpilibj.XboxController.Button;
|
||||
import edu.wpi.first.wpilibj.examples.statespacedifferentialdrivesimulation.subsystems.DriveSubsystem;
|
||||
import edu.wpi.first.wpilibj2.command.Command;
|
||||
import edu.wpi.first.wpilibj2.command.InstantCommand;
|
||||
import edu.wpi.first.wpilibj2.command.RamseteCommand;
|
||||
import edu.wpi.first.wpilibj2.command.RunCommand;
|
||||
import edu.wpi.first.wpilibj2.command.button.JoystickButton;
|
||||
@@ -66,8 +67,8 @@ public class RobotContainer {
|
||||
private void configureButtonBindings() {
|
||||
// Drive at half speed when the right bumper is held
|
||||
new JoystickButton(m_driverController, Button.kRightBumper.value)
|
||||
.whenPressed(() -> m_robotDrive.setMaxOutput(0.5))
|
||||
.whenReleased(() -> m_robotDrive.setMaxOutput(1));
|
||||
.onTrue(new InstantCommand(() -> m_robotDrive.setMaxOutput(0.5)))
|
||||
.onFalse(new InstantCommand(() -> m_robotDrive.setMaxOutput(1)));
|
||||
}
|
||||
|
||||
public DriveSubsystem getRobotDrive() {
|
||||
|
||||
Reference in New Issue
Block a user