[wpilib] Add a default deadband to all gamepads (#8897)

The FTC DS had a deadband. Additionally, the FRC one had an implicit
deadband due to the only 8 bit resolution. We need a deadband by default
now with the high resolution gamepads.
This commit is contained in:
Thad House
2026-05-29 16:31:48 -07:00
committed by GitHub
parent 40fdb779d8
commit 635e971a02
5 changed files with 233 additions and 16 deletions

View File

@@ -127,14 +127,14 @@ Trigger CommandGamepad::Misc6(wpi::EventLoop* loop) const {
Trigger CommandGamepad::LeftTrigger(double threshold, Trigger CommandGamepad::LeftTrigger(double threshold,
wpi::EventLoop* loop) const { wpi::EventLoop* loop) const {
return Trigger(loop, [this, threshold] { return Trigger(loop, [this, threshold] {
return m_hid.GetLeftTriggerAxis() > threshold; return m_hid.GetAxis(wpi::Gamepad::Axis::LEFT_TRIGGER) > threshold;
}); });
} }
Trigger CommandGamepad::RightTrigger(double threshold, Trigger CommandGamepad::RightTrigger(double threshold,
wpi::EventLoop* loop) const { wpi::EventLoop* loop) const {
return Trigger(loop, [this, threshold] { return Trigger(loop, [this, threshold] {
return m_hid.GetRightTriggerAxis() > threshold; return m_hid.GetAxis(wpi::Gamepad::Axis::RIGHT_TRIGGER) > threshold;
}); });
} }

View File

@@ -4,39 +4,71 @@
#include "wpi/driverstation/Gamepad.hpp" #include "wpi/driverstation/Gamepad.hpp"
#include <algorithm>
#include <cmath>
#include "wpi/event/BooleanEvent.hpp" #include "wpi/event/BooleanEvent.hpp"
#include "wpi/hal/UsageReporting.hpp" #include "wpi/hal/UsageReporting.hpp"
#include "wpi/math/util/MathUtil.hpp"
#include "wpi/util/sendable/SendableBuilder.hpp" #include "wpi/util/sendable/SendableBuilder.hpp"
using namespace wpi; using namespace wpi;
static double ClampDeadband(double deadband) {
if (std::isnan(deadband)) {
return 0.0;
}
return std::clamp(deadband, 0.0, std::nextafter(1.0, 0.0));
}
Gamepad::Gamepad(int port) : GenericHID(port) { Gamepad::Gamepad(int port) : GenericHID(port) {
HAL_ReportUsage("HID", port, "Gamepad"); HAL_ReportUsage("HID", port, "Gamepad");
} }
double Gamepad::GetLeftX() const { double Gamepad::GetLeftX() const {
return GetAxis(Axis::LEFT_X); return wpi::math::ApplyDeadband(GetAxis(Axis::LEFT_X), m_leftXDeadband);
}
void Gamepad::SetLeftXDeadband(double deadband) {
m_leftXDeadband = ClampDeadband(deadband);
} }
double Gamepad::GetLeftY() const { double Gamepad::GetLeftY() const {
return GetAxis(Axis::LEFT_Y); return wpi::math::ApplyDeadband(GetAxis(Axis::LEFT_Y), m_leftYDeadband);
}
void Gamepad::SetLeftYDeadband(double deadband) {
m_leftYDeadband = ClampDeadband(deadband);
} }
double Gamepad::GetRightX() const { double Gamepad::GetRightX() const {
return GetAxis(Axis::RIGHT_X); return wpi::math::ApplyDeadband(GetAxis(Axis::RIGHT_X), m_rightXDeadband);
}
void Gamepad::SetRightXDeadband(double deadband) {
m_rightXDeadband = ClampDeadband(deadband);
} }
double Gamepad::GetRightY() const { double Gamepad::GetRightY() const {
return GetAxis(Axis::RIGHT_Y); return wpi::math::ApplyDeadband(GetAxis(Axis::RIGHT_Y), m_rightYDeadband);
}
void Gamepad::SetRightYDeadband(double deadband) {
m_rightYDeadband = ClampDeadband(deadband);
} }
double Gamepad::GetLeftTriggerAxis() const { double Gamepad::GetLeftTriggerAxis() const {
return GetAxis(Axis::LEFT_TRIGGER); return wpi::math::ApplyDeadband(GetAxis(Axis::LEFT_TRIGGER),
m_leftTriggerDeadband);
}
void Gamepad::SetLeftTriggerDeadband(double deadband) {
m_leftTriggerDeadband = ClampDeadband(deadband);
} }
BooleanEvent Gamepad::LeftTrigger(double threshold, EventLoop* loop) const { BooleanEvent Gamepad::LeftTrigger(double threshold, EventLoop* loop) const {
return BooleanEvent(loop, [this, threshold] { return BooleanEvent(loop, [this, threshold] {
return this->GetLeftTriggerAxis() > threshold; return this->GetAxis(Axis::LEFT_TRIGGER) > threshold;
}); });
} }
@@ -45,12 +77,17 @@ BooleanEvent Gamepad::LeftTrigger(EventLoop* loop) const {
} }
double Gamepad::GetRightTriggerAxis() const { double Gamepad::GetRightTriggerAxis() const {
return GetAxis(Axis::RIGHT_TRIGGER); return wpi::math::ApplyDeadband(GetAxis(Axis::RIGHT_TRIGGER),
m_rightTriggerDeadband);
}
void Gamepad::SetRightTriggerDeadband(double deadband) {
m_rightTriggerDeadband = ClampDeadband(deadband);
} }
BooleanEvent Gamepad::RightTrigger(double threshold, EventLoop* loop) const { BooleanEvent Gamepad::RightTrigger(double threshold, EventLoop* loop) const {
return BooleanEvent(loop, [this, threshold] { return BooleanEvent(loop, [this, threshold] {
return this->GetRightTriggerAxis() > threshold; return this->GetAxis(Axis::RIGHT_TRIGGER) > threshold;
}); });
} }

View File

@@ -116,39 +116,99 @@ class Gamepad : public GenericHID,
/** /**
* Get the X axis value of left side of the controller. Right is positive. * Get the X axis value of left side of the controller. Right is positive.
* *
* A deadband of 0.1 is applied by default. Use SetLeftXDeadband() to change
* it.
*
* @return the axis value. * @return the axis value.
*/ */
double GetLeftX() const; double GetLeftX() const;
/**
* Set the deadband for the left X axis.
*
* The deadband is clamped to [0, 1).
*
* @param deadband The deadband to apply.
*/
void SetLeftXDeadband(double deadband);
/** /**
* Get the Y axis value of left side of the controller. Back is positive. * Get the Y axis value of left side of the controller. Back is positive.
* *
* A deadband of 0.1 is applied by default. Use SetLeftYDeadband() to change
* it.
*
* @return the axis value. * @return the axis value.
*/ */
double GetLeftY() const; double GetLeftY() const;
/**
* Set the deadband for the left Y axis.
*
* The deadband is clamped to [0, 1).
*
* @param deadband The deadband to apply.
*/
void SetLeftYDeadband(double deadband);
/** /**
* Get the X axis value of right side of the controller. Right is positive. * Get the X axis value of right side of the controller. Right is positive.
* *
* A deadband of 0.1 is applied by default. Use SetRightXDeadband() to change
* it.
*
* @return the axis value. * @return the axis value.
*/ */
double GetRightX() const; double GetRightX() const;
/**
* Set the deadband for the right X axis.
*
* The deadband is clamped to [0, 1).
*
* @param deadband The deadband to apply.
*/
void SetRightXDeadband(double deadband);
/** /**
* Get the Y axis value of right side of the controller. Back is positive. * Get the Y axis value of right side of the controller. Back is positive.
* *
* A deadband of 0.1 is applied by default. Use SetRightYDeadband() to change
* it.
*
* @return the axis value. * @return the axis value.
*/ */
double GetRightY() const; double GetRightY() const;
/**
* Set the deadband for the right Y axis.
*
* The deadband is clamped to [0, 1).
*
* @param deadband The deadband to apply.
*/
void SetRightYDeadband(double deadband);
/** /**
* Get the left trigger axis value of the controller. Note that this axis * Get the left trigger axis value of the controller. Note that this axis
* is bound to the range of [0, 1] as opposed to the usual [-1, 1]. * is bound to the range of [0, 1] as opposed to the usual [-1, 1].
* *
* A deadband of 0.01 is applied by default. Use SetLeftTriggerDeadband() to
* change it.
*
* @return the axis value. * @return the axis value.
*/ */
double GetLeftTriggerAxis() const; double GetLeftTriggerAxis() const;
/**
* Set the deadband for the left trigger axis.
*
* The deadband is clamped to [0, 1).
*
* @param deadband The deadband to apply.
*/
void SetLeftTriggerDeadband(double deadband);
/** /**
* Constructs an event instance around the axis value of the left trigger. * Constructs an event instance around the axis value of the left trigger.
* The returned trigger will be true when the axis value is greater than * The returned trigger will be true when the axis value is greater than
@@ -175,10 +235,22 @@ class Gamepad : public GenericHID,
* Get the right trigger axis value of the controller. Note that this axis * Get the right trigger axis value of the controller. Note that this axis
* is bound to the range of [0, 1] as opposed to the usual [-1, 1]. * is bound to the range of [0, 1] as opposed to the usual [-1, 1].
* *
* A deadband of 0.01 is applied by default. Use SetRightTriggerDeadband() to
* change it.
*
* @return the axis value. * @return the axis value.
*/ */
double GetRightTriggerAxis() const; double GetRightTriggerAxis() const;
/**
* Set the deadband for the right trigger axis.
*
* The deadband is clamped to [0, 1).
*
* @param deadband The deadband to apply.
*/
void SetRightTriggerDeadband(double deadband);
/** /**
* Constructs an event instance around the axis value of the right trigger. * Constructs an event instance around the axis value of the right trigger.
* The returned trigger will be true when the axis value is greater than * The returned trigger will be true when the axis value is greater than
@@ -1090,6 +1162,13 @@ class Gamepad : public GenericHID,
private: private:
double GetAxisForSendable(Axis axis) const; double GetAxisForSendable(Axis axis) const;
bool GetButtonForSendable(Button button) const; bool GetButtonForSendable(Button button) const;
double m_leftXDeadband = 0.1;
double m_leftYDeadband = 0.1;
double m_rightXDeadband = 0.1;
double m_rightYDeadband = 0.1;
double m_leftTriggerDeadband = 0.01;
double m_rightTriggerDeadband = 0.01;
}; };
} // namespace wpi } // namespace wpi

View File

@@ -8,15 +8,21 @@ classes:
methods: methods:
Gamepad: Gamepad:
GetLeftX: GetLeftX:
SetLeftXDeadband:
GetLeftY: GetLeftY:
SetLeftYDeadband:
GetRightX: GetRightX:
SetRightXDeadband:
GetRightY: GetRightY:
SetRightYDeadband:
GetLeftTriggerAxis: GetLeftTriggerAxis:
SetLeftTriggerDeadband:
LeftTrigger: LeftTrigger:
overloads: overloads:
double, EventLoop* [const]: double, EventLoop* [const]:
EventLoop* [const]: EventLoop* [const]:
GetRightTriggerAxis: GetRightTriggerAxis:
SetRightTriggerDeadband:
RightTrigger: RightTrigger:
overloads: overloads:
double, EventLoop* [const]: double, EventLoop* [const]:

View File

@@ -8,6 +8,7 @@ import org.wpilib.driverstation.internal.DriverStationBackend;
import org.wpilib.event.BooleanEvent; import org.wpilib.event.BooleanEvent;
import org.wpilib.event.EventLoop; import org.wpilib.event.EventLoop;
import org.wpilib.hardware.hal.HAL; import org.wpilib.hardware.hal.HAL;
import org.wpilib.math.util.MathUtil;
import org.wpilib.util.sendable.Sendable; import org.wpilib.util.sendable.Sendable;
import org.wpilib.util.sendable.SendableBuilder; import org.wpilib.util.sendable.SendableBuilder;
@@ -23,6 +24,8 @@ import org.wpilib.util.sendable.SendableBuilder;
* party controllers. * party controllers.
*/ */
public class Gamepad extends GenericHID implements Sendable { public class Gamepad extends GenericHID implements Sendable {
private static final double MAX_DEADBAND = Math.nextDown(1.0);
/** Represents a digital button on a Gamepad. */ /** Represents a digital button on a Gamepad. */
public enum Button { public enum Button {
/** Face Down button. */ /** Face Down button. */
@@ -139,6 +142,20 @@ public class Gamepad extends GenericHID implements Sendable {
} }
} }
private double m_leftXDeadband = 0.1;
private double m_leftYDeadband = 0.1;
private double m_rightXDeadband = 0.1;
private double m_rightYDeadband = 0.1;
private double m_leftTriggerDeadband = 0.01;
private double m_rightTriggerDeadband = 0.01;
private static double clampDeadband(double deadband) {
if (Double.isNaN(deadband)) {
return 0.0;
}
return Math.clamp(deadband, 0.0, MAX_DEADBAND);
}
/** /**
* Construct an instance of a controller. * Construct an instance of a controller.
* *
@@ -149,50 +166,126 @@ public class Gamepad extends GenericHID implements Sendable {
HAL.reportUsage("HID", port, "Gamepad"); HAL.reportUsage("HID", port, "Gamepad");
} }
/**
* Set the deadband for the left X axis.
*
* <p>The deadband is clamped to [0, 1).
*
* @param deadband The deadband to apply.
*/
public void setLeftXDeadband(double deadband) {
m_leftXDeadband = clampDeadband(deadband);
}
/**
* Set the deadband for the left Y axis.
*
* <p>The deadband is clamped to [0, 1).
*
* @param deadband The deadband to apply.
*/
public void setLeftYDeadband(double deadband) {
m_leftYDeadband = clampDeadband(deadband);
}
/**
* Set the deadband for the right X axis.
*
* <p>The deadband is clamped to [0, 1).
*
* @param deadband The deadband to apply.
*/
public void setRightXDeadband(double deadband) {
m_rightXDeadband = clampDeadband(deadband);
}
/**
* Set the deadband for the right Y axis.
*
* <p>The deadband is clamped to [0, 1).
*
* @param deadband The deadband to apply.
*/
public void setRightYDeadband(double deadband) {
m_rightYDeadband = clampDeadband(deadband);
}
/**
* Set the deadband for the left trigger axis.
*
* <p>The deadband is clamped to [0, 1).
*
* @param deadband The deadband to apply.
*/
public void setLeftTriggerDeadband(double deadband) {
m_leftTriggerDeadband = clampDeadband(deadband);
}
/**
* Set the deadband for the right trigger axis.
*
* <p>The deadband is clamped to [0, 1).
*
* @param deadband The deadband to apply.
*/
public void setRightTriggerDeadband(double deadband) {
m_rightTriggerDeadband = clampDeadband(deadband);
}
/** /**
* Get the X axis value of left side of the controller. Right is positive. * Get the X axis value of left side of the controller. Right is positive.
* *
* <p>A deadband of 0.1 is applied by default. Use {@link #setLeftXDeadband} to change it.
*
* @return The axis value. * @return The axis value.
*/ */
public double getLeftX() { public double getLeftX() {
return getAxis(Axis.LEFT_X); return MathUtil.applyDeadband(getAxis(Axis.LEFT_X), m_leftXDeadband);
} }
/** /**
* Get the Y axis value of left side of the controller. Back is positive. * Get the Y axis value of left side of the controller. Back is positive.
* *
* <p>A deadband of 0.1 is applied by default. Use {@link #setLeftYDeadband} to change it.
*
* @return The axis value. * @return The axis value.
*/ */
public double getLeftY() { public double getLeftY() {
return getAxis(Axis.LEFT_Y); return MathUtil.applyDeadband(getAxis(Axis.LEFT_Y), m_leftYDeadband);
} }
/** /**
* Get the X axis value of right side of the controller. Right is positive. * Get the X axis value of right side of the controller. Right is positive.
* *
* <p>A deadband of 0.1 is applied by default. Use {@link #setRightXDeadband} to change it.
*
* @return The axis value. * @return The axis value.
*/ */
public double getRightX() { public double getRightX() {
return getAxis(Axis.RIGHT_X); return MathUtil.applyDeadband(getAxis(Axis.RIGHT_X), m_rightXDeadband);
} }
/** /**
* Get the Y axis value of right side of the controller. Back is positive. * Get the Y axis value of right side of the controller. Back is positive.
* *
* <p>A deadband of 0.1 is applied by default. Use {@link #setRightYDeadband} to change it.
*
* @return The axis value. * @return The axis value.
*/ */
public double getRightY() { public double getRightY() {
return getAxis(Axis.RIGHT_Y); return MathUtil.applyDeadband(getAxis(Axis.RIGHT_Y), m_rightYDeadband);
} }
/** /**
* Get the left trigger axis value of the controller. Note that this axis is bound to the range of * Get the left trigger axis value of the controller. Note that this axis is bound to the range of
* [0, 1] as opposed to the usual [-1, 1]. * [0, 1] as opposed to the usual [-1, 1].
* *
* <p>A deadband of 0.01 is applied by default. Use {@link #setLeftTriggerDeadband} to change it.
*
* @return The axis value. * @return The axis value.
*/ */
public double getLeftTriggerAxis() { public double getLeftTriggerAxis() {
return getAxis(Axis.LEFT_TRIGGER); return MathUtil.applyDeadband(getAxis(Axis.LEFT_TRIGGER), m_leftTriggerDeadband);
} }
/** /**
@@ -225,10 +318,12 @@ public class Gamepad extends GenericHID implements Sendable {
* Get the right trigger axis value of the controller. Note that this axis is bound to the range * Get the right trigger axis value of the controller. Note that this axis is bound to the range
* of [0, 1] as opposed to the usual [-1, 1]. * of [0, 1] as opposed to the usual [-1, 1].
* *
* <p>A deadband of 0.01 is applied by default. Use {@link #setRightTriggerDeadband} to change it.
*
* @return The axis value. * @return The axis value.
*/ */
public double getRightTriggerAxis() { public double getRightTriggerAxis() {
return getAxis(Axis.RIGHT_TRIGGER); return MathUtil.applyDeadband(getAxis(Axis.RIGHT_TRIGGER), m_rightTriggerDeadband);
} }
/** /**