diff --git a/wpilibc/src/main/native/cpp/drive/DifferentialDrive.cpp b/wpilibc/src/main/native/cpp/drive/DifferentialDrive.cpp index 85232193a4..4a65d11c8e 100644 --- a/wpilibc/src/main/native/cpp/drive/DifferentialDrive.cpp +++ b/wpilibc/src/main/native/cpp/drive/DifferentialDrive.cpp @@ -115,8 +115,8 @@ DifferentialDrive::WheelSpeeds DifferentialDrive::ArcadeDriveIK( // Square the inputs (while preserving the sign) to increase fine control // while permitting full power. if (squareInputs) { - xSpeed = std::copysign(xSpeed * xSpeed, xSpeed); - zRotation = std::copysign(zRotation * zRotation, zRotation); + xSpeed = CopySignPow(xSpeed, 2); + zRotation = CopySignPow(zRotation, 2); } double leftSpeed = xSpeed - zRotation; @@ -170,8 +170,8 @@ DifferentialDrive::WheelSpeeds DifferentialDrive::TankDriveIK( // Square the inputs (while preserving the sign) to increase fine control // while permitting full power. if (squareInputs) { - leftSpeed = std::copysign(leftSpeed * leftSpeed, leftSpeed); - rightSpeed = std::copysign(rightSpeed * rightSpeed, rightSpeed); + leftSpeed = CopySignPow(leftSpeed, 2); + rightSpeed = CopySignPow(rightSpeed, 2); } return {leftSpeed, rightSpeed}; diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/DifferentialDrive.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/DifferentialDrive.java index 40e34a803d..676a8ea470 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/DifferentialDrive.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/DifferentialDrive.java @@ -265,8 +265,8 @@ public class DifferentialDrive extends RobotDriveBase implements Sendable, AutoC // Square the inputs (while preserving the sign) to increase fine control // while permitting full power. if (squareInputs) { - xSpeed = Math.copySign(xSpeed * xSpeed, xSpeed); - zRotation = Math.copySign(zRotation * zRotation, zRotation); + xSpeed = MathUtil.copySignPow(xSpeed, 2); + zRotation = MathUtil.copySignPow(zRotation, 2); } double leftSpeed = xSpeed - zRotation; @@ -340,8 +340,8 @@ public class DifferentialDrive extends RobotDriveBase implements Sendable, AutoC // Square the inputs (while preserving the sign) to increase fine control // while permitting full power. if (squareInputs) { - leftSpeed = Math.copySign(leftSpeed * leftSpeed, leftSpeed); - rightSpeed = Math.copySign(rightSpeed * rightSpeed, rightSpeed); + leftSpeed = MathUtil.copySignPow(leftSpeed, 2); + rightSpeed = MathUtil.copySignPow(rightSpeed, 2); } return new WheelSpeeds(leftSpeed, rightSpeed); diff --git a/wpimath/src/main/java/edu/wpi/first/math/MathUtil.java b/wpimath/src/main/java/edu/wpi/first/math/MathUtil.java index 1e374ec583..239a6a31fb 100644 --- a/wpimath/src/main/java/edu/wpi/first/math/MathUtil.java +++ b/wpimath/src/main/java/edu/wpi/first/math/MathUtil.java @@ -107,6 +107,42 @@ public final class MathUtil { return applyDeadband(value, deadband, 1); } + /** + * Raises the input to the power of the given exponent while preserving its sign. + * + *
The function normalizes the input value to the range [0, 1] based on the maximum magnitude, + * raises it to the power of the exponent, then scales the result back to the original range and + * copying the sign. This keeps the value in the original range and gives consistent curve + * behavior regardless of the input value's scale. + * + *
This is useful for applying smoother or more aggressive control response curves (e.g. + * joystick input shaping). + * + * @param value The input value to transform. + * @param exponent The exponent to apply (e.g. 1.0 = linear, 2.0 = squared curve). Must be + * positive. + * @param maxMagnitude The maximum expected absolute value of input. Must be positive. + * @return The transformed value with the same sign and scaled to the input range. + */ + public static double copySignPow(double value, double exponent, double maxMagnitude) { + return Math.copySign(Math.pow(Math.abs(value) / maxMagnitude, exponent), value) * maxMagnitude; + } + + /** + * Raises the input to the power of the given exponent while preserving its sign. + * + *
This is useful for applying smoother or more aggressive control response curves (e.g.
+ * joystick input shaping).
+ *
+ * @param value The input value to transform.
+ * @param exponent The exponent to apply (e.g. 1.0 = linear, 2.0 = squared curve). Must be
+ * positive.
+ * @return The transformed value with the same sign.
+ */
+ public static double copySignPow(double value, double exponent) {
+ return copySignPow(value, exponent, 1);
+ }
+
/**
* Returns modulus of input.
*
diff --git a/wpimath/src/main/native/include/frc/MathUtil.h b/wpimath/src/main/native/include/frc/MathUtil.h
index 060be0da91..97705811f9 100644
--- a/wpimath/src/main/native/include/frc/MathUtil.h
+++ b/wpimath/src/main/native/include/frc/MathUtil.h
@@ -94,6 +94,42 @@ constexpr T ApplyDeadband(T value, T deadband, T maxMagnitude = T{1.0}) {
}
}
+/**
+ * Raises the input to the power of the given exponent while preserving its
+ * sign.
+ *
+ * The function normalizes the input value to the range [0, 1] based on the
+ * maximum magnitude, raises it to the power of the exponent, then scales the
+ * result back to the original range and copying the sign. This keeps the value
+ * in the original range and gives consistent curve behavior regardless of the
+ * input value's scale.
+ *
+ * This is useful for applying smoother or more aggressive control response
+ * curves (e.g. joystick input shaping).
+ *
+ * @param value The input value to transform.
+ * @param exponent The exponent to apply (e.g. 1.0 = linear, 2.0 = squared
+ * curve). Must be positive.
+ * @param maxMagnitude The maximum expected absolute value of input. Must be
+ * positive.
+ * @return The transformed value with the same sign and scaled to the input
+ * range.
+ */
+template