diff --git a/wpilibcExamples/src/main/cpp/examples/SwerveBot/cpp/SwerveModule.cpp b/wpilibcExamples/src/main/cpp/examples/SwerveBot/cpp/SwerveModule.cpp index 2e3f525dc38..8783385e91d 100644 --- a/wpilibcExamples/src/main/cpp/examples/SwerveBot/cpp/SwerveModule.cpp +++ b/wpilibcExamples/src/main/cpp/examples/SwerveBot/cpp/SwerveModule.cpp @@ -32,7 +32,12 @@ frc::SwerveModuleState SwerveModule::GetState() const { frc::Rotation2d(units::radian_t(m_turningEncoder.Get()))}; } -void SwerveModule::SetDesiredState(const frc::SwerveModuleState& state) { +void SwerveModule::SetDesiredState( + const frc::SwerveModuleState& referenceState) { + // Optimize the reference state to avoid spinning further than 90 degrees + const auto state = frc::SwerveModuleState::Optimize( + referenceState, units::radian_t(m_turningEncoder.Get())); + // Calculate the drive output from the drive PID controller. const auto driveOutput = m_drivePIDController.Calculate( m_driveEncoder.GetRate(), state.speed.to()); diff --git a/wpilibcExamples/src/main/cpp/examples/SwerveControllerCommand/cpp/subsystems/SwerveModule.cpp b/wpilibcExamples/src/main/cpp/examples/SwerveControllerCommand/cpp/subsystems/SwerveModule.cpp index 8c756a37c8d..bccafd7b756 100644 --- a/wpilibcExamples/src/main/cpp/examples/SwerveControllerCommand/cpp/subsystems/SwerveModule.cpp +++ b/wpilibcExamples/src/main/cpp/examples/SwerveControllerCommand/cpp/subsystems/SwerveModule.cpp @@ -43,7 +43,12 @@ frc::SwerveModuleState SwerveModule::GetState() { frc::Rotation2d(units::radian_t(m_turningEncoder.Get()))}; } -void SwerveModule::SetDesiredState(frc::SwerveModuleState& state) { +void SwerveModule::SetDesiredState( + const frc::SwerveModuleState& referenceState) { + // Optimize the reference state to avoid spinning further than 90 degrees + const auto state = frc::SwerveModuleState::Optimize( + referenceState, units::radian_t(m_turningEncoder.Get())); + // Calculate the drive output from the drive PID controller. const auto driveOutput = m_drivePIDController.Calculate( m_driveEncoder.GetRate(), state.speed.to()); diff --git a/wpilibcExamples/src/main/cpp/examples/SwerveControllerCommand/include/subsystems/SwerveModule.h b/wpilibcExamples/src/main/cpp/examples/SwerveControllerCommand/include/subsystems/SwerveModule.h index d501f0b7d08..7f3dba843b5 100644 --- a/wpilibcExamples/src/main/cpp/examples/SwerveControllerCommand/include/subsystems/SwerveModule.h +++ b/wpilibcExamples/src/main/cpp/examples/SwerveControllerCommand/include/subsystems/SwerveModule.h @@ -27,7 +27,7 @@ class SwerveModule { frc::SwerveModuleState GetState(); - void SetDesiredState(frc::SwerveModuleState& state); + void SetDesiredState(const frc::SwerveModuleState& state); void ResetEncoders(); diff --git a/wpilibcExamples/src/main/cpp/examples/SwerveDrivePoseEstimator/cpp/SwerveModule.cpp b/wpilibcExamples/src/main/cpp/examples/SwerveDrivePoseEstimator/cpp/SwerveModule.cpp index 5e88d10a530..6bb982f7fe9 100644 --- a/wpilibcExamples/src/main/cpp/examples/SwerveDrivePoseEstimator/cpp/SwerveModule.cpp +++ b/wpilibcExamples/src/main/cpp/examples/SwerveDrivePoseEstimator/cpp/SwerveModule.cpp @@ -32,7 +32,12 @@ frc::SwerveModuleState SwerveModule::GetState() const { frc::Rotation2d(units::radian_t(m_turningEncoder.Get()))}; } -void SwerveModule::SetDesiredState(const frc::SwerveModuleState& state) { +void SwerveModule::SetDesiredState( + const frc::SwerveModuleState& referenceState) { + // Optimize the reference state to avoid spinning further than 90 degrees + const auto state = frc::SwerveModuleState::Optimize( + referenceState, units::radian_t(m_turningEncoder.Get())); + // Calculate the drive output from the drive PID controller. const auto driveOutput = m_drivePIDController.Calculate( m_driveEncoder.GetRate(), state.speed.to()); diff --git a/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/swervebot/SwerveModule.java b/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/swervebot/SwerveModule.java index 469403f5299..eb619e1068e 100644 --- a/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/swervebot/SwerveModule.java +++ b/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/swervebot/SwerveModule.java @@ -79,9 +79,13 @@ public SwerveModuleState getState() { /** * Sets the desired state for the module. * - * @param state Desired state with speed and angle. + * @param desiredState Desired state with speed and angle. */ - public void setDesiredState(SwerveModuleState state) { + public void setDesiredState(SwerveModuleState desiredState) { + // Optimize the reference state to avoid spinning further than 90 degrees + SwerveModuleState state = + SwerveModuleState.optimize(desiredState, new Rotation2d(m_turningEncoder.get())); + // Calculate the drive output from the drive PID controller. final double driveOutput = m_drivePIDController.calculate(m_driveEncoder.getRate(), state.speedMetersPerSecond); diff --git a/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/swervecontrollercommand/subsystems/SwerveModule.java b/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/swervecontrollercommand/subsystems/SwerveModule.java index 34adc6d2f6b..4ec1545da0b 100644 --- a/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/swervecontrollercommand/subsystems/SwerveModule.java +++ b/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/swervecontrollercommand/subsystems/SwerveModule.java @@ -87,11 +87,15 @@ public SwerveModuleState getState() { /** * Sets the desired state for the module. * - * @param state Desired state with speed and angle. + * @param desiredState Desired state with speed and angle. */ - public void setDesiredState(SwerveModuleState state) { + public void setDesiredState(SwerveModuleState desiredState) { + // Optimize the reference state to avoid spinning further than 90 degrees + SwerveModuleState state = + SwerveModuleState.optimize(desiredState, new Rotation2d(m_turningEncoder.get())); + // Calculate the drive output from the drive PID controller. - final var driveOutput = + final double driveOutput = m_drivePIDController.calculate(m_driveEncoder.getRate(), state.speedMetersPerSecond); // Calculate the turning motor output from the turning PID controller. diff --git a/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/swervesdriveposeestimator/SwerveModule.java b/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/swervesdriveposeestimator/SwerveModule.java index a178f787c25..94886401395 100644 --- a/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/swervesdriveposeestimator/SwerveModule.java +++ b/wpilibjExamples/src/main/java/edu/wpi/first/wpilibj/examples/swervesdriveposeestimator/SwerveModule.java @@ -79,9 +79,13 @@ public SwerveModuleState getState() { /** * Sets the desired state for the module. * - * @param state Desired state with speed and angle. + * @param desiredState Desired state with speed and angle. */ - public void setDesiredState(SwerveModuleState state) { + public void setDesiredState(SwerveModuleState desiredState) { + // Optimize the reference state to avoid spinning further than 90 degrees + SwerveModuleState state = + SwerveModuleState.optimize(desiredState, new Rotation2d(m_turningEncoder.get())); + // Calculate the drive output from the drive PID controller. final double driveOutput = m_drivePIDController.calculate(m_driveEncoder.getRate(), state.speedMetersPerSecond); diff --git a/wpimath/src/main/java/edu/wpi/first/wpilibj/kinematics/SwerveModuleState.java b/wpimath/src/main/java/edu/wpi/first/wpilibj/kinematics/SwerveModuleState.java index a3096da7f89..2c800376d46 100644 --- a/wpimath/src/main/java/edu/wpi/first/wpilibj/kinematics/SwerveModuleState.java +++ b/wpimath/src/main/java/edu/wpi/first/wpilibj/kinematics/SwerveModuleState.java @@ -48,4 +48,24 @@ public String toString() { return String.format( "SwerveModuleState(Speed: %.2f m/s, Angle: %s)", speedMetersPerSecond, angle); } + + /** + * Minimize the change in heading the desired swerve module state would require by potentially + * reversing the direction the wheel spins. If this is used with the PIDController class's + * continuous input functionality, the furthest a wheel will ever rotate is 90 degrees. + * + * @param desiredState The desired state. + * @param currentAngle The current module angle. + */ + public static SwerveModuleState optimize( + SwerveModuleState desiredState, Rotation2d currentAngle) { + var delta = desiredState.angle.minus(currentAngle); + if (Math.abs(delta.getDegrees()) > 90.0) { + return new SwerveModuleState( + -desiredState.speedMetersPerSecond, + desiredState.angle.rotateBy(Rotation2d.fromDegrees(180.0))); + } else { + return new SwerveModuleState(desiredState.speedMetersPerSecond, desiredState.angle); + } + } } diff --git a/wpimath/src/main/native/include/frc/kinematics/SwerveModuleState.h b/wpimath/src/main/native/include/frc/kinematics/SwerveModuleState.h index 28ea9e58e05..52dfe8eff01 100644 --- a/wpimath/src/main/native/include/frc/kinematics/SwerveModuleState.h +++ b/wpimath/src/main/native/include/frc/kinematics/SwerveModuleState.h @@ -5,6 +5,8 @@ #pragma once #include "frc/geometry/Rotation2d.h" +#include "units/angle.h" +#include "units/math.h" #include "units/velocity.h" namespace frc { @@ -21,5 +23,24 @@ struct SwerveModuleState { * Angle of the module. */ Rotation2d angle; + + /** + * Minimize the change in heading the desired swerve module state would + * require by potentially reversing the direction the wheel spins. If this is + * used with the PIDController class's continuous input functionality, the + * furthest a wheel will ever rotate is 90 degrees. + * + * @param desiredState The desired state. + * @param currentAngle The current module angle. + */ + static SwerveModuleState Optimize(const SwerveModuleState& desiredState, + const Rotation2d& currentAngle) { + auto delta = desiredState.angle - currentAngle; + if (units::math::abs(delta.Degrees()) > 90_deg) { + return {-desiredState.speed, desiredState.angle + Rotation2d{180_deg}}; + } else { + return {desiredState.speed, desiredState.angle}; + } + } }; } // namespace frc