Skip to content
This repository was archived by the owner on Feb 16, 2026. It is now read-only.

Commit 039e5c2

Browse files
Improved inverted IMU's using ternary operations. Removed debug parameter. Removed redundant inversion from SwerveDriveConfiguration. Added getOdometryHeading. Utilize getOdometryHeading alot within SwerveDrive. Fixed SwerveSubsystem. Fixed vision measurement issue. Removed dedicated visionStdDevs and stateStdDevs.
Signed-off-by: thenetworkgrinch <thenetworkgrinch@users.noreply.github.com>
1 parent d1b07d2 commit 039e5c2

File tree

14 files changed

+124
-151
lines changed

14 files changed

+124
-151
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
plugins {
22
id "java"
3-
id "edu.wpi.first.GradleRIO" version "2024.1.1"
3+
id "edu.wpi.first.GradleRIO" version "2024.2.1"
44
}
55

66
java {

simgui.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,12 @@
8585
"arrowWeight": 3.0,
8686
"style": "Hidden"
8787
},
88+
"bottom": 1476,
89+
"height": 8.210550308227539,
90+
"left": 150,
91+
"right": 2961,
92+
"top": 79,
93+
"width": 16.541748046875,
8894
"window": {
8995
"visible": true
9096
}

src/main/java/swervelib/SwerveDrive.java

Lines changed: 57 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package swervelib;
22

33
import edu.wpi.first.math.Matrix;
4-
import edu.wpi.first.math.VecBuilder;
54
import edu.wpi.first.math.controller.SimpleMotorFeedforward;
65
import edu.wpi.first.math.estimator.SwerveDrivePoseEstimator;
76
import edu.wpi.first.math.filter.SlewRateLimiter;
@@ -72,9 +71,12 @@ public class SwerveDrive
7271
*/
7372
private final Lock odometryLock = new ReentrantLock();
7473
/**
75-
* Deadband for speeds in heading correction.
74+
* Alert to recommend Tuner X if the configuration is compatible.
7675
*/
77-
private double HEADING_CORRECTION_DEADBAND = 0.01;
76+
private final Alert tunerXRecommendation = new Alert("Swerve Drive",
77+
"Your Swerve Drive is compatible with Tuner X swerve generator, please consider using that instead of YAGSL. More information here!\n" +
78+
"https://pro.docs.ctr-electronics.com/en/latest/docs/tuner/tuner-swerve/index.html",
79+
AlertType.WARNING);
7880
/**
7981
* Field object.
8082
*/
@@ -83,26 +85,6 @@ public class SwerveDrive
8385
* Swerve controller for controlling heading of the robot.
8486
*/
8587
public SwerveController swerveController;
86-
/**
87-
* Standard deviation of encoders and gyroscopes, usually should not change. (meters of position and degrees of
88-
* rotation)
89-
*/
90-
public Matrix<N3, N1> stateStdDevs = VecBuilder.fill(0.1,
91-
0.1,
92-
0.1);
93-
/**
94-
* The standard deviation of the vision measurement, for best accuracy calculate the standard deviation at 2 or more
95-
* points and fit a line to it and modify this using {@link SwerveDrive#addVisionMeasurement(Pose2d, double, Matrix)}
96-
* with the calculated optimal standard deviation. (Units should be meters per pixel). By optimizing this you can get
97-
* vision accurate to inches instead of feet.
98-
*/
99-
public Matrix<N3, N1> visionMeasurementStdDevs = VecBuilder.fill(0.9,
100-
0.9,
101-
0.9);
102-
/**
103-
* Invert odometry readings of drive motor positions, used as a patch for debugging currently.
104-
*/
105-
public boolean invertOdometry = false;
10688
/**
10789
* Correct chassis velocity in {@link SwerveDrive#drive(Translation2d, double, boolean, boolean)} using 254's
10890
* correction.
@@ -112,6 +94,10 @@ public class SwerveDrive
11294
* Whether to correct heading when driving translationally. Set to true to enable.
11395
*/
11496
public boolean headingCorrection = false;
97+
/**
98+
* Deadband for speeds in heading correction.
99+
*/
100+
private double HEADING_CORRECTION_DEADBAND = 0.01;
115101
/**
116102
* Whether heading correction PID is currently active.
117103
*/
@@ -144,13 +130,6 @@ public class SwerveDrive
144130
* Maximum speed of the robot in meters per second.
145131
*/
146132
private double maxSpeedMPS;
147-
/**
148-
* Alert to recommend Tuner X if the configuration is compatible.
149-
*/
150-
private final Alert tunerXRecommendation = new Alert("Swerve Drive",
151-
"Your Swerve Drive is compatible with Tuner X swerve generator, please consider using that instead of YAGSL. More information here!\n" +
152-
"https://pro.docs.ctr-electronics.com/en/latest/docs/tuner/tuner-swerve/index.html",
153-
AlertType.WARNING);
154133

155134
/**
156135
* Creates a new swerve drivebase subsystem. Robot is controlled via the {@link SwerveDrive#drive} method, or via the
@@ -194,9 +173,8 @@ public SwerveDrive(
194173
kinematics,
195174
getYaw(),
196175
getModulePositions(),
197-
new Pose2d(new Translation2d(0, 0), Rotation2d.fromDegrees(0)),
198-
stateStdDevs,
199-
visionMeasurementStdDevs); // x,y,heading in radians; Vision measurement std dev, higher=less weight
176+
new Pose2d(new Translation2d(0, 0),
177+
Rotation2d.fromDegrees(0))); // x,y,heading in radians; Vision measurement std dev, higher=less weight
200178

201179
zeroGyro();
202180

@@ -308,6 +286,16 @@ public void setDriveMotorConversionFactor(double conversionFactor)
308286
}
309287
}
310288

289+
/**
290+
* Fetch the latest odometry heading, should be trusted over {@link SwerveDrive#getYaw()}.
291+
*
292+
* @return {@link Rotation2d} of the robot heading.
293+
*/
294+
public Rotation2d getOdometryHeading()
295+
{
296+
return swerveDrivePoseEstimator.getEstimatedPosition().getRotation();
297+
}
298+
311299
/**
312300
* Set the heading correction capabilities of YAGSL.
313301
*
@@ -337,7 +325,7 @@ public void setHeadingCorrection(boolean state, double deadband)
337325
*/
338326
public void driveFieldOriented(ChassisSpeeds velocity)
339327
{
340-
ChassisSpeeds fieldOrientedVelocity = ChassisSpeeds.fromFieldRelativeSpeeds(velocity, getYaw());
328+
ChassisSpeeds fieldOrientedVelocity = ChassisSpeeds.fromFieldRelativeSpeeds(velocity, getOdometryHeading());
341329
drive(fieldOrientedVelocity);
342330
}
343331

@@ -349,7 +337,7 @@ public void driveFieldOriented(ChassisSpeeds velocity)
349337
*/
350338
public void driveFieldOriented(ChassisSpeeds velocity, Translation2d centerOfRotationMeters)
351339
{
352-
ChassisSpeeds fieldOrientedVelocity = ChassisSpeeds.fromFieldRelativeSpeeds(velocity, getYaw());
340+
ChassisSpeeds fieldOrientedVelocity = ChassisSpeeds.fromFieldRelativeSpeeds(velocity, getOdometryHeading());
353341
drive(fieldOrientedVelocity, centerOfRotationMeters);
354342
}
355343

@@ -401,7 +389,7 @@ public void drive(
401389
ChassisSpeeds velocity =
402390
fieldRelative
403391
? ChassisSpeeds.fromFieldRelativeSpeeds(
404-
translation.getX(), translation.getY(), rotation, getYaw())
392+
translation.getX(), translation.getY(), rotation, getOdometryHeading())
405393
: new ChassisSpeeds(translation.getX(), translation.getY(), rotation);
406394

407395
drive(velocity, isOpenLoop, centerOfRotationMeters);
@@ -430,7 +418,7 @@ public void drive(
430418
ChassisSpeeds velocity =
431419
fieldRelative
432420
? ChassisSpeeds.fromFieldRelativeSpeeds(
433-
translation.getX(), translation.getY(), rotation, getYaw())
421+
translation.getX(), translation.getY(), rotation, getOdometryHeading())
434422
: new ChassisSpeeds(translation.getX(), translation.getY(), rotation);
435423

436424
drive(velocity, isOpenLoop, new Translation2d());
@@ -466,11 +454,11 @@ public void drive(ChassisSpeeds velocity, boolean isOpenLoop, Translation2d cent
466454
{
467455
if (!correctionEnabled)
468456
{
469-
lastHeadingRadians = getYaw().getRadians();
457+
lastHeadingRadians = getOdometryHeading().getRadians();
470458
correctionEnabled = true;
471459
}
472460
velocity.omegaRadiansPerSecond =
473-
swerveController.headingCalculate(lastHeadingRadians, getYaw().getRadians());
461+
swerveController.headingCalculate(lastHeadingRadians, getOdometryHeading().getRadians());
474462
} else
475463
{
476464
correctionEnabled = false;
@@ -623,7 +611,7 @@ public ChassisSpeeds getFieldVelocity()
623611
// angle
624612
// given as the robot angle reverses the direction of rotation, and the conversion is reversed.
625613
return ChassisSpeeds.fromFieldRelativeSpeeds(
626-
kinematics.toChassisSpeeds(getStates()), getYaw().unaryMinus());
614+
kinematics.toChassisSpeeds(getStates()), getOdometryHeading().unaryMinus());
627615
}
628616

629617
/**
@@ -680,8 +668,7 @@ public SwerveModuleState[] getStates()
680668
}
681669

682670
/**
683-
* Gets the current module positions (azimuth and wheel position (meters)). Inverts the distance from each module if
684-
* {@link #invertOdometry} is true.
671+
* Gets the current module positions (azimuth and wheel position (meters)).
685672
*
686673
* @return A list of SwerveModulePositions containg the current module positions
687674
*/
@@ -692,10 +679,6 @@ public SwerveModulePosition[] getModulePositions()
692679
for (SwerveModule module : swerveModules)
693680
{
694681
positions[module.moduleNumber] = module.getPosition();
695-
if (invertOdometry)
696-
{
697-
positions[module.moduleNumber].distanceMeters *= -1;
698-
}
699682
}
700683
return positions;
701684
}
@@ -945,7 +928,7 @@ public void updateOdometry()
945928
SwerveDriveTelemetry.measuredChassisSpeeds[1] = measuredChassisSpeeds.vyMetersPerSecond;
946929
SwerveDriveTelemetry.measuredChassisSpeeds[0] = measuredChassisSpeeds.vxMetersPerSecond;
947930
SwerveDriveTelemetry.measuredChassisSpeeds[2] = Math.toDegrees(measuredChassisSpeeds.omegaRadiansPerSecond);
948-
SwerveDriveTelemetry.robotRotation = getYaw().getDegrees();
931+
SwerveDriveTelemetry.robotRotation = getOdometryHeading().getDegrees();
949932
}
950933

951934
if (SwerveDriveTelemetry.verbosity.ordinal() >= TelemetryVerbosity.LOW.ordinal())
@@ -961,7 +944,8 @@ public void updateOdometry()
961944
if (SwerveDriveTelemetry.verbosity == TelemetryVerbosity.HIGH)
962945
{
963946
module.updateTelemetry();
964-
SmartDashboard.putNumber("Adjusted IMU Yaw", getYaw().getDegrees());
947+
SmartDashboard.putNumber("Raw IMU Yaw", getYaw().getDegrees());
948+
SmartDashboard.putNumber("Adjusted IMU Yaw", getOdometryHeading().getDegrees());
965949
}
966950
if (SwerveDriveTelemetry.verbosity.ordinal() >= TelemetryVerbosity.HIGH.ordinal())
967951
{
@@ -1019,28 +1003,6 @@ public void setGyroOffset(Rotation3d offset)
10191003
}
10201004
}
10211005

1022-
/**
1023-
* Add a vision measurement to the {@link SwerveDrivePoseEstimator} and update the {@link SwerveIMU} gyro reading with
1024-
* the given timestamp of the vision measurement. <br /> <b>IT IS HIGHLY RECOMMENDED TO UPDATE YOUR GYROSCOPE OFFSET
1025-
* AFTER USING THIS FUNCTION!</b> <br /> To update your gyroscope readings directly use
1026-
* {@link SwerveDrive#setGyroOffset(Rotation3d)}.
1027-
*
1028-
* @param robotPose Robot {@link Pose2d} as measured by vision.
1029-
* @param timestamp Timestamp the measurement was taken as time since startup, should be taken from
1030-
* {@link Timer#getFPGATimestamp()} or similar sources.
1031-
*/
1032-
public void addVisionMeasurement(Pose2d robotPose, double timestamp)
1033-
{
1034-
odometryLock.lock();
1035-
swerveDrivePoseEstimator.addVisionMeasurement(robotPose, timestamp);
1036-
Pose2d newOdometry = new Pose2d(swerveDrivePoseEstimator.getEstimatedPosition().getTranslation(),
1037-
robotPose.getRotation());
1038-
odometryLock.unlock();
1039-
1040-
setGyroOffset(new Rotation3d(0, 0, robotPose.getRotation().getRadians()));
1041-
resetOdometry(newOdometry);
1042-
}
1043-
10441006
/**
10451007
* Add a vision measurement to the {@link SwerveDrivePoseEstimator} and update the {@link SwerveIMU} gyro reading with
10461008
* the given timestamp of the vision measurement.
@@ -1058,8 +1020,31 @@ public void addVisionMeasurement(Pose2d robotPose, double timestamp)
10581020
public void addVisionMeasurement(Pose2d robotPose, double timestamp,
10591021
Matrix<N3, N1> visionMeasurementStdDevs)
10601022
{
1061-
this.visionMeasurementStdDevs = visionMeasurementStdDevs;
1062-
addVisionMeasurement(robotPose, timestamp);
1023+
odometryLock.lock();
1024+
swerveDrivePoseEstimator.addVisionMeasurement(robotPose, timestamp, visionMeasurementStdDevs);
1025+
odometryLock.unlock();
1026+
}
1027+
1028+
/**
1029+
* Add a vision measurement to the {@link SwerveDrivePoseEstimator} and update the {@link SwerveIMU} gyro reading with
1030+
* the given timestamp of the vision measurement. <br /> <b>IT IS HIGHLY RECOMMENDED TO UPDATE YOUR GYROSCOPE OFFSET
1031+
* AFTER USING THIS FUNCTION!</b> <br /> To update your gyroscope readings directly use
1032+
* {@link SwerveDrive#setGyroOffset(Rotation3d)}.
1033+
*
1034+
* @param robotPose Robot {@link Pose2d} as measured by vision.
1035+
* @param timestamp Timestamp the measurement was taken as time since startup, should be taken from
1036+
* {@link Timer#getFPGATimestamp()} or similar sources.
1037+
*/
1038+
public void addVisionMeasurement(Pose2d robotPose, double timestamp)
1039+
{
1040+
odometryLock.lock();
1041+
swerveDrivePoseEstimator.addVisionMeasurement(robotPose, timestamp);
1042+
// Pose2d newOdometry = new Pose2d(swerveDrivePoseEstimator.getEstimatedPosition().getTranslation(),
1043+
// robotPose.getRotation());
1044+
odometryLock.unlock();
1045+
1046+
// setGyroOffset(new Rotation3d(0, 0, robotPose.getRotation().getRadians()));
1047+
// resetOdometry(newOdometry);
10631048
}
10641049

10651050

src/main/java/swervelib/imu/ADIS16448Swerve.java

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ public class ADIS16448Swerve extends SwerveIMU
1919
/**
2020
* Offset for the ADIS16448.
2121
*/
22-
private Rotation3d offset = new Rotation3d();
22+
private Rotation3d offset = new Rotation3d();
2323
/**
2424
* Inversion for the gyro
2525
*/
26-
private boolean invertedIMU = false;
26+
private boolean invertedIMU = false;
2727

2828
/**
2929
* Construct the ADIS16448 imu and reset default configurations. Publish the gyro to the SmartDashboard.
@@ -66,7 +66,7 @@ public void setOffset(Rotation3d offset)
6666

6767
/**
6868
* Set the gyro to invert its default direction
69-
*
69+
*
7070
* @param invertIMU invert gyro direction
7171
*/
7272
public void setInverted(boolean invertIMU)
@@ -81,14 +81,10 @@ public void setInverted(boolean invertIMU)
8181
*/
8282
public Rotation3d getRawRotation3d()
8383
{
84-
if(invertedIMU){
85-
return new Rotation3d(Math.toRadians(-imu.getGyroAngleX()),
86-
Math.toRadians(-imu.getGyroAngleY()),
87-
Math.toRadians(-imu.getGyroAngleZ())).unaryMinus();
88-
}
89-
return new Rotation3d(Math.toRadians(-imu.getGyroAngleX()),
90-
Math.toRadians(-imu.getGyroAngleY()),
91-
Math.toRadians(-imu.getGyroAngleZ()));
84+
Rotation3d reading = new Rotation3d(Math.toRadians(-imu.getGyroAngleX()),
85+
Math.toRadians(-imu.getGyroAngleY()),
86+
Math.toRadians(-imu.getGyroAngleZ()));
87+
return invertedIMU ? reading.unaryMinus() : reading;
9288
}
9389

9490
/**

src/main/java/swervelib/imu/ADIS16470Swerve.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ public class ADIS16470Swerve extends SwerveIMU
2020
/**
2121
* Offset for the ADIS16470.
2222
*/
23-
private Rotation3d offset = new Rotation3d();
23+
private Rotation3d offset = new Rotation3d();
2424
/**
2525
* Inversion for the gyro
2626
*/
27-
private boolean invertedIMU = false;
27+
private boolean invertedIMU = false;
2828

2929
/**
3030
* Construct the ADIS16470 imu and reset default configurations. Publish the gyro to the SmartDashboard.
@@ -68,7 +68,7 @@ public void setOffset(Rotation3d offset)
6868

6969
/**
7070
* Set the gyro to invert its default direction
71-
*
71+
*
7272
* @param invertIMU invert gyro direction
7373
*/
7474
public void setInverted(boolean invertIMU)
@@ -83,10 +83,8 @@ public void setInverted(boolean invertIMU)
8383
*/
8484
public Rotation3d getRawRotation3d()
8585
{
86-
if(invertedIMU){
87-
return new Rotation3d(0, 0, Math.toRadians(-imu.getAngle(IMUAxis.kYaw))).unaryMinus();
88-
}
89-
return new Rotation3d(0, 0, Math.toRadians(-imu.getAngle(IMUAxis.kYaw)));
86+
Rotation3d reading = new Rotation3d(0, 0, Math.toRadians(-imu.getAngle(IMUAxis.kYaw)));
87+
return invertedIMU ? reading.unaryMinus() : reading;
9088
}
9189

9290
/**

0 commit comments

Comments
 (0)