mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
[wpimath] Fix C++ Odometry ResetRotation missing a negation (#8949)
The original implementation was `m_gyroOffset + (rotation - m_pose.Rotation())`, which means the first `RotateBy` should be using `-m_pose.Rotation()` (see `ResetPose()`). Java is already correct. This also adds new tests to catch this particular error.
This commit is contained in:
@@ -95,7 +95,7 @@ class WPILIB_DLLEXPORT Odometry {
|
|||||||
* @param rotation The rotation to reset to.
|
* @param rotation The rotation to reset to.
|
||||||
*/
|
*/
|
||||||
void ResetRotation(const Rotation2d& rotation) {
|
void ResetRotation(const Rotation2d& rotation) {
|
||||||
m_gyroOffset = m_gyroOffset.RotateBy(m_pose.Rotation()).RotateBy(rotation);
|
m_gyroOffset = m_gyroOffset.RotateBy(-m_pose.Rotation()).RotateBy(rotation);
|
||||||
m_pose = Pose2d{m_pose.Translation(), rotation};
|
m_pose = Pose2d{m_pose.Translation(), rotation};
|
||||||
m_previousAngle = rotation;
|
m_previousAngle = rotation;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,6 +101,52 @@ class SwerveDriveOdometryTest {
|
|||||||
() -> assertEquals(0.00, pose.getRotation().getRadians(), 0.1));
|
() -> assertEquals(0.00, pose.getRotation().getRadians(), 0.1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testResetTranslation() {
|
||||||
|
var modulePositions = new SwerveModulePosition[] {zero, zero, zero, zero};
|
||||||
|
var gyro = Rotation2d.fromDegrees(30.0);
|
||||||
|
|
||||||
|
m_odometry.resetPosition(
|
||||||
|
Rotation2d.kZero, modulePositions, new Pose2d(Translation2d.kZero, Rotation2d.kZero));
|
||||||
|
var initialPose = m_odometry.update(gyro, modulePositions);
|
||||||
|
|
||||||
|
assertAll(
|
||||||
|
() -> assertEquals(0.00, initialPose.getX(), 0.1),
|
||||||
|
() -> assertEquals(0.00, initialPose.getY(), 0.1),
|
||||||
|
() -> assertEquals(30.0, initialPose.getRotation().getDegrees(), 0.1));
|
||||||
|
|
||||||
|
m_odometry.resetTranslation(new Translation2d(0.5, 0));
|
||||||
|
var newPose = m_odometry.update(gyro, modulePositions);
|
||||||
|
|
||||||
|
assertAll(
|
||||||
|
() -> assertEquals(0.50, newPose.getX(), 0.1),
|
||||||
|
() -> assertEquals(0.00, newPose.getY(), 0.1),
|
||||||
|
() -> assertEquals(30.0, newPose.getRotation().getDegrees(), 0.1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testResetRotation() {
|
||||||
|
var modulePositions = new SwerveModulePosition[] {zero, zero, zero, zero};
|
||||||
|
var gyro = Rotation2d.fromDegrees(30.0);
|
||||||
|
|
||||||
|
m_odometry.resetPosition(
|
||||||
|
Rotation2d.kZero, modulePositions, new Pose2d(0.5, 0.0, Rotation2d.kZero));
|
||||||
|
var initialPose = m_odometry.update(gyro, modulePositions);
|
||||||
|
|
||||||
|
assertAll(
|
||||||
|
() -> assertEquals(0.50, initialPose.getX(), 0.1),
|
||||||
|
() -> assertEquals(0.00, initialPose.getY(), 0.1),
|
||||||
|
() -> assertEquals(30.0, initialPose.getRotation().getDegrees(), 0.1));
|
||||||
|
|
||||||
|
m_odometry.resetRotation(Rotation2d.kCCW_90deg);
|
||||||
|
var newPose = m_odometry.update(gyro, modulePositions);
|
||||||
|
|
||||||
|
assertAll(
|
||||||
|
() -> assertEquals(0.50, newPose.getX(), 0.1),
|
||||||
|
() -> assertEquals(0.00, newPose.getY(), 0.1),
|
||||||
|
() -> assertEquals(90.0, newPose.getRotation().getDegrees(), 0.1));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testAccuracyFacingTrajectory() {
|
void testAccuracyFacingTrajectory() {
|
||||||
var kinematics =
|
var kinematics =
|
||||||
|
|||||||
@@ -73,6 +73,44 @@ TEST_F(SwerveDriveOdometryTest, GyroAngleReset) {
|
|||||||
EXPECT_NEAR(0.0, pose.Rotation().Degrees().value(), kEpsilon);
|
EXPECT_NEAR(0.0, pose.Rotation().Degrees().value(), kEpsilon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(SwerveDriveOdometryTest, ResetTranslation) {
|
||||||
|
wpi::util::array<SwerveModulePosition, 4> wheelPositions{zero, zero, zero,
|
||||||
|
zero};
|
||||||
|
|
||||||
|
m_odometry.ResetPosition(0_deg, wheelPositions, Pose2d{});
|
||||||
|
auto pose = m_odometry.Update(30_deg, wheelPositions);
|
||||||
|
|
||||||
|
EXPECT_NEAR(0.0, pose.X().value(), kEpsilon);
|
||||||
|
EXPECT_NEAR(0.0, pose.Y().value(), kEpsilon);
|
||||||
|
EXPECT_NEAR(30.0, pose.Rotation().Degrees().value(), kEpsilon);
|
||||||
|
|
||||||
|
m_odometry.ResetTranslation({0.5_m, 0_m});
|
||||||
|
pose = m_odometry.Update(30_deg, wheelPositions);
|
||||||
|
|
||||||
|
EXPECT_NEAR(0.5, pose.X().value(), kEpsilon);
|
||||||
|
EXPECT_NEAR(0.0, pose.Y().value(), kEpsilon);
|
||||||
|
EXPECT_NEAR(30.0, pose.Rotation().Degrees().value(), kEpsilon);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(SwerveDriveOdometryTest, ResetRotation) {
|
||||||
|
wpi::util::array<SwerveModulePosition, 4> wheelPositions{zero, zero, zero,
|
||||||
|
zero};
|
||||||
|
|
||||||
|
m_odometry.ResetPosition(0_deg, wheelPositions, Pose2d{0.5_m, 0_m, 0_rad});
|
||||||
|
auto pose = m_odometry.Update(30_deg, wheelPositions);
|
||||||
|
|
||||||
|
EXPECT_NEAR(0.5, pose.X().value(), kEpsilon);
|
||||||
|
EXPECT_NEAR(0.0, pose.Y().value(), kEpsilon);
|
||||||
|
EXPECT_NEAR(30.0, pose.Rotation().Degrees().value(), kEpsilon);
|
||||||
|
|
||||||
|
m_odometry.ResetRotation(90_deg);
|
||||||
|
pose = m_odometry.Update(30_deg, wheelPositions);
|
||||||
|
|
||||||
|
EXPECT_NEAR(0.5, pose.X().value(), kEpsilon);
|
||||||
|
EXPECT_NEAR(0.0, pose.Y().value(), kEpsilon);
|
||||||
|
EXPECT_NEAR(90.0, pose.Rotation().Degrees().value(), kEpsilon);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(SwerveDriveOdometryTest, AccuracyFacingTrajectory) {
|
TEST_F(SwerveDriveOdometryTest, AccuracyFacingTrajectory) {
|
||||||
SwerveDriveKinematics<4> kinematics{
|
SwerveDriveKinematics<4> kinematics{
|
||||||
Translation2d{1_m, 1_m}, Translation2d{1_m, -1_m},
|
Translation2d{1_m, 1_m}, Translation2d{1_m, -1_m},
|
||||||
|
|||||||
Reference in New Issue
Block a user