[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:
Starlight220
2022-10-28 08:03:28 +03:00
committed by GitHub
parent 66157397c1
commit dcda09f90a
50 changed files with 1090 additions and 645 deletions

View File

@@ -17,7 +17,10 @@ import java.util.function.BooleanSupplier;
* <p>This class represents a subclass of Trigger that is specifically aimed at buttons on an
* operator interface as a common use case of the more generalized Trigger objects. This is a simple
* wrapper around Trigger with the method names renamed to fit the Button object use.
*
* @deprecated Replace with {@link Trigger}.
*/
@Deprecated
public class Button extends Trigger {
/**
* Default constructor; creates a button that is never pressed.
@@ -31,7 +34,9 @@ public class Button extends Trigger {
* Creates a new button with the given condition determining whether it is pressed.
*
* @param isPressed returns whether or not the trigger should be active
* @deprecated Replace with Trigger.
*/
@Deprecated
public Button(BooleanSupplier isPressed) {
super(isPressed);
}
@@ -41,7 +46,9 @@ public class Button extends Trigger {
*
* @param command the command to start
* @return this button, so calls can be chained
* @deprecated Replace with {@link Trigger#onTrue(Command)}
*/
@Deprecated
public Button whenPressed(final Command command) {
whenActive(command);
return this;
@@ -53,7 +60,9 @@ public class Button extends Trigger {
* @param toRun the runnable to run
* @param requirements the required subsystems
* @return this button, so calls can be chained
* @deprecated Replace with {@link #onTrue(Command)}, creating the InstantCommand manually
*/
@Deprecated
public Button whenPressed(final Runnable toRun, Subsystem... requirements) {
whenActive(toRun, requirements);
return this;
@@ -67,7 +76,10 @@ public class Button extends Trigger {
*
* @param command the command to start
* @return this button, so calls can be chained
* @deprecated Use {@link #whileTrue(Command)} with {@link
* edu.wpi.first.wpilibj2.command.RepeatCommand RepeatCommand}.
*/
@Deprecated
public Button whileHeld(final Command command) {
whileActiveContinuous(command);
return this;
@@ -79,7 +91,9 @@ public class Button extends Trigger {
* @param toRun the runnable to run
* @param requirements the required subsystems
* @return this button, so calls can be chained
* @deprecated Use {@link #whileTrue(Command)} and construct a RunCommand manually
*/
@Deprecated
public Button whileHeld(final Runnable toRun, Subsystem... requirements) {
whileActiveContinuous(toRun, requirements);
return this;
@@ -91,7 +105,9 @@ public class Button extends Trigger {
*
* @param command the command to start
* @return this button, so calls can be chained
* @deprecated Replace with {@link Trigger#whileTrue(Command)}
*/
@Deprecated
public Button whenHeld(final Command command) {
whileActiveOnce(command);
return this;
@@ -102,7 +118,9 @@ public class Button extends Trigger {
*
* @param command the command to start
* @return this button, so calls can be chained
* @deprecated Replace with {@link Trigger#onFalse(Command)}
*/
@Deprecated
public Button whenReleased(final Command command) {
whenInactive(command);
return this;
@@ -114,7 +132,9 @@ public class Button extends Trigger {
* @param toRun the runnable to run
* @param requirements the required subsystems
* @return this button, so calls can be chained
* @deprecated Replace with {@link Trigger#onFalse(Command)}, creating the InstantCommand manually
*/
@Deprecated
public Button whenReleased(final Runnable toRun, Subsystem... requirements) {
whenInactive(toRun, requirements);
return this;
@@ -126,7 +146,9 @@ public class Button extends Trigger {
*
* @param command the command to start
* @return this button, so calls can be chained
* @deprecated Replace with {@link Trigger#toggleOnTrue(Command)}
*/
@Deprecated
public Button toggleWhenPressed(final Command command) {
toggleWhenActive(command);
return this;
@@ -137,7 +159,10 @@ public class Button extends Trigger {
*
* @param command the command to start
* @return this button, so calls can be chained
* @deprecated Instead, pass {@link #rising()} as an end condition to {@link
* Command#until(BooleanSupplier)}.
*/
@Deprecated
public Button cancelWhenPressed(final Command command) {
cancelWhenActive(command);
return this;

View File

@@ -12,6 +12,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
*
* <p>This class is provided by the NewCommands VendorDep
*/
@SuppressWarnings("deprecation")
public class InternalButton extends Button {
// need to be references, so they can be mutated after being captured in the constructor.
private final AtomicBoolean m_pressed;

View File

@@ -13,6 +13,7 @@ import edu.wpi.first.wpilibj.GenericHID;
*
* <p>This class is provided by the NewCommands VendorDep
*/
@SuppressWarnings("deprecation")
public class JoystickButton extends Button {
/**
* Creates a joystick button for triggering commands.

View File

@@ -16,6 +16,7 @@ import edu.wpi.first.networktables.NetworkTableInstance;
*
* <p>This class is provided by the NewCommands VendorDep
*/
@SuppressWarnings("deprecation")
public class NetworkButton extends Button {
/**
* Creates a NetworkButton that commands can be bound to.

View File

@@ -13,6 +13,7 @@ import edu.wpi.first.wpilibj.GenericHID;
*
* <p>This class is provided by the NewCommands VendorDep
*/
@SuppressWarnings("deprecation")
public class POVButton extends Button {
/**
* Creates a POV button for triggering commands.

View File

@@ -22,7 +22,9 @@ import java.util.function.BooleanSupplier;
*
* <p>This class is provided by the NewCommands VendorDep
*/
public class Trigger extends BooleanEvent {
public class Trigger implements BooleanSupplier {
private final BooleanEvent m_event;
/**
* Creates a new trigger with the given condition/digital signal.
*
@@ -30,7 +32,7 @@ public class Trigger extends BooleanEvent {
* @param signal the digital signal represented.
*/
public Trigger(EventLoop loop, BooleanSupplier signal) {
super(loop, signal);
m_event = new BooleanEvent(loop, signal);
}
/**
@@ -62,18 +64,103 @@ public class Trigger extends BooleanEvent {
}
/**
* Returns whether or not the trigger is active.
* Starts the given command whenever the signal rises from the low state to the high state.
*
* <p>This method will be called repeatedly a command is linked to the Trigger.
*
* <p>Functionally identical to {@link Trigger#getAsBoolean()}.
*
* @return whether or not the trigger condition is active.
* @deprecated use {@link #getAsBoolean()}
* @param command the command to start
* @return this trigger, so calls can be chained
* @see #rising()
*/
@Deprecated
public final boolean get() {
return getAsBoolean();
public Trigger onTrue(Command command) {
requireNonNullParam(command, "command", "onRising");
m_event.rising().ifHigh(command::schedule);
return this;
}
/**
* Starts the given command whenever the signal falls from the high state to the low state.
*
* @param command the command to start
* @return this trigger, so calls can be chained
* @see #falling()
*/
public Trigger onFalse(Command command) {
requireNonNullParam(command, "command", "onFalling");
m_event.falling().ifHigh(command::schedule);
return this;
}
/**
* Starts the given command when the signal rises to the high state and cancels it when the signal
* falls.
*
* <p>Doesn't re-start the command in-between.
*
* @param command the command to start
* @return this trigger, so calls can be chained
*/
public Trigger whileTrue(Command command) {
requireNonNullParam(command, "command", "whileHigh");
m_event.rising().ifHigh(command::schedule);
m_event.falling().ifHigh(command::cancel);
return this;
}
/**
* Starts the given command when the signal falls to the low state and cancels it when the signal
* rises.
*
* <p>Does not re-start the command in-between.
*
* @param command the command to start
* @return this trigger, so calls can be chained
*/
public Trigger whileFalse(Command command) {
requireNonNullParam(command, "command", "whileLow");
m_event.falling().ifHigh(command::schedule);
m_event.rising().ifHigh(command::cancel);
return this;
}
/**
* Toggles a command when the signal rises from the low state to the high state.
*
* @param command the command to toggle
* @return this trigger, so calls can be chained
*/
public Trigger toggleOnTrue(Command command) {
requireNonNullParam(command, "command", "toggleOnRising");
m_event
.rising()
.ifHigh(
() -> {
if (!command.isScheduled()) {
command.schedule();
} else {
command.cancel();
}
});
return this;
}
/**
* Toggles a command when the signal rises from the low state to the high state.
*
* @param command the command to toggle
* @return this trigger, so calls can be chained
*/
public Trigger toggleOnFalse(Command command) {
requireNonNullParam(command, "command", "toggleOnFalling");
m_event
.falling()
.ifHigh(
() -> {
if (!command.isScheduled()) {
command.schedule();
} else {
command.cancel();
}
});
return this;
}
/**
@@ -81,11 +168,13 @@ public class Trigger extends BooleanEvent {
*
* @param command the command to start
* @return this trigger, so calls can be chained
* @deprecated Use {@link #onTrue(Command)} instead.
*/
@Deprecated
public Trigger whenActive(final Command command) {
requireNonNullParam(command, "command", "whenActive");
this.rising().ifHigh(command::schedule);
m_event.rising().ifHigh(command::schedule);
return this;
}
@@ -95,7 +184,9 @@ public class Trigger extends BooleanEvent {
* @param toRun the runnable to run
* @param requirements the required subsystems
* @return this trigger, so calls can be chained
* @deprecated Replace with {@link #onTrue(Command)}, creating the InstantCommand manually
*/
@Deprecated
public Trigger whenActive(final Runnable toRun, Subsystem... requirements) {
return whenActive(new InstantCommand(toRun, requirements));
}
@@ -108,12 +199,17 @@ public class Trigger extends BooleanEvent {
*
* @param command the command to start
* @return this trigger, so calls can be chained
* @deprecated Use {@link #whileTrue(Command)} with {@link
* edu.wpi.first.wpilibj2.command.RepeatCommand RepeatCommand}, or bind {@link
* Command#schedule() command::schedule} to {@link BooleanEvent#ifHigh(Runnable)} (passing no
* requirements).
*/
@Deprecated
public Trigger whileActiveContinuous(final Command command) {
requireNonNullParam(command, "command", "whileActiveContinuous");
this.ifHigh(command::schedule);
this.falling().ifHigh(command::cancel);
m_event.ifHigh(command::schedule);
m_event.falling().ifHigh(command::cancel);
return this;
}
@@ -124,7 +220,9 @@ public class Trigger extends BooleanEvent {
* @param toRun the runnable to run
* @param requirements the required subsystems
* @return this trigger, so calls can be chained
* @deprecated Use {@link #whileTrue(Command)} and construct a RunCommand manually
*/
@Deprecated
public Trigger whileActiveContinuous(final Runnable toRun, Subsystem... requirements) {
return whileActiveContinuous(new InstantCommand(toRun, requirements));
}
@@ -135,12 +233,14 @@ public class Trigger extends BooleanEvent {
*
* @param command the command to start
* @return this trigger, so calls can be chained
* @deprecated Use {@link #whileTrue(Command)} instead.
*/
@Deprecated
public Trigger whileActiveOnce(final Command command) {
requireNonNullParam(command, "command", "whileActiveOnce");
this.rising().ifHigh(command::schedule);
this.falling().ifHigh(command::cancel);
m_event.rising().ifHigh(command::schedule);
m_event.falling().ifHigh(command::cancel);
return this;
}
@@ -150,11 +250,13 @@ public class Trigger extends BooleanEvent {
*
* @param command the command to start
* @return this trigger, so calls can be chained
* @deprecated Use {@link #onFalse(Command)} instead.
*/
@Deprecated
public Trigger whenInactive(final Command command) {
requireNonNullParam(command, "command", "whenInactive");
this.falling().ifHigh(command::schedule);
m_event.falling().ifHigh(command::schedule);
return this;
}
@@ -165,7 +267,9 @@ public class Trigger extends BooleanEvent {
* @param toRun the runnable to run
* @param requirements the required subsystems
* @return this trigger, so calls can be chained
* @deprecated Construct the InstantCommand manually and replace with {@link #onFalse(Command)}
*/
@Deprecated
public Trigger whenInactive(final Runnable toRun, Subsystem... requirements) {
return whenInactive(new InstantCommand(toRun, requirements));
}
@@ -175,11 +279,14 @@ public class Trigger extends BooleanEvent {
*
* @param command the command to toggle
* @return this trigger, so calls can be chained
* @deprecated Use {@link #toggleOnTrue(Command)} instead.
*/
@Deprecated
public Trigger toggleWhenActive(final Command command) {
requireNonNullParam(command, "command", "toggleWhenActive");
this.rising()
m_event
.rising()
.ifHigh(
() -> {
if (command.isScheduled()) {
@@ -197,49 +304,57 @@ public class Trigger extends BooleanEvent {
*
* @param command the command to cancel
* @return this trigger, so calls can be chained
* @deprecated Instead, pass {@link #rising()} as an end condition to {@link
* Command#until(BooleanSupplier)}.
*/
@Deprecated
public Trigger cancelWhenActive(final Command command) {
requireNonNullParam(command, "command", "cancelWhenActive");
this.rising().ifHigh(command::cancel);
m_event.rising().ifHigh(command::cancel);
return this;
}
/* ----------- Super method type redeclarations ----------------- */
/**
* Get the wrapped BooleanEvent.
*
* @return the wrapped BooleanEvent instance.
*/
public BooleanEvent getEvent() {
return m_event;
}
@Override
public boolean getAsBoolean() {
return m_event.getAsBoolean();
}
public Trigger and(BooleanSupplier trigger) {
return cast(super.and(trigger));
return cast(m_event.and(trigger));
}
@Override
public Trigger or(BooleanSupplier trigger) {
return cast(super.or(trigger));
return cast(m_event.or(trigger));
}
@Override
public Trigger negate() {
return cast(super.negate());
return cast(m_event.negate());
}
@Override
public Trigger debounce(double seconds) {
return debounce(seconds, Debouncer.DebounceType.kRising);
}
@Override
public Trigger debounce(double seconds, Debouncer.DebounceType type) {
return cast(super.debounce(seconds, type));
return cast(m_event.debounce(seconds, type));
}
@Override
public Trigger rising() {
return cast(super.rising());
return cast(m_event.rising());
}
@Override
public Trigger falling() {
return cast(super.falling());
return cast(m_event.falling());
}
}

View File

@@ -9,92 +9,91 @@ using namespace frc2;
Button::Button(std::function<bool()> isPressed) : Trigger(isPressed) {}
Button Button::WhenPressed(Command* command) {
WPI_IGNORE_DEPRECATED
WhenActive(command);
return *this;
}
Button Button::WhenPressed(CommandPtr&& command) {
WhenActive(std::move(command));
WPI_UNIGNORE_DEPRECATED
return *this;
}
Button Button::WhenPressed(std::function<void()> toRun,
std::initializer_list<Subsystem*> requirements) {
WPI_IGNORE_DEPRECATED
WhenActive(std::move(toRun), requirements);
WPI_UNIGNORE_DEPRECATED
return *this;
}
Button Button::WhenPressed(std::function<void()> toRun,
std::span<Subsystem* const> requirements) {
WPI_IGNORE_DEPRECATED
WhenActive(std::move(toRun), requirements);
WPI_UNIGNORE_DEPRECATED
return *this;
}
Button Button::WhileHeld(Command* command) {
WPI_IGNORE_DEPRECATED
WhileActiveContinous(command);
return *this;
}
Button Button::WhileHeld(CommandPtr&& command) {
WhileActiveContinous(std::move(command));
WPI_UNIGNORE_DEPRECATED
return *this;
}
Button Button::WhileHeld(std::function<void()> toRun,
std::initializer_list<Subsystem*> requirements) {
WPI_IGNORE_DEPRECATED
WhileActiveContinous(std::move(toRun), requirements);
WPI_UNIGNORE_DEPRECATED
return *this;
}
Button Button::WhileHeld(std::function<void()> toRun,
std::span<Subsystem* const> requirements) {
WPI_IGNORE_DEPRECATED
WhileActiveContinous(std::move(toRun), requirements);
WPI_UNIGNORE_DEPRECATED
return *this;
}
Button Button::WhenHeld(Command* command) {
WPI_IGNORE_DEPRECATED
WhileActiveOnce(command);
return *this;
}
Button Button::WhenHeld(CommandPtr&& command) {
WhileActiveOnce(std::move(command));
WPI_UNIGNORE_DEPRECATED
return *this;
}
Button Button::WhenReleased(Command* command) {
WPI_IGNORE_DEPRECATED
WhenInactive(command);
return *this;
}
Button Button::WhenReleased(CommandPtr&& command) {
WhenInactive(std::move(command));
WPI_UNIGNORE_DEPRECATED
return *this;
}
Button Button::WhenReleased(std::function<void()> toRun,
std::initializer_list<Subsystem*> requirements) {
WPI_IGNORE_DEPRECATED
WhenInactive(std::move(toRun), requirements);
WPI_UNIGNORE_DEPRECATED
return *this;
}
Button Button::WhenReleased(std::function<void()> toRun,
std::span<Subsystem* const> requirements) {
WPI_IGNORE_DEPRECATED
WhenInactive(std::move(toRun), requirements);
WPI_UNIGNORE_DEPRECATED
return *this;
}
Button Button::ToggleWhenPressed(Command* command) {
WPI_IGNORE_DEPRECATED
ToggleWhenActive(command);
return *this;
}
Button Button::ToggleWhenPressed(CommandPtr&& command) {
ToggleWhenActive(std::move(command));
WPI_UNIGNORE_DEPRECATED
return *this;
}
Button Button::CancelWhenPressed(Command* command) {
WPI_IGNORE_DEPRECATED
CancelWhenActive(command);
WPI_UNIGNORE_DEPRECATED
return *this;
}

View File

@@ -4,8 +4,11 @@
#include "frc2/command/button/NetworkButton.h"
#include <wpi/deprecated.h>
using namespace frc2;
WPI_IGNORE_DEPRECATED
NetworkButton::NetworkButton(nt::BooleanTopic topic)
: NetworkButton(topic.Subscribe(false)) {}
@@ -13,6 +16,7 @@ NetworkButton::NetworkButton(nt::BooleanSubscriber sub)
: Button([sub = std::make_shared<nt::BooleanSubscriber>(std::move(sub))] {
return sub->GetTopic().GetInstance().IsConnected() && sub->Get();
}) {}
WPI_UNIGNORE_DEPRECATED
NetworkButton::NetworkButton(std::shared_ptr<nt::NetworkTable> table,
std::string_view field)

View File

@@ -13,13 +13,101 @@ using namespace frc2;
Trigger::Trigger(const Trigger& other) = default;
Trigger Trigger::WhenActive(Command* command) {
this->Rising().IfHigh([command] { command->Schedule(); });
Trigger Trigger::OnTrue(Command* command) {
m_event.Rising().IfHigh([command] { command->Schedule(); });
return *this;
}
Trigger Trigger::WhenActive(CommandPtr&& command) {
this->Rising().IfHigh([command = std::move(command)] { command.Schedule(); });
Trigger Trigger::OnTrue(CommandPtr&& command) {
m_event.Rising().IfHigh(
[command = std::move(command)] { command.Schedule(); });
return *this;
}
Trigger Trigger::OnFalse(Command* command) {
m_event.Falling().IfHigh([command] { command->Schedule(); });
return *this;
}
Trigger Trigger::OnFalse(CommandPtr&& command) {
m_event.Falling().IfHigh(
[command = std::move(command)] { command.Schedule(); });
return *this;
}
Trigger Trigger::WhileTrue(Command* command) {
m_event.Rising().IfHigh([command] { command->Schedule(); });
m_event.Falling().IfHigh([command] { command->Cancel(); });
return *this;
}
Trigger Trigger::WhileTrue(CommandPtr&& command) {
auto ptr = std::make_shared<CommandPtr>(std::move(command));
m_event.Rising().IfHigh([ptr] { ptr->Schedule(); });
m_event.Falling().IfHigh([ptr] { ptr->Cancel(); });
return *this;
}
Trigger Trigger::WhileFalse(Command* command) {
m_event.Falling().IfHigh([command] { command->Schedule(); });
m_event.Rising().IfHigh([command] { command->Cancel(); });
return *this;
}
Trigger Trigger::WhileFalse(CommandPtr&& command) {
auto ptr = std::make_shared<CommandPtr>(std::move(command));
m_event.Falling().IfHigh([ptr] { ptr->Schedule(); });
m_event.Rising().IfHigh([ptr] { ptr->Cancel(); });
return *this;
}
Trigger Trigger::ToggleOnTrue(Command* command) {
m_event.Rising().IfHigh([command] {
if (command->IsScheduled()) {
command->Cancel();
} else {
command->Schedule();
}
});
return *this;
}
Trigger Trigger::ToggleOnTrue(CommandPtr&& command) {
m_event.Rising().IfHigh([command = std::move(command)] {
if (command.IsScheduled()) {
command.Cancel();
} else {
command.Schedule();
}
});
return *this;
}
Trigger Trigger::ToggleOnFalse(Command* command) {
m_event.Falling().IfHigh([command] {
if (command->IsScheduled()) {
command->Cancel();
} else {
command->Schedule();
}
});
return *this;
}
Trigger Trigger::ToggleOnFalse(CommandPtr&& command) {
m_event.Falling().IfHigh([command = std::move(command)] {
if (command.IsScheduled()) {
command.Cancel();
} else {
command.Schedule();
}
});
return *this;
}
WPI_IGNORE_DEPRECATED
Trigger Trigger::WhenActive(Command* command) {
m_event.Rising().IfHigh([command] { command->Schedule(); });
return *this;
}
@@ -35,15 +123,8 @@ Trigger Trigger::WhenActive(std::function<void()> toRun,
}
Trigger Trigger::WhileActiveContinous(Command* command) {
this->IfHigh([command] { command->Schedule(); });
this->Falling().IfHigh([command] { command->Cancel(); });
return *this;
}
Trigger Trigger::WhileActiveContinous(CommandPtr&& command) {
auto ptr = std::make_shared<CommandPtr>(std::move(command));
this->IfHigh([ptr] { ptr->Schedule(); });
this->Falling().IfHigh([ptr] { ptr->Cancel(); });
m_event.IfHigh([command] { command->Schedule(); });
m_event.Falling().IfHigh([command] { command->Cancel(); });
return *this;
}
@@ -60,26 +141,13 @@ Trigger Trigger::WhileActiveContinous(
}
Trigger Trigger::WhileActiveOnce(Command* command) {
this->Rising().IfHigh([command] { command->Schedule(); });
this->Falling().IfHigh([command] { command->Cancel(); });
return *this;
}
Trigger Trigger::WhileActiveOnce(CommandPtr&& command) {
auto ptr = std::make_shared<CommandPtr>(std::move(command));
this->Rising().IfHigh([ptr] { ptr->Schedule(); });
this->Falling().IfHigh([ptr] { ptr->Cancel(); });
m_event.Rising().IfHigh([command] { command->Schedule(); });
m_event.Falling().IfHigh([command] { command->Cancel(); });
return *this;
}
Trigger Trigger::WhenInactive(Command* command) {
this->Falling().IfHigh([command] { command->Schedule(); });
return *this;
}
Trigger Trigger::WhenInactive(CommandPtr&& command) {
this->Falling().IfHigh(
[command = std::move(command)] { command.Schedule(); });
m_event.Falling().IfHigh([command] { command->Schedule(); });
return *this;
}
@@ -95,7 +163,7 @@ Trigger Trigger::WhenInactive(std::function<void()> toRun,
}
Trigger Trigger::ToggleWhenActive(Command* command) {
this->Rising().IfHigh([command] {
m_event.Rising().IfHigh([command] {
if (command->IsScheduled()) {
command->Cancel();
} else {
@@ -105,18 +173,12 @@ Trigger Trigger::ToggleWhenActive(Command* command) {
return *this;
}
Trigger Trigger::ToggleWhenActive(CommandPtr&& command) {
this->Rising().IfHigh([command = std::move(command)] {
if (command.IsScheduled()) {
command.Cancel();
} else {
command.Schedule();
}
});
return *this;
}
Trigger Trigger::CancelWhenActive(Command* command) {
this->Rising().IfHigh([command] { command->Cancel(); });
m_event.Rising().IfHigh([command] { command->Cancel(); });
return *this;
}
WPI_UNIGNORE_DEPRECATED
BooleanEvent Trigger::GetEvent() const {
return m_event;
}

View File

@@ -9,6 +9,8 @@
#include <span>
#include <utility>
#include <wpi/deprecated.h>
#include "Trigger.h"
#include "frc2/command/CommandPtr.h"
@@ -28,13 +30,17 @@ class Button : public Trigger {
* Create a new button that is pressed when the given condition is true.
*
* @param isPressed Whether the button is pressed.
* @deprecated Replace with Trigger
*/
WPI_DEPRECATED("Replace with Trigger")
explicit Button(std::function<bool()> isPressed);
/**
* Create a new button that is pressed active (default constructor) - activity
* can be further determined by subclass code.
* @deprecated Replace with Trigger
*/
WPI_DEPRECATED("Replace with Trigger")
Button() = default;
/**
@@ -44,19 +50,11 @@ class Button : public Trigger {
*
* @param command The command to bind.
* @return The trigger, for chained calls.
* @deprecated Replace with Trigger::OnTrue()
*/
WPI_DEPRECATED("Replace with Trigger#OnTrue()")
Button WhenPressed(Command* command);
/**
* Binds a command to start when the button is pressed. Transfers
* command ownership to the button scheduler, so the user does not have to
* worry about lifespan.
*
* @param command The command to bind.
* @return The trigger, for chained calls.
*/
Button WhenPressed(CommandPtr&& command);
/**
* Binds a command to start when the button is pressed. Transfers
* command ownership to the button scheduler, so the user does not have to
@@ -65,9 +63,11 @@ class Button : public Trigger {
*
* @param command The command to bind.
* @return The trigger, for chained calls.
* @deprecated Replace with Trigger::OnTrue()
*/
template <class T, typename = std::enable_if_t<std::is_base_of_v<
Command, std::remove_reference_t<T>>>>
WPI_DEPRECATED("Replace with Trigger#OnTrue()")
Button WhenPressed(T&& command) {
WhenActive(std::forward<T>(command));
return *this;
@@ -78,7 +78,9 @@ class Button : public Trigger {
*
* @param toRun the runnable to execute.
* @param requirements the required subsystems.
* @deprecated Replace with Trigger::OnTrue(cmd::RunOnce())
*/
WPI_DEPRECATED("Replace with Trigger#OnTrue(cmd::RunOnce())")
Button WhenPressed(std::function<void()> toRun,
std::initializer_list<Subsystem*> requirements);
@@ -87,7 +89,9 @@ class Button : public Trigger {
*
* @param toRun the runnable to execute.
* @param requirements the required subsystems.
* @deprecated Replace with Trigger::OnTrue(cmd::RunOnce())
*/
WPI_DEPRECATED("Replace with Trigger#OnTrue(cmd::RunOnce())")
Button WhenPressed(std::function<void()> toRun,
std::span<Subsystem* const> requirements = {});
@@ -98,19 +102,11 @@ class Button : public Trigger {
*
* @param command The command to bind.
* @return The button, for chained calls.
* @deprecated Replace with Trigger::WhileTrue(command.Repeatedly())
*/
WPI_DEPRECATED("Replace with Trigger#WhileTrue(command.Repeatedly())")
Button WhileHeld(Command* command);
/**
* Binds a command to be started repeatedly while the button is pressed, and
* canceled when it is released. Transfers command ownership to the button
* scheduler, so the user does not have to worry about lifespan.
*
* @param command The command to bind.
* @return The button, for chained calls.
*/
Button WhileHeld(CommandPtr&& command);
/**
* Binds a command to be started repeatedly while the button is pressed, and
* canceled when it is released. Transfers command ownership to the button
@@ -119,9 +115,11 @@ class Button : public Trigger {
*
* @param command The command to bind.
* @return The button, for chained calls.
* @deprecated Replace with Trigger::WhileTrue(command.Repeatedly())
*/
template <class T, typename = std::enable_if_t<std::is_base_of_v<
Command, std::remove_reference_t<T>>>>
WPI_DEPRECATED("Replace with Trigger#WhileTrue(command.Repeatedly())")
Button WhileHeld(T&& command) {
WhileActiveContinous(std::forward<T>(command));
return *this;
@@ -132,7 +130,9 @@ class Button : public Trigger {
*
* @param toRun the runnable to execute.
* @param requirements the required subsystems.
* @deprecated Replace with Trigger::WhileTrue(cmd::Run())
*/
WPI_DEPRECATED("Replace with Trigger#WhileTrue(cmd::Run())")
Button WhileHeld(std::function<void()> toRun,
std::initializer_list<Subsystem*> requirements);
@@ -141,7 +141,9 @@ class Button : public Trigger {
*
* @param toRun the runnable to execute.
* @param requirements the required subsystems.
* @deprecated Replace with Trigger::WhileTrue(cmd::Run())
*/
WPI_DEPRECATED("Replace with Trigger#WhileTrue(cmd::Run())")
Button WhileHeld(std::function<void()> toRun,
std::span<Subsystem* const> requirements = {});
@@ -152,19 +154,11 @@ class Button : public Trigger {
*
* @param command The command to bind.
* @return The button, for chained calls.
* @deprecated Replace with Trigger::WhileTrue()
*/
WPI_DEPRECATED("Replace with Trigger#WhileTrue()")
Button WhenHeld(Command* command);
/**
* Binds a command to be started when the button is pressed, and canceled
* when it is released. Transfers command ownership to the button scheduler,
* so the user does not have to worry about lifespan.
*
* @param command The command to bind.
* @return The button, for chained calls.
*/
Button WhenHeld(CommandPtr&& command);
/**
* Binds a command to be started when the button is pressed, and canceled
* when it is released. Transfers command ownership to the button scheduler,
@@ -173,9 +167,11 @@ class Button : public Trigger {
*
* @param command The command to bind.
* @return The button, for chained calls.
* @deprecated Replace with Trigger::WhileTrue()
*/
template <class T, typename = std::enable_if_t<std::is_base_of_v<
Command, std::remove_reference_t<T>>>>
WPI_DEPRECATED("Replace with Trigger#WhileTrue()")
Button WhenHeld(T&& command) {
WhileActiveOnce(std::forward<T>(command));
return *this;
@@ -188,19 +184,11 @@ class Button : public Trigger {
*
* @param command The command to bind.
* @return The button, for chained calls.
* @deprecated Replace with Trigger::OnFalse()
*/
WPI_DEPRECATED("Replace with Trigger#OnFalse()")
Button WhenReleased(Command* command);
/**
* Binds a command to start when the button is pressed. Transfers
* command ownership to the button scheduler, so the user does not have to
* worry about lifespan.
*
* @param command The command to bind.
* @return The button, for chained calls.
*/
Button WhenReleased(CommandPtr&& command);
/**
* Binds a command to start when the button is pressed. Transfers
* command ownership to the button scheduler, so the user does not have to
@@ -209,9 +197,11 @@ class Button : public Trigger {
*
* @param command The command to bind.
* @return The button, for chained calls.
* @deprecated Replace with Trigger::OnFalse()
*/
template <class T, typename = std::enable_if_t<std::is_base_of_v<
Command, std::remove_reference_t<T>>>>
WPI_DEPRECATED("Replace with Trigger#OnFalse()")
Button WhenReleased(T&& command) {
WhenInactive(std::forward<T>(command));
return *this;
@@ -222,7 +212,9 @@ class Button : public Trigger {
*
* @param toRun the runnable to execute.
* @param requirements the required subsystems.
* @deprecated Replace with Trigger::OnFalse(cmd::RunOnce())
*/
WPI_DEPRECATED("Replace with Trigger#OnFalse(cmd::RunOnce())")
Button WhenReleased(std::function<void()> toRun,
std::initializer_list<Subsystem*> requirements);
@@ -231,7 +223,9 @@ class Button : public Trigger {
*
* @param toRun the runnable to execute.
* @param requirements the required subsystems.
* @deprecated Replace with Trigger::OnFalse(cmd::RunOnce())
*/
WPI_DEPRECATED("Replace with Trigger#OnFalse(cmd::RunOnce())")
Button WhenReleased(std::function<void()> toRun,
std::span<Subsystem* const> requirements = {});
@@ -242,19 +236,11 @@ class Button : public Trigger {
*
* @param command The command to bind.
* @return The button, for chained calls.
* @deprecated Replace with Trigger::ToggleOnTrue()
*/
WPI_DEPRECATED("Replace with Trigger#ToggleOnTrue()")
Button ToggleWhenPressed(Command* command);
/**
* Binds a command to start when the button is pressed, and be canceled when
* it is pessed again. Transfers command ownership to the button scheduler,
* so the user does not have to worry about lifespan.
*
* @param command The command to bind.
* @return The button, for chained calls.
*/
Button ToggleWhenPressed(CommandPtr&& command);
/**
* Binds a command to start when the button is pressed, and be canceled when
* it is pessed again. Transfers command ownership to the button scheduler,
@@ -263,9 +249,11 @@ class Button : public Trigger {
*
* @param command The command to bind.
* @return The button, for chained calls.
* @deprecated Replace with Trigger::ToggleOnTrue()
*/
template <class T, typename = std::enable_if_t<std::is_base_of_v<
Command, std::remove_reference_t<T>>>>
WPI_DEPRECATED("Replace with Trigger#ToggleOnTrue()")
Button ToggleWhenPressed(T&& command) {
ToggleWhenActive(std::forward<T>(command));
return *this;
@@ -278,7 +266,10 @@ class Button : public Trigger {
*
* @param command The command to bind.
* @return The button, for chained calls.
* @deprecated Use Rising() as a command end condition with Until() instead.
*/
WPI_DEPRECATED(
"Use Rising() as a command end condition with Until() instead.")
Button CancelWhenPressed(Command* command);
};
} // namespace frc2

View File

@@ -4,6 +4,7 @@
#pragma once
#include <frc/GenericHID.h>
#include <wpi/deprecated.h>
#include "Button.h"
@@ -24,9 +25,11 @@ class JoystickButton : public Button {
* @param joystick The joystick on which the button is located.
* @param buttonNumber The number of the button on the joystic.
*/
WPI_IGNORE_DEPRECATED
explicit JoystickButton(frc::GenericHID* joystick, int buttonNumber)
: Button([joystick, buttonNumber] {
return joystick->GetRawButton(buttonNumber);
}) {}
WPI_UNIGNORE_DEPRECATED
};
} // namespace frc2

View File

@@ -4,6 +4,7 @@
#pragma once
#include <frc/GenericHID.h>
#include <wpi/deprecated.h>
#include "Button.h"
@@ -25,9 +26,11 @@ class POVButton : public Button {
* @param angle The angle of the POV corresponding to a button press.
* @param povNumber The number of the POV on the joystick.
*/
WPI_IGNORE_DEPRECATED
POVButton(frc::GenericHID* joystick, int angle, int povNumber = 0)
: Button([joystick, angle, povNumber] {
return joystick->GetPOV(povNumber) == angle;
}) {}
WPI_UNIGNORE_DEPRECATED
};
} // namespace frc2

View File

@@ -14,6 +14,7 @@
#include <frc/event/EventLoop.h>
#include <frc/filter/Debouncer.h>
#include <units/time.h>
#include <wpi/deprecated.h>
#include "frc2/command/Command.h"
#include "frc2/command/CommandScheduler.h"
@@ -21,14 +22,14 @@
namespace frc2 {
class Command;
/**
* This class is a command-based wrapper around {@link BooleanEvent}, providing
* an easy way to link commands to inputs.
* This class is a command-based wrapper around {@link frc::BooleanEvent},
* providing an easy way to link commands to inputs.
*
* This class is provided by the NewCommands VendorDep
*
* @see Button
*/
class Trigger : public frc::BooleanEvent {
class Trigger {
public:
/**
* Creates a new trigger with the given condition determining whether it is
@@ -39,8 +40,8 @@ class Trigger : public frc::BooleanEvent {
* @param isActive returns whether or not the trigger should be active
*/
explicit Trigger(std::function<bool()> isActive)
: BooleanEvent{CommandScheduler::GetInstance().GetDefaultButtonLoop(),
std::move(isActive)} {}
: m_event{CommandScheduler::GetInstance().GetDefaultButtonLoop(),
std::move(isActive)} {}
/**
* Create a new trigger that is active when the given condition is true.
@@ -49,7 +50,7 @@ class Trigger : public frc::BooleanEvent {
* @param isActive Whether the trigger is active.
*/
Trigger(frc::EventLoop* loop, std::function<bool()> isActive)
: BooleanEvent{loop, std::move(isActive)} {}
: m_event{loop, std::move(isActive)} {}
/**
* Create a new trigger that is never active (default constructor) - activity
@@ -59,6 +60,143 @@ class Trigger : public frc::BooleanEvent {
Trigger(const Trigger& other);
/**
* Starts the given command whenever the signal rises from `false` to `true`.
*
* <p>Takes a raw pointer, and so is non-owning; users are responsible for the
* lifespan of the command.
*
* @param command the command to start
* @return this trigger, so calls can be chained
* @see #Rising()
*/
Trigger OnTrue(Command* command);
/**
* Starts the given command whenever the signal rises from `false` to `true`.
* Moves command ownership to the button scheduler.
*
* @param command The command to bind.
* @return The trigger, for chained calls.
*/
Trigger OnTrue(CommandPtr&& command);
/**
* Starts the given command whenever the signal falls from `true` to `false`.
*
* <p>Takes a raw pointer, and so is non-owning; users are responsible for the
* lifespan of the command.
*
* @param command the command to start
* @return this trigger, so calls can be chained
* @see #Falling()
*/
Trigger OnFalse(Command* command);
/**
* Starts the given command whenever the signal falls from `true` to `false`.
*
* @param command The command to bind.
* @return The trigger, for chained calls.
*/
Trigger OnFalse(CommandPtr&& command);
/**
* Starts the given command when the signal rises to `true` and cancels it
* when the signal falls to `false`.
*
* <p>Doesn't re-start the command in-between.
*
* <p>Takes a raw pointer, and so is non-owning; users are responsible for the
* lifespan of the command.
*
* @param command the command to start
* @return this trigger, so calls can be chained
*/
Trigger WhileTrue(Command* command);
/**
* Starts the given command when the signal rises to `true` and cancels it
* when the signal falls to `false`. Moves command ownership to the button
* scheduler.
*
* @param command The command to bind.
* @return The trigger, for chained calls.
*/
Trigger WhileTrue(CommandPtr&& command);
/**
* Starts the given command when the signal falls to `false` and cancels
* it when the signal rises.
*
* <p>Doesn't re-start the command in-between.
*
* <p>Takes a raw pointer, and so is non-owning; users are responsible for the
* lifespan of the command.
*
* @param command the command to start
* @return this trigger, so calls can be chained
*/
Trigger WhileFalse(Command* command);
/**
* Starts the given command when the signal falls to `false` and cancels
* it when the signal rises. Moves command ownership to the button
* scheduler.
*
* @param command The command to bind.
* @return The trigger, for chained calls.
*/
Trigger WhileFalse(CommandPtr&& command);
/**
* Toggles a command when the signal rises from `false` to the high
* state.
*
* <p>Takes a raw pointer, and so is non-owning; users are responsible for the
* lifespan of the command.
*
* @param command the command to toggle
* @return this trigger, so calls can be chained
*/
Trigger ToggleOnTrue(Command* command);
/**
* Toggles a command when the signal rises from `false` to the high
* state.
*
* <p>Takes a raw pointer, and so is non-owning; users are responsible for the
* lifespan of the command.
*
* @param command the command to toggle
* @return this trigger, so calls can be chained
*/
Trigger ToggleOnTrue(CommandPtr&& command);
/**
* Toggles a command when the signal falls from `true` to the low
* state.
*
* <p>Takes a raw pointer, and so is non-owning; users are responsible for the
* lifespan of the command.
*
* @param command the command to toggle
* @return this trigger, so calls can be chained
*/
Trigger ToggleOnFalse(Command* command);
/**
* Toggles a command when the signal falls from `true` to the low
* state.
*
* <p>Takes a raw pointer, and so is non-owning; users are responsible for the
* lifespan of the command.
*
* @param command the command to toggle
* @return this trigger, so calls can be chained
*/
Trigger ToggleOnFalse(CommandPtr&& command);
/**
* Binds a command to start when the trigger becomes active. Takes a
* raw pointer, and so is non-owning; users are responsible for the lifespan
@@ -66,18 +204,11 @@ class Trigger : public frc::BooleanEvent {
*
* @param command The command to bind.
* @return The trigger, for chained calls.
* @deprecated Use OnTrue(Command) instead
*/
WPI_DEPRECATED("Use OnTrue(Command) instead")
Trigger WhenActive(Command* command);
/**
* Binds a command to start when the trigger becomes active. Moves
* command ownership to the button scheduler.
*
* @param command The command to bind.
* @return The trigger, for chained calls.
*/
Trigger WhenActive(CommandPtr&& command);
/**
* Binds a command to start when the trigger becomes active. Transfers
* command ownership to the button scheduler, so the user does not have to
@@ -86,11 +217,13 @@ class Trigger : public frc::BooleanEvent {
*
* @param command The command to bind.
* @return The trigger, for chained calls.
* @deprecated Use OnTrue(Command) instead
*/
template <class T, typename = std::enable_if_t<std::is_base_of_v<
Command, std::remove_reference_t<T>>>>
WPI_DEPRECATED("Use OnTrue(Command) instead")
Trigger WhenActive(T&& command) {
this->Rising().IfHigh(
m_event.Rising().IfHigh(
[command = std::make_unique<std::remove_reference_t<T>>(
std::forward<T>(command))] { command->Schedule(); });
@@ -102,7 +235,11 @@ class Trigger : public frc::BooleanEvent {
*
* @param toRun the runnable to execute.
* @param requirements the required subsystems.
* @deprecated Use OnTrue(Command) instead and construct the InstantCommand
* manually
*/
WPI_DEPRECATED(
"Use OnTrue(Command) instead and construct the InstantCommand manually")
Trigger WhenActive(std::function<void()> toRun,
std::initializer_list<Subsystem*> requirements);
@@ -111,7 +248,11 @@ class Trigger : public frc::BooleanEvent {
*
* @param toRun the runnable to execute.
* @param requirements the required subsystems.
* @deprecated Use OnTrue(Command) instead and construct the InstantCommand
* manually
*/
WPI_DEPRECATED(
"Use OnTrue(Command) instead and construct the InstantCommand manually")
Trigger WhenActive(std::function<void()> toRun,
std::span<Subsystem* const> requirements = {});
@@ -122,19 +263,14 @@ class Trigger : public frc::BooleanEvent {
*
* @param command The command to bind.
* @return The trigger, for chained calls.
* @deprecated Use WhileTrue(Command) with RepeatCommand, or bind
command::Schedule with IfHigh(std::function<void()>).
*/
WPI_DEPRECATED(
"Use WhileTrue(Command) with RepeatCommand, or bind command::Schedule "
"with IfHigh(std::function<void()>).")
Trigger WhileActiveContinous(Command* command);
/**
* Binds a command to be started repeatedly while the trigger is active, and
* canceled when it becomes inactive. Moves command ownership to the button
* scheduler.
*
* @param command The command to bind.
* @return The trigger, for chained calls.
*/
Trigger WhileActiveContinous(CommandPtr&& command);
/**
* Binds a command to be started repeatedly while the trigger is active, and
* canceled when it becomes inactive. Transfers command ownership to the
@@ -143,14 +279,19 @@ class Trigger : public frc::BooleanEvent {
*
* @param command The command to bind.
* @return The trigger, for chained calls.
* @deprecated Use WhileTrue(Command) with RepeatCommand, or bind
command::Schedule with IfHigh(std::function<void()>).
*/
template <class T, typename = std::enable_if_t<std::is_base_of_v<
Command, std::remove_reference_t<T>>>>
WPI_DEPRECATED(
"Use WhileTrue(Command) with RepeatCommand, or bind command::Schedule "
"with IfHigh(std::function<void()>).")
Trigger WhileActiveContinous(T&& command) {
std::shared_ptr<T> ptr =
std::make_shared<std::remove_reference_t<T>>(std::forward<T>(command));
this->IfHigh([ptr] { ptr->Schedule(); });
this->Falling().IfHigh([ptr] { ptr->Cancel(); });
m_event.IfHigh([ptr] { ptr->Schedule(); });
m_event.Falling().IfHigh([ptr] { ptr->Cancel(); });
return *this;
}
@@ -160,7 +301,9 @@ class Trigger : public frc::BooleanEvent {
*
* @param toRun the runnable to execute.
* @param requirements the required subsystems.
* @deprecated Use WhileTrue(Command) and construct a RunCommand manually
*/
WPI_DEPRECATED("Use WhileTrue(Command) and construct a RunCommand manually")
Trigger WhileActiveContinous(std::function<void()> toRun,
std::initializer_list<Subsystem*> requirements);
@@ -169,7 +312,9 @@ class Trigger : public frc::BooleanEvent {
*
* @param toRun the runnable to execute.
* @param requirements the required subsystems.
* @deprecated Use WhileTrue(Command) and construct a RunCommand manually
*/
WPI_DEPRECATED("Use WhileTrue(Command) and construct a RunCommand manually")
Trigger WhileActiveContinous(std::function<void()> toRun,
std::span<Subsystem* const> requirements = {});
@@ -180,19 +325,11 @@ class Trigger : public frc::BooleanEvent {
*
* @param command The command to bind.
* @return The trigger, for chained calls.
* @deprecated Use WhileTrue(Command) instead.
*/
WPI_DEPRECATED("Use WhileTrue(Command) instead.")
Trigger WhileActiveOnce(Command* command);
/**
* Binds a command to be started when the trigger becomes active, and
* canceled when it becomes inactive. Moves command ownership to the button
* scheduler.
*
* @param command The command to bind.
* @return The trigger, for chained calls.
*/
Trigger WhileActiveOnce(CommandPtr&& command);
/**
* Binds a command to be started when the trigger becomes active, and
* canceled when it becomes inactive. Transfers command ownership to the
@@ -201,15 +338,17 @@ class Trigger : public frc::BooleanEvent {
*
* @param command The command to bind.
* @return The trigger, for chained calls.
* @deprecated Use WhileTrue(Command) instead.
*/
template <class T, typename = std::enable_if_t<std::is_base_of_v<
Command, std::remove_reference_t<T>>>>
WPI_DEPRECATED("Use WhileTrue(Command) instead.")
Trigger WhileActiveOnce(T&& command) {
std::shared_ptr<T> ptr =
std::make_shared<std::remove_reference_t<T>>(std::forward<T>(command));
this->Rising().IfHigh([ptr] { ptr->Schedule(); });
this->Falling().IfHigh([ptr] { ptr->Cancel(); });
m_event.Rising().IfHigh([ptr] { ptr->Schedule(); });
m_event.Falling().IfHigh([ptr] { ptr->Cancel(); });
return *this;
}
@@ -221,18 +360,11 @@ class Trigger : public frc::BooleanEvent {
*
* @param command The command to bind.
* @return The trigger, for chained calls.
* @deprecated Use OnFalse(Command) instead.
*/
WPI_DEPRECATED("Use OnFalse(Command) instead.")
Trigger WhenInactive(Command* command);
/**
* Binds a command to start when the trigger becomes inactive. Moves
* command ownership to the button scheduler.
*
* @param command The command to bind.
* @return The trigger, for chained calls.
*/
Trigger WhenInactive(CommandPtr&& command);
/**
* Binds a command to start when the trigger becomes inactive. Transfers
* command ownership to the button scheduler, so the user does not have to
@@ -241,11 +373,13 @@ class Trigger : public frc::BooleanEvent {
*
* @param command The command to bind.
* @return The trigger, for chained calls.
* @deprecated Use OnFalse(Command) instead.
*/
template <class T, typename = std::enable_if_t<std::is_base_of_v<
Command, std::remove_reference_t<T>>>>
WPI_DEPRECATED("Use OnFalse(Command) instead.")
Trigger WhenInactive(T&& command) {
this->Falling().IfHigh(
m_event.Falling().IfHigh(
[command = std::make_unique<std::remove_reference_t<T>>(
std::forward<T>(command))] { command->Schedule(); });
@@ -257,7 +391,11 @@ class Trigger : public frc::BooleanEvent {
*
* @param toRun the runnable to execute.
* @param requirements the required subsystems.
* @deprecated Use OnFalse(Command) instead and construct the InstantCommand
* manually
*/
WPI_DEPRECATED(
"Use OnFalse(Command) instead and construct the InstantCommand manually")
Trigger WhenInactive(std::function<void()> toRun,
std::initializer_list<Subsystem*> requirements);
@@ -266,7 +404,11 @@ class Trigger : public frc::BooleanEvent {
*
* @param toRun the runnable to execute.
* @param requirements the required subsystems.
* @deprecated Use OnFalse(Command) instead and construct the InstantCommand
* manually
*/
WPI_DEPRECATED(
"Use OnFalse(Command) instead and construct the InstantCommand manually")
Trigger WhenInactive(std::function<void()> toRun,
std::span<Subsystem* const> requirements = {});
@@ -277,19 +419,11 @@ class Trigger : public frc::BooleanEvent {
*
* @param command The command to bind.
* @return The trigger, for chained calls.
* @deprecated Use ToggleOnTrue(Command) instead.
*/
WPI_DEPRECATED("Use ToggleOnTrue(Command) instead.")
Trigger ToggleWhenActive(Command* command);
/**
* Binds a command to start when the trigger becomes active, and be canceled
* when it again becomes active. Moves command ownership to the button
* scheduler.
*
* @param command The command to bind.
* @return The trigger, for chained calls.
*/
Trigger ToggleWhenActive(CommandPtr&& command);
/**
* Binds a command to start when the trigger becomes active, and be canceled
* when it again becomes active. Transfers command ownership to the button
@@ -298,11 +432,13 @@ class Trigger : public frc::BooleanEvent {
*
* @param command The command to bind.
* @return The trigger, for chained calls.
* @deprecated Use ToggleOnTrue(Command) instead.
*/
template <class T, typename = std::enable_if_t<std::is_base_of_v<
Command, std::remove_reference_t<T>>>>
WPI_DEPRECATED("Use ToggleOnTrue(Command) instead.")
Trigger ToggleWhenActive(T&& command) {
this->Rising().IfHigh(
m_event.Rising().IfHigh(
[command = std::make_unique<std::remove_reference_t<T>>(
std::forward<T>(command))] {
if (!command->IsScheduled()) {
@@ -322,7 +458,10 @@ class Trigger : public frc::BooleanEvent {
*
* @param command The command to bind.
* @return The trigger, for chained calls.
* @deprecated Use Rising() as a command end condition with Until() instead.
*/
WPI_DEPRECATED(
"Use Rising() as a command end condition with Until() instead.")
Trigger CancelWhenActive(Command* command);
/**
@@ -330,14 +469,14 @@ class Trigger : public frc::BooleanEvent {
*
* @return a new event representing when this one newly changes to true.
*/
Trigger Rising() { return BooleanEvent::Rising().CastTo<Trigger>(); }
Trigger Rising() { return m_event.Rising().CastTo<Trigger>(); }
/**
* Get a new event that triggers only when this one newly changes to false.
*
* @return a new event representing when this one newly changes to false.
*/
Trigger Falling() { return BooleanEvent::Falling().CastTo<Trigger>(); }
Trigger Falling() { return m_event.Falling().CastTo<Trigger>(); }
/**
* Composes two triggers with logical AND.
@@ -345,7 +484,7 @@ class Trigger : public frc::BooleanEvent {
* @return A trigger which is active when both component triggers are active.
*/
Trigger operator&&(std::function<bool()> rhs) {
return BooleanEvent::operator&&(rhs).CastTo<Trigger>();
return m_event.operator&&(rhs).CastTo<Trigger>();
}
/**
@@ -354,7 +493,7 @@ class Trigger : public frc::BooleanEvent {
* @return A trigger which is active when either component trigger is active.
*/
Trigger operator||(std::function<bool()> rhs) {
return BooleanEvent::operator||(rhs).CastTo<Trigger>();
return m_event.operator||(rhs).CastTo<Trigger>();
}
/**
@@ -363,7 +502,7 @@ class Trigger : public frc::BooleanEvent {
* @return A trigger which is active when the component trigger is inactive,
* and vice-versa.
*/
Trigger operator!() { return BooleanEvent::operator!().CastTo<Trigger>(); }
Trigger operator!() { return m_event.operator!().CastTo<Trigger>(); }
/**
* Creates a new debounced trigger from this trigger - it will become active
@@ -376,7 +515,15 @@ class Trigger : public frc::BooleanEvent {
Trigger Debounce(units::second_t debounceTime,
frc::Debouncer::DebounceType type =
frc::Debouncer::DebounceType::kRising) {
return BooleanEvent::Debounce(debounceTime, type).CastTo<Trigger>();
return m_event.Debounce(debounceTime, type).CastTo<Trigger>();
}
/**
* Get the wrapped BooleanEvent instance.
*/
frc::BooleanEvent GetEvent() const;
private:
frc::BooleanEvent m_event;
};
} // namespace frc2

View File

@@ -1,220 +0,0 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj2.command.button;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import edu.wpi.first.wpilibj.simulation.SimHooks;
import edu.wpi.first.wpilibj2.command.Command;
import edu.wpi.first.wpilibj2.command.CommandScheduler;
import edu.wpi.first.wpilibj2.command.CommandTestBase;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BooleanSupplier;
import org.junit.jupiter.api.Test;
class ButtonTest extends CommandTestBase {
@Test
void whenPressedTest() {
CommandScheduler scheduler = CommandScheduler.getInstance();
MockCommandHolder command1Holder = new MockCommandHolder(true);
Command command1 = command1Holder.getMock();
InternalButton button = new InternalButton();
button.setPressed(false);
button.whenPressed(command1);
scheduler.run();
verify(command1, never()).schedule();
button.setPressed(true);
scheduler.run();
scheduler.run();
verify(command1).schedule();
}
@Test
void whenReleasedTest() {
CommandScheduler scheduler = CommandScheduler.getInstance();
MockCommandHolder command1Holder = new MockCommandHolder(true);
Command command1 = command1Holder.getMock();
InternalButton button = new InternalButton();
button.setPressed(true);
button.whenReleased(command1);
scheduler.run();
verify(command1, never()).schedule();
button.setPressed(false);
scheduler.run();
scheduler.run();
verify(command1).schedule();
}
@Test
void whileHeldTest() {
CommandScheduler scheduler = CommandScheduler.getInstance();
MockCommandHolder command1Holder = new MockCommandHolder(true);
Command command1 = command1Holder.getMock();
InternalButton button = new InternalButton();
button.setPressed(false);
button.whileHeld(command1);
scheduler.run();
verify(command1, never()).schedule();
button.setPressed(true);
scheduler.run();
scheduler.run();
verify(command1, times(2)).schedule();
button.setPressed(false);
scheduler.run();
verify(command1).cancel();
}
@Test
void whenHeldTest() {
CommandScheduler scheduler = CommandScheduler.getInstance();
MockCommandHolder command1Holder = new MockCommandHolder(true);
Command command1 = command1Holder.getMock();
InternalButton button = new InternalButton();
button.setPressed(false);
button.whenHeld(command1);
scheduler.run();
verify(command1, never()).schedule();
button.setPressed(true);
scheduler.run();
scheduler.run();
verify(command1).schedule();
button.setPressed(false);
scheduler.run();
verify(command1).cancel();
}
@Test
void toggleWhenPressedTest() {
CommandScheduler scheduler = CommandScheduler.getInstance();
MockCommandHolder command1Holder = new MockCommandHolder(true);
Command command1 = command1Holder.getMock();
InternalButton button = new InternalButton();
button.setPressed(false);
button.toggleWhenPressed(command1);
scheduler.run();
verify(command1, never()).schedule();
button.setPressed(true);
scheduler.run();
when(command1.isScheduled()).thenReturn(true);
scheduler.run();
verify(command1).schedule();
button.setPressed(false);
scheduler.run();
verify(command1, never()).cancel();
button.setPressed(true);
scheduler.run();
verify(command1).cancel();
}
@Test
void cancelWhenPressedTest() {
CommandScheduler scheduler = CommandScheduler.getInstance();
MockCommandHolder command1Holder = new MockCommandHolder(true);
Command command1 = command1Holder.getMock();
InternalButton button = new InternalButton();
button.setPressed(false);
button.cancelWhenPressed(command1);
scheduler.run();
verify(command1, never()).cancel();
button.setPressed(true);
scheduler.run();
scheduler.run();
verify(command1).cancel();
}
@Test
void runnableBindingTest() {
InternalButton buttonWhenPressed = new InternalButton();
InternalButton buttonWhileHeld = new InternalButton();
InternalButton buttonWhenReleased = new InternalButton();
buttonWhenPressed.setPressed(false);
buttonWhileHeld.setPressed(true);
buttonWhenReleased.setPressed(true);
AtomicInteger counter = new AtomicInteger(0);
buttonWhenPressed.whenPressed(counter::incrementAndGet);
buttonWhileHeld.whileHeld(counter::incrementAndGet);
buttonWhenReleased.whenReleased(counter::incrementAndGet);
CommandScheduler scheduler = CommandScheduler.getInstance();
scheduler.run();
buttonWhenPressed.setPressed(true);
buttonWhenReleased.setPressed(false);
scheduler.run();
assertEquals(counter.get(), 4);
}
@Test
void buttonCompositionTest() {
InternalButton button1 = new InternalButton();
InternalButton button2 = new InternalButton();
button1.setPressed(true);
button2.setPressed(false);
assertFalse(button1.and(button2).getAsBoolean());
assertTrue(button1.or(button2).getAsBoolean());
assertFalse(button1.negate().getAsBoolean());
assertTrue(button1.and(button2.negate()).getAsBoolean());
}
@Test
void buttonCompositionSupplierTest() {
InternalButton button1 = new InternalButton();
BooleanSupplier booleanSupplier = () -> false;
button1.setPressed(true);
assertFalse(button1.and(booleanSupplier).getAsBoolean());
assertTrue(button1.or(booleanSupplier).getAsBoolean());
}
@Test
void debounceTest() {
CommandScheduler scheduler = CommandScheduler.getInstance();
MockCommandHolder commandHolder = new MockCommandHolder(true);
Command command = commandHolder.getMock();
InternalButton button = new InternalButton();
Trigger debounced = button.debounce(0.1);
debounced.whenActive(command);
button.setPressed(true);
scheduler.run();
verify(command, never()).schedule();
SimHooks.stepTiming(0.3);
button.setPressed(true);
scheduler.run();
verify(command).schedule();
}
@Test
void booleanSupplierTest() {
InternalButton button = new InternalButton();
assertFalse(button.getAsBoolean());
button.setPressed(true);
assertTrue(button.getAsBoolean());
}
}

View File

@@ -37,7 +37,7 @@ class NetworkButtonTest extends CommandTestBase {
var button = new NetworkButton(m_inst, "TestTable", "Test");
pub.set(false);
button.whenPressed(command);
button.onTrue(command);
scheduler.run();
verify(command, never()).schedule();
pub.set(true);

View File

@@ -0,0 +1,278 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package edu.wpi.first.wpilibj2.command.button;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import edu.wpi.first.wpilibj.simulation.SimHooks;
import edu.wpi.first.wpilibj2.command.Command;
import edu.wpi.first.wpilibj2.command.CommandScheduler;
import edu.wpi.first.wpilibj2.command.CommandTestBase;
import edu.wpi.first.wpilibj2.command.FunctionalCommand;
import edu.wpi.first.wpilibj2.command.RunCommand;
import edu.wpi.first.wpilibj2.command.StartEndCommand;
import edu.wpi.first.wpilibj2.command.WaitUntilCommand;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BooleanSupplier;
import org.junit.jupiter.api.Test;
class TriggerTest extends CommandTestBase {
@Test
void onTrueTest() {
CommandScheduler scheduler = CommandScheduler.getInstance();
AtomicBoolean finished = new AtomicBoolean(false);
Command command1 = new WaitUntilCommand(finished::get);
InternalButton button = new InternalButton();
button.setPressed(false);
button.onTrue(command1);
scheduler.run();
assertFalse(command1.isScheduled());
button.setPressed(true);
scheduler.run();
assertTrue(command1.isScheduled());
finished.set(true);
scheduler.run();
assertFalse(command1.isScheduled());
}
@Test
void onFalseTest() {
CommandScheduler scheduler = CommandScheduler.getInstance();
AtomicBoolean finished = new AtomicBoolean(false);
Command command1 = new WaitUntilCommand(finished::get);
InternalButton button = new InternalButton();
button.setPressed(true);
button.onFalse(command1);
scheduler.run();
assertFalse(command1.isScheduled());
button.setPressed(false);
scheduler.run();
assertTrue(command1.isScheduled());
finished.set(true);
scheduler.run();
assertFalse(command1.isScheduled());
}
@Test
void whileTrueRepeatedlyTest() {
CommandScheduler scheduler = CommandScheduler.getInstance();
AtomicInteger inits = new AtomicInteger(0);
AtomicInteger counter = new AtomicInteger(0);
// the repeatedly() here is the point!
Command command1 =
new FunctionalCommand(
inits::incrementAndGet,
() -> {},
interrupted -> {},
() -> counter.incrementAndGet() % 2 == 0)
.repeatedly();
InternalButton button = new InternalButton();
button.setPressed(false);
button.whileTrue(command1);
scheduler.run();
assertEquals(0, inits.get());
button.setPressed(true);
scheduler.run();
assertEquals(1, inits.get());
scheduler.run();
assertEquals(2, inits.get());
button.setPressed(false);
scheduler.run();
assertEquals(2, inits.get());
}
@Test
void whileTrueLambdaRunTest() {
CommandScheduler scheduler = CommandScheduler.getInstance();
AtomicInteger counter = new AtomicInteger(0);
// the repeatedly() here is the point!
Command command1 = new RunCommand(counter::incrementAndGet);
InternalButton button = new InternalButton();
button.setPressed(false);
button.whileTrue(command1);
scheduler.run();
assertEquals(0, counter.get());
button.setPressed(true);
scheduler.run();
assertEquals(1, counter.get());
scheduler.run();
assertEquals(2, counter.get());
button.setPressed(false);
scheduler.run();
assertEquals(2, counter.get());
}
@Test
void whileTrueOnceTest() {
CommandScheduler scheduler = CommandScheduler.getInstance();
AtomicInteger startCounter = new AtomicInteger(0);
AtomicInteger endCounter = new AtomicInteger(0);
Command command1 =
new StartEndCommand(startCounter::incrementAndGet, endCounter::incrementAndGet);
InternalButton button = new InternalButton();
button.setPressed(false);
button.whileTrue(command1);
scheduler.run();
assertEquals(0, startCounter.get());
assertEquals(0, endCounter.get());
button.setPressed(true);
scheduler.run();
scheduler.run();
assertEquals(1, startCounter.get());
assertEquals(0, endCounter.get());
button.setPressed(false);
scheduler.run();
assertEquals(1, startCounter.get());
assertEquals(1, endCounter.get());
}
@Test
void toggleOnTrueTest() {
CommandScheduler scheduler = CommandScheduler.getInstance();
AtomicInteger startCounter = new AtomicInteger(0);
AtomicInteger endCounter = new AtomicInteger(0);
Command command1 =
new StartEndCommand(startCounter::incrementAndGet, endCounter::incrementAndGet);
InternalButton button = new InternalButton();
button.setPressed(false);
button.toggleOnTrue(command1);
scheduler.run();
assertEquals(0, startCounter.get());
assertEquals(0, endCounter.get());
button.setPressed(true);
scheduler.run();
scheduler.run();
assertEquals(1, startCounter.get());
assertEquals(0, endCounter.get());
button.setPressed(false);
scheduler.run();
assertEquals(1, startCounter.get());
assertEquals(0, endCounter.get());
button.setPressed(true);
scheduler.run();
assertEquals(1, startCounter.get());
assertEquals(1, endCounter.get());
}
@Test
void cancelWhenActiveTest() {
CommandScheduler scheduler = CommandScheduler.getInstance();
AtomicInteger startCounter = new AtomicInteger(0);
AtomicInteger endCounter = new AtomicInteger(0);
InternalButton button = new InternalButton();
Command command1 =
new StartEndCommand(startCounter::incrementAndGet, endCounter::incrementAndGet)
.until(button.rising());
button.setPressed(false);
command1.schedule();
scheduler.run();
assertEquals(1, startCounter.get());
assertEquals(0, endCounter.get());
button.setPressed(true);
scheduler.run();
assertEquals(1, startCounter.get());
assertEquals(1, endCounter.get());
scheduler.run();
assertEquals(1, startCounter.get());
assertEquals(1, endCounter.get());
}
// Binding runnables directly is deprecated -- users should create the command manually
@SuppressWarnings("deprecation")
@Test
void runnableBindingTest() {
InternalButton buttonWhenActive = new InternalButton();
InternalButton buttonWhileActiveContinuous = new InternalButton();
InternalButton buttonWhenInactive = new InternalButton();
buttonWhenActive.setPressed(false);
buttonWhileActiveContinuous.setPressed(true);
buttonWhenInactive.setPressed(true);
AtomicInteger counter = new AtomicInteger(0);
buttonWhenActive.whenPressed(counter::incrementAndGet);
buttonWhileActiveContinuous.whileActiveContinuous(counter::incrementAndGet);
buttonWhenInactive.whenInactive(counter::incrementAndGet);
CommandScheduler scheduler = CommandScheduler.getInstance();
scheduler.run();
buttonWhenActive.setPressed(true);
buttonWhenInactive.setPressed(false);
scheduler.run();
assertEquals(counter.get(), 4);
}
@Test
void triggerCompositionTest() {
InternalButton button1 = new InternalButton();
InternalButton button2 = new InternalButton();
button1.setPressed(true);
button2.setPressed(false);
assertFalse(button1.and(button2).getAsBoolean());
assertTrue(button1.or(button2).getAsBoolean());
assertFalse(button1.negate().getAsBoolean());
assertTrue(button1.and(button2.negate()).getAsBoolean());
}
@Test
void triggerCompositionSupplierTest() {
InternalButton button1 = new InternalButton();
BooleanSupplier booleanSupplier = () -> false;
button1.setPressed(true);
assertFalse(button1.and(booleanSupplier).getAsBoolean());
assertTrue(button1.or(booleanSupplier).getAsBoolean());
}
@Test
void debounceTest() {
CommandScheduler scheduler = CommandScheduler.getInstance();
MockCommandHolder commandHolder = new MockCommandHolder(true);
Command command = commandHolder.getMock();
InternalButton button = new InternalButton();
Trigger debounced = button.debounce(0.1);
debounced.onTrue(command);
button.setPressed(true);
scheduler.run();
verify(command, never()).schedule();
SimHooks.stepTiming(0.3);
button.setPressed(true);
scheduler.run();
verify(command).schedule();
}
@Test
void booleanSupplierTest() {
InternalButton button = new InternalButton();
assertFalse(button.getAsBoolean());
button.setPressed(true);
assertTrue(button.getAsBoolean());
}
}

View File

@@ -26,7 +26,7 @@ TEST_F(POVButtonTest, SetPOV) {
WaitUntilCommand command([&finished] { return finished; });
frc::Joystick joy(1);
POVButton(&joy, 90).WhenPressed(&command);
POVButton(&joy, 90).OnTrue(&command);
scheduler.Run();
EXPECT_FALSE(scheduler.IsScheduled(&command));

View File

@@ -32,7 +32,7 @@ TEST_F(NetworkButtonTest, SetNetworkButton) {
WaitUntilCommand command([&finished] { return finished; });
NetworkButton(inst, "TestTable", "Test").WhenActive(&command);
NetworkButton(inst, "TestTable", "Test").OnTrue(&command);
scheduler.Run();
EXPECT_FALSE(scheduler.IsScheduled(&command));
pub.Set(true);

View File

@@ -5,23 +5,25 @@
#include <frc/simulation/SimHooks.h>
#include "../CommandTestBase.h"
#include "frc2/command/CommandPtr.h"
#include "frc2/command/CommandScheduler.h"
#include "frc2/command/Commands.h"
#include "frc2/command/RunCommand.h"
#include "frc2/command/WaitUntilCommand.h"
#include "frc2/command/button/Trigger.h"
#include "gtest/gtest.h"
using namespace frc2;
class ButtonTest : public CommandTestBase {};
class TriggerTest : public CommandTestBase {};
TEST_F(ButtonTest, WhenPressed) {
TEST_F(TriggerTest, OnTrue) {
auto& scheduler = CommandScheduler::GetInstance();
bool finished = false;
bool pressed = false;
WaitUntilCommand command([&finished] { return finished; });
Trigger([&pressed] { return pressed; }).WhenActive(&command);
Trigger([&pressed] { return pressed; }).OnTrue(&command);
scheduler.Run();
EXPECT_FALSE(scheduler.IsScheduled(&command));
pressed = true;
@@ -32,14 +34,14 @@ TEST_F(ButtonTest, WhenPressed) {
EXPECT_FALSE(scheduler.IsScheduled(&command));
}
TEST_F(ButtonTest, WhenReleased) {
TEST_F(TriggerTest, OnFalse) {
auto& scheduler = CommandScheduler::GetInstance();
bool finished = false;
bool pressed = false;
WaitUntilCommand command([&finished] { return finished; });
pressed = true;
Trigger([&pressed] { return pressed; }).WhenInactive(&command);
Trigger([&pressed] { return pressed; }).OnFalse(&command);
scheduler.Run();
EXPECT_FALSE(scheduler.IsScheduled(&command));
pressed = false;
@@ -50,87 +52,111 @@ TEST_F(ButtonTest, WhenReleased) {
EXPECT_FALSE(scheduler.IsScheduled(&command));
}
TEST_F(ButtonTest, WhileHeld) {
TEST_F(TriggerTest, WhileTrueRepeatedly) {
auto& scheduler = CommandScheduler::GetInstance();
bool finished = false;
int inits = 0;
int counter = 0;
bool pressed = false;
WaitUntilCommand command([&finished] { return finished; });
CommandPtr command =
FunctionalCommand([&inits] { inits++; }, [] {}, [](bool interrupted) {},
[&counter] { return ++counter % 2 == 0; })
.Repeatedly();
pressed = false;
Trigger([&pressed] { return pressed; }).WhileActiveContinous(&command);
Trigger([&pressed] { return pressed; }).WhileTrue(std::move(command));
scheduler.Run();
EXPECT_FALSE(scheduler.IsScheduled(&command));
EXPECT_EQ(0, inits);
pressed = true;
scheduler.Run();
EXPECT_TRUE(scheduler.IsScheduled(&command));
finished = true;
EXPECT_EQ(1, inits);
scheduler.Run();
finished = false;
scheduler.Run();
EXPECT_TRUE(scheduler.IsScheduled(&command));
EXPECT_EQ(2, inits);
pressed = false;
scheduler.Run();
EXPECT_FALSE(scheduler.IsScheduled(&command));
EXPECT_EQ(2, inits);
}
TEST_F(ButtonTest, WhenHeld) {
TEST_F(TriggerTest, WhileTrueLambdaRun) {
auto& scheduler = CommandScheduler::GetInstance();
bool finished = false;
int counter = 0;
bool pressed = false;
WaitUntilCommand command([&finished] { return finished; });
CommandPtr command = cmd::Run([&counter] { counter++; });
pressed = false;
Trigger([&pressed] { return pressed; }).WhileActiveOnce(&command);
Trigger([&pressed] { return pressed; }).WhileTrue(std::move(command));
scheduler.Run();
EXPECT_FALSE(scheduler.IsScheduled(&command));
EXPECT_EQ(0, counter);
pressed = true;
scheduler.Run();
EXPECT_TRUE(scheduler.IsScheduled(&command));
finished = true;
scheduler.Run();
finished = false;
scheduler.Run();
EXPECT_FALSE(scheduler.IsScheduled(&command));
pressed = false;
Trigger([&pressed] { return pressed; }).WhileActiveOnce(&command);
pressed = true;
scheduler.Run();
EXPECT_EQ(2, counter);
pressed = false;
scheduler.Run();
EXPECT_FALSE(scheduler.IsScheduled(&command));
EXPECT_EQ(2, counter);
}
TEST_F(ButtonTest, ToggleWhenPressed) {
TEST_F(TriggerTest, WhenTrueOnce) {
auto& scheduler = CommandScheduler::GetInstance();
bool finished = false;
int startCounter = 0;
int endCounter = 0;
bool pressed = false;
WaitUntilCommand command([&finished] { return finished; });
CommandPtr command = cmd::StartEnd([&startCounter] { startCounter++; },
[&endCounter] { endCounter++; });
pressed = false;
Trigger([&pressed] { return pressed; }).ToggleWhenActive(&command);
Trigger([&pressed] { return pressed; }).WhileTrue(std::move(command));
scheduler.Run();
EXPECT_FALSE(scheduler.IsScheduled(&command));
EXPECT_EQ(0, startCounter);
EXPECT_EQ(0, endCounter);
pressed = true;
scheduler.Run();
EXPECT_TRUE(scheduler.IsScheduled(&command));
scheduler.Run();
EXPECT_EQ(1, startCounter);
EXPECT_EQ(0, endCounter);
pressed = false;
scheduler.Run();
pressed = true;
scheduler.Run();
EXPECT_FALSE(scheduler.IsScheduled(&command));
EXPECT_EQ(1, startCounter);
EXPECT_EQ(1, endCounter);
}
TEST_F(ButtonTest, And) {
TEST_F(TriggerTest, ToggleOnTrue) {
auto& scheduler = CommandScheduler::GetInstance();
bool pressed = false;
int startCounter = 0;
int endCounter = 0;
CommandPtr command = cmd::StartEnd([&startCounter] { startCounter++; },
[&endCounter] { endCounter++; });
Trigger([&pressed] { return pressed; }).ToggleOnTrue(std::move(command));
scheduler.Run();
EXPECT_EQ(0, startCounter);
EXPECT_EQ(0, endCounter);
pressed = true;
scheduler.Run();
scheduler.Run();
EXPECT_EQ(1, startCounter);
EXPECT_EQ(0, endCounter);
pressed = false;
scheduler.Run();
EXPECT_EQ(1, startCounter);
EXPECT_EQ(0, endCounter);
pressed = true;
scheduler.Run();
EXPECT_EQ(1, startCounter);
EXPECT_EQ(1, endCounter);
}
TEST_F(TriggerTest, And) {
auto& scheduler = CommandScheduler::GetInstance();
bool finished = false;
bool pressed1 = false;
bool pressed2 = false;
WaitUntilCommand command([&finished] { return finished; });
(Trigger([&pressed1] { return pressed1; }) && Trigger([&pressed2] {
(Trigger([&pressed1] { return pressed1; }) && ([&pressed2] {
return pressed2;
})).WhenActive(&command);
})).OnTrue(&command);
pressed1 = true;
scheduler.Run();
EXPECT_FALSE(scheduler.IsScheduled(&command));
@@ -139,7 +165,7 @@ TEST_F(ButtonTest, And) {
EXPECT_TRUE(scheduler.IsScheduled(&command));
}
TEST_F(ButtonTest, Or) {
TEST_F(TriggerTest, Or) {
auto& scheduler = CommandScheduler::GetInstance();
bool finished = false;
bool pressed1 = false;
@@ -147,30 +173,30 @@ TEST_F(ButtonTest, Or) {
WaitUntilCommand command1([&finished] { return finished; });
WaitUntilCommand command2([&finished] { return finished; });
(Trigger([&pressed1] { return pressed1; }) || Trigger([&pressed2] {
(Trigger([&pressed1] { return pressed1; }) || ([&pressed2] {
return pressed2;
})).WhenActive(&command1);
})).OnTrue(&command1);
pressed1 = true;
scheduler.Run();
EXPECT_TRUE(scheduler.IsScheduled(&command1));
pressed1 = false;
(Trigger([&pressed1] { return pressed1; }) || Trigger([&pressed2] {
(Trigger([&pressed1] { return pressed1; }) || ([&pressed2] {
return pressed2;
})).WhenActive(&command2);
})).OnTrue(&command2);
pressed2 = true;
scheduler.Run();
EXPECT_TRUE(scheduler.IsScheduled(&command2));
}
TEST_F(ButtonTest, Negate) {
TEST_F(TriggerTest, Negate) {
auto& scheduler = CommandScheduler::GetInstance();
bool finished = false;
bool pressed = true;
WaitUntilCommand command([&finished] { return finished; });
(!Trigger([&pressed] { return pressed; })).WhenActive(&command);
(!Trigger([&pressed] { return pressed; })).OnTrue(&command);
scheduler.Run();
EXPECT_FALSE(scheduler.IsScheduled(&command));
pressed = false;
@@ -178,7 +204,9 @@ TEST_F(ButtonTest, Negate) {
EXPECT_TRUE(scheduler.IsScheduled(&command));
}
TEST_F(ButtonTest, RValueButton) {
// this type of binding is deprecated and identical to OnTrue
WPI_IGNORE_DEPRECATED
TEST_F(TriggerTest, RValueTrigger) {
auto& scheduler = CommandScheduler::GetInstance();
int counter = 0;
bool pressed = false;
@@ -192,13 +220,14 @@ TEST_F(ButtonTest, RValueButton) {
scheduler.Run();
EXPECT_EQ(counter, 1);
}
WPI_UNIGNORE_DEPRECATED
TEST_F(ButtonTest, Debounce) {
TEST_F(TriggerTest, Debounce) {
auto& scheduler = CommandScheduler::GetInstance();
bool pressed = false;
RunCommand command([] {});
Trigger([&pressed] { return pressed; }).Debounce(100_ms).WhenActive(&command);
Trigger([&pressed] { return pressed; }).Debounce(100_ms).OnTrue(&command);
pressed = true;
scheduler.Run();
EXPECT_FALSE(scheduler.IsScheduled(&command));

View File

@@ -64,8 +64,7 @@ class BooleanEvent {
* second.
* @return an instance of the subclass.
*/
template <class T,
typename = std::enable_if_t<std::is_base_of_v<BooleanEvent, T>>>
template <class T>
T CastTo(std::function<T(EventLoop*, std::function<bool()>)> ctor =
[](EventLoop* loop, std::function<bool()> condition) {
return T(loop, condition);

View File

@@ -5,6 +5,9 @@
#include "RobotContainer.h"
#include <frc/shuffleboard/Shuffleboard.h>
#include <frc2/command/Commands.h>
#include <frc2/command/InstantCommand.h>
#include <frc2/command/RunCommand.h>
#include <frc2/command/button/JoystickButton.h>
#include <units/angle.h>
@@ -28,31 +31,31 @@ void RobotContainer::ConfigureButtonBindings() {
// Move the arm to 2 radians above horizontal when the 'A' button is pressed.
frc2::JoystickButton(&m_driverController, frc::XboxController::Button::kA)
.WhenPressed(
.OnTrue(frc2::cmd::RunOnce(
[this] {
m_arm.SetGoal(2_rad);
m_arm.Enable();
},
{&m_arm});
{&m_arm}));
// Move the arm to neutral position when the 'B' button is pressed.
frc2::JoystickButton(&m_driverController, frc::XboxController::Button::kB)
.WhenPressed(
.OnTrue(frc2::cmd::RunOnce(
[this] {
m_arm.SetGoal(ArmConstants::kArmOffset);
m_arm.Enable();
},
{&m_arm});
{&m_arm}));
// Disable the arm controller when Y is pressed.
frc2::JoystickButton(&m_driverController, frc::XboxController::Button::kY)
.WhenPressed([this] { m_arm.Disable(); }, {&m_arm});
.OnTrue(frc2::cmd::RunOnce([this] { m_arm.Disable(); }, {&m_arm}));
// While holding the shoulder button, drive at half speed
frc2::JoystickButton(&m_driverController,
frc::XboxController::Button::kRightBumper)
.WhenPressed([this] { m_drive.SetMaxOutput(0.5); })
.WhenReleased([this] { m_drive.SetMaxOutput(1); });
.OnTrue(frc2::cmd::RunOnce([this] { m_drive.SetMaxOutput(0.5); }))
.OnFalse(frc2::cmd::RunOnce([this] { m_drive.SetMaxOutput(1); }));
}
void RobotContainer::DisablePIDSubsystems() {

View File

@@ -7,13 +7,6 @@
#include <frc/XboxController.h>
#include <frc/smartdashboard/SendableChooser.h>
#include <frc2/command/Command.h>
#include <frc2/command/ConditionalCommand.h>
#include <frc2/command/InstantCommand.h>
#include <frc2/command/ParallelRaceGroup.h>
#include <frc2/command/RunCommand.h>
#include <frc2/command/SequentialCommandGroup.h>
#include <frc2/command/WaitCommand.h>
#include <frc2/command/WaitUntilCommand.h>
#include "Constants.h"
#include "subsystems/ArmSubsystem.h"

View File

@@ -5,6 +5,9 @@
#include "RobotContainer.h"
#include <frc/shuffleboard/Shuffleboard.h>
#include <frc2/command/Commands.h>
#include <frc2/command/InstantCommand.h>
#include <frc2/command/RunCommand.h>
#include <frc2/command/button/JoystickButton.h>
#include <units/angle.h>
@@ -28,18 +31,18 @@ void RobotContainer::ConfigureButtonBindings() {
// Move the arm to 2 radians above horizontal when the 'A' button is pressed.
frc2::JoystickButton(&m_driverController, frc::XboxController::Button::kA)
.WhenPressed([this] { m_arm.SetGoal(2_rad); }, {&m_arm});
.OnTrue(frc2::cmd::RunOnce([this] { m_arm.SetGoal(2_rad); }, {&m_arm}));
// Move the arm to neutral position when the 'B' button is pressed.
frc2::JoystickButton(&m_driverController, frc::XboxController::Button::kB)
.WhenPressed([this] { m_arm.SetGoal(ArmConstants::kArmOffset); },
{&m_arm});
.OnTrue(frc2::cmd::RunOnce(
[this] { m_arm.SetGoal(ArmConstants::kArmOffset); }, {&m_arm}));
// While holding the shoulder button, drive at half speed
frc2::JoystickButton(&m_driverController,
frc::XboxController::Button::kRightBumper)
.WhenPressed([this] { m_drive.SetMaxOutput(0.5); })
.WhenReleased([this] { m_drive.SetMaxOutput(1); });
.OnTrue(frc2::cmd::RunOnce([this] { m_drive.SetMaxOutput(0.5); }))
.OnFalse(frc2::cmd::RunOnce([this] { m_drive.SetMaxOutput(1); }));
}
frc2::Command* RobotContainer::GetAutonomousCommand() {

View File

@@ -7,13 +7,6 @@
#include <frc/XboxController.h>
#include <frc/smartdashboard/SendableChooser.h>
#include <frc2/command/Command.h>
#include <frc2/command/ConditionalCommand.h>
#include <frc2/command/InstantCommand.h>
#include <frc2/command/ParallelRaceGroup.h>
#include <frc2/command/RunCommand.h>
#include <frc2/command/SequentialCommandGroup.h>
#include <frc2/command/WaitCommand.h>
#include <frc2/command/WaitUntilCommand.h>
#include "Constants.h"
#include "subsystems/ArmSubsystem.h"

View File

@@ -5,6 +5,7 @@
#include "RobotContainer.h"
#include <frc/shuffleboard/Shuffleboard.h>
#include <frc2/command/Commands.h>
#include <frc2/command/button/JoystickButton.h>
#include "commands/DriveDistanceProfiled.h"
@@ -16,7 +17,7 @@ RobotContainer::RobotContainer() {
ConfigureButtonBindings();
// Set up default drive command
m_drive.SetDefaultCommand(frc2::RunCommand(
m_drive.SetDefaultCommand(frc2::cmd::Run(
[this] {
m_drive.ArcadeDrive(-m_driverController.GetLeftY(),
m_driverController.GetRightX());
@@ -30,18 +31,18 @@ void RobotContainer::ConfigureButtonBindings() {
// While holding the shoulder button, drive at half speed
frc2::JoystickButton(&m_driverController,
frc::XboxController::Button::kRightBumper)
.WhenPressed(&m_driveHalfSpeed)
.WhenReleased(&m_driveFullSpeed);
.OnTrue(&m_driveHalfSpeed)
.OnFalse(&m_driveFullSpeed);
// Drive forward by 3 meters when the 'A' button is pressed, with a timeout of
// 10 seconds
frc2::JoystickButton(&m_driverController, frc::XboxController::Button::kA)
.WhenPressed(DriveDistanceProfiled(3_m, &m_drive).WithTimeout(10_s));
.OnTrue(DriveDistanceProfiled(3_m, &m_drive).WithTimeout(10_s));
// Do the same thing as above when the 'B' button is pressed, but defined
// inline
frc2::JoystickButton(&m_driverController, frc::XboxController::Button::kB)
.WhenPressed(
.OnTrue(
frc2::TrapezoidProfileCommand<units::meters>(
frc::TrapezoidProfile<units::meters>(
// Limit the max acceleration and velocity
@@ -54,7 +55,9 @@ void RobotContainer::ConfigureButtonBindings() {
},
// Require the drive
{&m_drive})
.BeforeStarting([this]() { m_drive.ResetEncoders(); })
.ToPtr()
.BeforeStarting(
frc2::cmd::RunOnce([this]() { m_drive.ResetEncoders(); }, {}))
.WithTimeout(10_s));
}

View File

@@ -27,22 +27,22 @@ void RobotContainer::ConfigureButtonBindings() {
// Spin up the shooter when the 'A' button is pressed
frc2::JoystickButton(&m_driverController, frc::XboxController::Button::kA)
.WhenPressed(&m_spinUpShooter);
.OnTrue(&m_spinUpShooter);
// Turn off the shooter when the 'B' button is pressed
frc2::JoystickButton(&m_driverController, frc::XboxController::Button::kB)
.WhenPressed(&m_stopShooter);
.OnTrue(&m_stopShooter);
// Shoot when the 'X' button is held
frc2::JoystickButton(&m_driverController, frc::XboxController::Button::kX)
.WhenPressed(&m_shoot)
.WhenReleased(&m_stopFeeder);
.OnTrue(&m_shoot)
.OnFalse(&m_stopFeeder);
// While holding the shoulder button, drive at half speed
frc2::JoystickButton(&m_driverController,
frc::XboxController::Button::kRightBumper)
.WhenPressed(&m_driveHalfSpeed)
.WhenReleased(&m_driveFullSpeed);
.OnTrue(&m_driveHalfSpeed)
.OnFalse(&m_driveFullSpeed);
}
frc2::Command* RobotContainer::GetAutonomousCommand() {

View File

@@ -32,20 +32,20 @@ RobotContainer::RobotContainer()
void RobotContainer::ConfigureButtonBindings() {
// Configure your button bindings here
frc2::JoystickButton(&m_joy, 5).WhenPressed(
SetElevatorSetpoint(0.25, m_elevator));
frc2::JoystickButton(&m_joy, 6).WhenPressed(CloseClaw(m_claw));
frc2::JoystickButton(&m_joy, 7).WhenPressed(
SetElevatorSetpoint(0.0, m_elevator));
frc2::JoystickButton(&m_joy, 8).WhenPressed(OpenClaw(m_claw));
frc2::JoystickButton(&m_joy, 9).WhenPressed(
Autonomous(m_claw, m_wrist, m_elevator, m_drivetrain));
frc2::JoystickButton(&m_joy, 5).OnTrue(
SetElevatorSetpoint(0.25, m_elevator).ToPtr());
frc2::JoystickButton(&m_joy, 6).OnTrue(CloseClaw(m_claw).ToPtr());
frc2::JoystickButton(&m_joy, 7).OnTrue(
SetElevatorSetpoint(0.0, m_elevator).ToPtr());
frc2::JoystickButton(&m_joy, 8).OnTrue(OpenClaw(m_claw).ToPtr());
frc2::JoystickButton(&m_joy, 9).OnTrue(
Autonomous(m_claw, m_wrist, m_elevator, m_drivetrain).ToPtr());
frc2::JoystickButton(&m_joy, 10)
.WhenPressed(Pickup(m_claw, m_wrist, m_elevator));
.OnTrue(Pickup(m_claw, m_wrist, m_elevator).ToPtr());
frc2::JoystickButton(&m_joy, 11)
.WhenPressed(Place(m_claw, m_wrist, m_elevator));
.OnTrue(Place(m_claw, m_wrist, m_elevator).ToPtr());
frc2::JoystickButton(&m_joy, 12)
.WhenPressed(PrepareToPickup(m_claw, m_wrist, m_elevator));
.OnTrue(PrepareToPickup(m_claw, m_wrist, m_elevator).ToPtr());
}
frc2::Command* RobotContainer::GetAutonomousCommand() {

View File

@@ -5,6 +5,7 @@
#include "RobotContainer.h"
#include <frc/shuffleboard/Shuffleboard.h>
#include <frc2/command/Commands.h>
#include <frc2/command/PIDCommand.h>
#include <frc2/command/ParallelRaceGroup.h>
#include <frc2/command/RunCommand.h>
@@ -32,33 +33,35 @@ void RobotContainer::ConfigureButtonBindings() {
// Stabilize robot to drive straight with gyro when L1 is held
frc2::JoystickButton(&m_driverController, frc::PS4Controller::Button::kL1)
.WhenHeld(frc2::PIDCommand{
frc2::PIDController{dc::kStabilizationP, dc::kStabilizationI,
dc::kStabilizationD},
// Close the loop on the turn rate
[this] { return m_drive.GetTurnRate(); },
// Setpoint is 0
0,
// Pipe the output to the turning controls
[this](double output) {
m_drive.ArcadeDrive(m_driverController.GetLeftY(), output);
},
// Require the robot drive
{&m_drive}});
.WhileTrue(
frc2::PIDCommand(
frc2::PIDController{dc::kStabilizationP, dc::kStabilizationI,
dc::kStabilizationD},
// Close the loop on the turn rate
[this] { return m_drive.GetTurnRate(); },
// Setpoint is 0
0,
// Pipe the output to the turning controls
[this](double output) {
m_drive.ArcadeDrive(m_driverController.GetLeftY(), output);
},
// Require the robot drive
{&m_drive})
.ToPtr());
// Turn to 90 degrees when the 'Cross' button is pressed
frc2::JoystickButton(&m_driverController, frc::PS4Controller::Button::kCross)
.WhenPressed(TurnToAngle{90_deg, &m_drive}.WithTimeout(5_s));
.OnTrue(TurnToAngle{90_deg, &m_drive}.WithTimeout(5_s));
// Turn to -90 degrees with a profile when the 'Square' button is pressed,
// with a 5 second timeout
frc2::JoystickButton(&m_driverController, frc::PS4Controller::Button::kSquare)
.WhenPressed(TurnToAngle{90_deg, &m_drive}.WithTimeout(5_s));
.OnTrue(TurnToAngle{90_deg, &m_drive}.WithTimeout(5_s));
// While holding R1, drive at half speed
frc2::JoystickButton(&m_driverController, frc::PS4Controller::Button::kR1)
.WhenPressed(frc2::InstantCommand{[this] { m_drive.SetMaxOutput(0.5); }})
.WhenReleased(frc2::InstantCommand{[this] { m_drive.SetMaxOutput(1); }});
.OnTrue(frc2::cmd::RunOnce([this] { m_drive.SetMaxOutput(0.5); }, {}))
.OnFalse(frc2::cmd::RunOnce([this] { m_drive.SetMaxOutput(1); }, {}));
}
frc2::Command* RobotContainer::GetAutonomousCommand() {

View File

@@ -34,14 +34,14 @@ void RobotContainer::ConfigureButtonBindings() {
// Grab the hatch when the 'Circle' button is pressed.
frc2::JoystickButton(&m_driverController, frc::PS4Controller::Button::kCircle)
.WhenPressed(&m_grabHatch);
.OnTrue(&m_grabHatch);
// Release the hatch when the 'Square' button is pressed.
frc2::JoystickButton(&m_driverController, frc::PS4Controller::Button::kSquare)
.WhenPressed(&m_releaseHatch);
.OnTrue(&m_releaseHatch);
// While holding R1, drive at half speed
frc2::JoystickButton(&m_driverController, frc::PS4Controller::Button::kR1)
.WhenPressed(&m_driveHalfSpeed)
.WhenReleased(&m_driveFullSpeed);
.OnTrue(&m_driveHalfSpeed)
.OnFalse(&m_driveFullSpeed);
}
frc2::Command* RobotContainer::GetAutonomousCommand() {

View File

@@ -41,14 +41,14 @@ void RobotContainer::ConfigureButtonBindings() {
// Grab the hatch when the 'A' button is pressed.
frc2::JoystickButton(&m_driverController, frc::XboxController::Button::kA)
.WhenPressed(new GrabHatch(&m_hatch));
.OnTrue(GrabHatch(&m_hatch).ToPtr());
// Release the hatch when the 'B' button is pressed.
frc2::JoystickButton(&m_driverController, frc::XboxController::Button::kB)
.WhenPressed(new ReleaseHatch(&m_hatch));
.OnTrue(ReleaseHatch(&m_hatch).ToPtr());
// While holding the shoulder button, drive at half speed
frc2::JoystickButton(&m_driverController,
frc::XboxController::Button::kRightBumper)
.WhenHeld(new HalveDriveSpeed(&m_drive));
.WhileTrue(HalveDriveSpeed(&m_drive).ToPtr());
}
frc2::Command* RobotContainer::GetAutonomousCommand() {

View File

@@ -43,8 +43,8 @@ void RobotContainer::ConfigureButtonBindings() {
// While holding the shoulder button, drive at half speed
frc2::JoystickButton(&m_driverController,
frc::XboxController::Button::kRightBumper)
.WhenPressed(&m_driveHalfSpeed)
.WhenReleased(&m_driveFullSpeed);
.OnTrue(&m_driveHalfSpeed)
.OnFalse(&m_driveFullSpeed);
}
frc2::Command* RobotContainer::GetAutonomousCommand() {

View File

@@ -39,8 +39,8 @@ void RobotContainer::ConfigureButtonBindings() {
// While holding the shoulder button, drive at half speed
frc2::JoystickButton{&m_driverController, 6}
.WhenPressed(&m_driveHalfSpeed)
.WhenReleased(&m_driveFullSpeed);
.OnTrue(&m_driveHalfSpeed)
.OnFalse(&m_driveFullSpeed);
}
frc2::Command* RobotContainer::GetAutonomousCommand() {

View File

@@ -5,7 +5,7 @@
#include "RobotContainer.h"
#include <frc/smartdashboard/SmartDashboard.h>
#include <frc2/command/PrintCommand.h>
#include <frc2/command/Commands.h>
#include <frc2/command/button/Button.h>
#include "commands/TeleopArcadeDrive.h"
@@ -22,8 +22,8 @@ void RobotContainer::ConfigureButtonBindings() {
[this] { return m_controller.GetRawAxis(2); }));
// Example of how to use the onboard IO
m_onboardButtonA.WhenPressed(frc2::PrintCommand("Button A Pressed"))
.WhenReleased(frc2::PrintCommand("Button A Released"));
m_onboardButtonA.OnTrue(frc2::cmd::Print("Button A Pressed"))
.OnFalse(frc2::cmd::Print("Button A Released"));
// Setup SmartDashboard options.
m_chooser.SetDefaultOption("Auto Routine Distance", &m_autoDistance);

View File

@@ -7,6 +7,7 @@
#include <frc/Joystick.h>
#include <frc/smartdashboard/SendableChooser.h>
#include <frc2/command/Command.h>
#include <frc2/command/CommandPtr.h>
#include <frc2/command/button/Button.h>
#include "Constants.h"

View File

@@ -46,14 +46,14 @@ void RobotContainer::ConfigureButtonBindings() {
// Run instant command 1 when the 'A' button is pressed
frc2::JoystickButton(&m_driverController, frc::XboxController::Button::kA)
.WhenPressed(&m_instantCommand1);
.OnTrue(&m_instantCommand1);
// Run instant command 2 when the 'X' button is pressed
frc2::JoystickButton(&m_driverController, frc::XboxController::Button::kX)
.WhenPressed(&m_instantCommand2);
.OnTrue(&m_instantCommand2);
// Run instant command 3 when the 'Y' button is held; release early to
// interrupt
frc2::JoystickButton(&m_driverController, frc::XboxController::Button::kY)
.WhenHeld(&m_waitCommand);
.OnTrue(&m_waitCommand);
}
frc2::Command* RobotContainer::GetAutonomousCommand() {

View File

@@ -53,8 +53,8 @@ void RobotContainer::ConfigureButtonBindings() {
// While holding the shoulder button, drive at half speed
frc2::JoystickButton(&m_driverController,
frc::XboxController::Button::kRightBumper)
.WhenPressed(&m_driveHalfSpeed)
.WhenReleased(&m_driveFullSpeed);
.OnTrue(&m_driveHalfSpeed)
.OnFalse(&m_driveFullSpeed);
}
frc2::Command* RobotContainer::GetAutonomousCommand() {

View File

@@ -178,7 +178,7 @@ public class BooleanEvent implements BooleanSupplier {
* @param <T> the subclass type
* @return an instance of the subclass.
*/
public <T extends BooleanEvent> T castTo(BiFunction<EventLoop, BooleanSupplier, T> ctor) {
public <T extends BooleanSupplier> T castTo(BiFunction<EventLoop, BooleanSupplier, T> ctor) {
return ctor.apply(m_loop, m_signal);
}
}

View File

@@ -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)));
}
/**

View File

@@ -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)));
}
/**

View File

@@ -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)));
}
/**

View File

@@ -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)));
}
/**

View File

@@ -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));
}
/**

View File

@@ -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));
}
/**

View File

@@ -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)));
}
/**

View File

@@ -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));
}
/**

View File

@@ -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)));
}
/**

View File

@@ -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)));
}
/**

View File

@@ -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));

View File

@@ -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);
}
/**

View File

@@ -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() {