|
4 | 4 |
|
5 | 5 | package frc.robot.subsystems;
|
6 | 6 |
|
| 7 | +import edu.wpi.first.math.filter.SlewRateLimiter; |
7 | 8 | import edu.wpi.first.math.geometry.Pose2d;
|
8 | 9 | import edu.wpi.first.math.geometry.Rotation2d;
|
9 | 10 | import edu.wpi.first.math.kinematics.ChassisSpeeds;
|
10 | 11 | import edu.wpi.first.math.kinematics.SwerveDriveKinematics;
|
11 | 12 | import edu.wpi.first.math.kinematics.SwerveDriveOdometry;
|
12 | 13 | import edu.wpi.first.math.kinematics.SwerveModulePosition;
|
13 | 14 | import edu.wpi.first.math.kinematics.SwerveModuleState;
|
| 15 | +import edu.wpi.first.util.WPIUtilJNI; |
14 | 16 | import edu.wpi.first.wpilibj.ADIS16470_IMU;
|
15 | 17 | import frc.robot.Constants.DriveConstants;
|
| 18 | +import frc.utils.SwerveUtils; |
16 | 19 | import edu.wpi.first.wpilibj2.command.SubsystemBase;
|
17 | 20 |
|
18 | 21 | public class DriveSubsystem extends SubsystemBase {
|
@@ -40,6 +43,15 @@ public class DriveSubsystem extends SubsystemBase {
|
40 | 43 | // The gyro sensor
|
41 | 44 | private final ADIS16470_IMU m_gyro = new ADIS16470_IMU();
|
42 | 45 |
|
| 46 | + // Slew rate filter variables for controlling lateral acceleration |
| 47 | + private double m_currentRotation = 0.0; |
| 48 | + private double m_currentTranslationDir = 0.0; |
| 49 | + private double m_currentTranslationMag = 0.0; |
| 50 | + |
| 51 | + private SlewRateLimiter m_magLimiter = new SlewRateLimiter(DriveConstants.kMagnitudeSlewRate); |
| 52 | + private SlewRateLimiter m_rotLimiter = new SlewRateLimiter(DriveConstants.kRotationalSlewRate); |
| 53 | + private double m_prevTime = WPIUtilJNI.now() * 1e-6; |
| 54 | + |
43 | 55 | // Odometry class for tracking robot pose
|
44 | 56 | SwerveDriveOdometry m_odometry = new SwerveDriveOdometry(
|
45 | 57 | DriveConstants.kDriveKinematics,
|
@@ -102,17 +114,70 @@ public void resetOdometry(Pose2d pose) {
|
102 | 114 | * @param rot Angular rate of the robot.
|
103 | 115 | * @param fieldRelative Whether the provided x and y speeds are relative to the
|
104 | 116 | * field.
|
| 117 | + * @param rateLimit Whether to enable rate limiting for smoother control. |
105 | 118 | */
|
106 |
| - public void drive(double xSpeed, double ySpeed, double rot, boolean fieldRelative) { |
107 |
| - // Adjust input based on max speed |
108 |
| - xSpeed *= DriveConstants.kMaxSpeedMetersPerSecond; |
109 |
| - ySpeed *= DriveConstants.kMaxSpeedMetersPerSecond; |
110 |
| - rot *= DriveConstants.kMaxAngularSpeed; |
| 119 | + public void drive(double xSpeed, double ySpeed, double rot, boolean fieldRelative, boolean rateLimit) { |
| 120 | + |
| 121 | + double xSpeedCommanded; |
| 122 | + double ySpeedCommanded; |
| 123 | + |
| 124 | + if (rateLimit) { |
| 125 | + // Convert XY to polar for rate limiting |
| 126 | + double inputTranslationDir = Math.atan2(ySpeed, xSpeed); |
| 127 | + double inputTranslationMag = Math.sqrt(Math.pow(xSpeed, 2) + Math.pow(ySpeed, 2)); |
| 128 | + |
| 129 | + // Calculate the direction slew rate based on an estimate of the lateral acceleration |
| 130 | + double directionSlewRate; |
| 131 | + if (m_currentTranslationMag != 0.0) { |
| 132 | + directionSlewRate = Math.abs(DriveConstants.kDirectionSlewRate / m_currentTranslationMag); |
| 133 | + } else { |
| 134 | + directionSlewRate = 500.0; //some high number that means the slew rate is effectively instantaneous |
| 135 | + } |
| 136 | + |
| 137 | + |
| 138 | + double currentTime = WPIUtilJNI.now() * 1e-6; |
| 139 | + double elapsedTime = currentTime - m_prevTime; |
| 140 | + double angleDif = SwerveUtils.AngleDifference(inputTranslationDir, m_currentTranslationDir); |
| 141 | + if (angleDif < 0.45*Math.PI) { |
| 142 | + m_currentTranslationDir = SwerveUtils.StepTowardsCircular(m_currentTranslationDir, inputTranslationDir, directionSlewRate * elapsedTime); |
| 143 | + m_currentTranslationMag = m_magLimiter.calculate(inputTranslationMag); |
| 144 | + } |
| 145 | + else if (angleDif > 0.85*Math.PI) { |
| 146 | + if (m_currentTranslationMag > 1e-4) { //some small number to avoid floating-point errors with equality checking |
| 147 | + // keep currentTranslationDir unchanged |
| 148 | + m_currentTranslationMag = m_magLimiter.calculate(0.0); |
| 149 | + } |
| 150 | + else { |
| 151 | + m_currentTranslationDir = SwerveUtils.WrapAngle(m_currentTranslationDir + Math.PI); |
| 152 | + m_currentTranslationMag = m_magLimiter.calculate(inputTranslationMag); |
| 153 | + } |
| 154 | + } |
| 155 | + else { |
| 156 | + m_currentTranslationDir = SwerveUtils.StepTowardsCircular(m_currentTranslationDir, inputTranslationDir, directionSlewRate * elapsedTime); |
| 157 | + m_currentTranslationMag = m_magLimiter.calculate(0.0); |
| 158 | + } |
| 159 | + m_prevTime = currentTime; |
| 160 | + |
| 161 | + xSpeedCommanded = m_currentTranslationMag * Math.cos(m_currentTranslationDir); |
| 162 | + ySpeedCommanded = m_currentTranslationMag * Math.sin(m_currentTranslationDir); |
| 163 | + m_currentRotation = m_rotLimiter.calculate(rot); |
| 164 | + |
| 165 | + |
| 166 | + } else { |
| 167 | + xSpeedCommanded = xSpeed; |
| 168 | + ySpeedCommanded = ySpeed; |
| 169 | + m_currentRotation = rot; |
| 170 | + } |
| 171 | + |
| 172 | + // Convert the commanded speeds into the correct units for the drivetrain |
| 173 | + double xSpeedDelivered = xSpeedCommanded * DriveConstants.kMaxSpeedMetersPerSecond; |
| 174 | + double ySpeedDelivered = ySpeedCommanded * DriveConstants.kMaxSpeedMetersPerSecond; |
| 175 | + double rotDelivered = m_currentRotation * DriveConstants.kMaxAngularSpeed; |
111 | 176 |
|
112 | 177 | var swerveModuleStates = DriveConstants.kDriveKinematics.toSwerveModuleStates(
|
113 | 178 | fieldRelative
|
114 |
| - ? ChassisSpeeds.fromFieldRelativeSpeeds(xSpeed, ySpeed, rot, Rotation2d.fromDegrees(m_gyro.getAngle())) |
115 |
| - : new ChassisSpeeds(xSpeed, ySpeed, rot)); |
| 179 | + ? ChassisSpeeds.fromFieldRelativeSpeeds(xSpeedDelivered, ySpeedDelivered, rotDelivered, Rotation2d.fromDegrees(m_gyro.getAngle())) |
| 180 | + : new ChassisSpeeds(xSpeedDelivered, ySpeedDelivered, rotDelivered)); |
116 | 181 | SwerveDriveKinematics.desaturateWheelSpeeds(
|
117 | 182 | swerveModuleStates, DriveConstants.kMaxSpeedMetersPerSecond);
|
118 | 183 | m_frontLeft.setDesiredState(swerveModuleStates[0]);
|
|
0 commit comments