/*----------------------------------------------------------------------------*/ /* Copyright (c) 2019-2020 FIRST. All Rights Reserved. */ /* Open Source Software - may be modified and shared by FRC teams. The code */ /* must be accompanied by the FIRST BSD license file in the root directory of */ /* the project. */ /*----------------------------------------------------------------------------*/ #include #include #include "frc/geometry/Translation2d.h" #include "frc/kinematics/SwerveDriveKinematics.h" #include "gtest/gtest.h" using namespace frc; static constexpr double kEpsilon = 0.1; class SwerveDriveKinematicsTest : public ::testing::Test { protected: Translation2d m_fl{12_m, 12_m}; Translation2d m_fr{12_m, -12_m}; Translation2d m_bl{-12_m, 12_m}; Translation2d m_br{-12_m, -12_m}; SwerveDriveKinematics<4> m_kinematics{m_fl, m_fr, m_bl, m_br}; }; TEST_F(SwerveDriveKinematicsTest, StraightLineInverseKinematics) { ChassisSpeeds speeds{5.0_mps, 0.0_mps, 0.0_rad_per_s}; auto [fl, fr, bl, br] = m_kinematics.ToSwerveModuleStates(speeds); EXPECT_NEAR(fl.speed.to(), 5.0, kEpsilon); EXPECT_NEAR(fr.speed.to(), 5.0, kEpsilon); EXPECT_NEAR(bl.speed.to(), 5.0, kEpsilon); EXPECT_NEAR(br.speed.to(), 5.0, kEpsilon); EXPECT_NEAR(fl.angle.Radians().to(), 0.0, kEpsilon); EXPECT_NEAR(fr.angle.Radians().to(), 0.0, kEpsilon); EXPECT_NEAR(bl.angle.Radians().to(), 0.0, kEpsilon); EXPECT_NEAR(br.angle.Radians().to(), 0.0, kEpsilon); } TEST_F(SwerveDriveKinematicsTest, StraightLineForwardKinematics) { SwerveModuleState state{5.0_mps, Rotation2d()}; auto chassisSpeeds = m_kinematics.ToChassisSpeeds(state, state, state, state); EXPECT_NEAR(chassisSpeeds.vx.to(), 5.0, kEpsilon); EXPECT_NEAR(chassisSpeeds.vy.to(), 0.0, kEpsilon); EXPECT_NEAR(chassisSpeeds.omega.to(), 0.0, kEpsilon); } TEST_F(SwerveDriveKinematicsTest, StraightStrafeInverseKinematics) { ChassisSpeeds speeds{0_mps, 5_mps, 0_rad_per_s}; auto [fl, fr, bl, br] = m_kinematics.ToSwerveModuleStates(speeds); EXPECT_NEAR(fl.speed.to(), 5.0, kEpsilon); EXPECT_NEAR(fr.speed.to(), 5.0, kEpsilon); EXPECT_NEAR(bl.speed.to(), 5.0, kEpsilon); EXPECT_NEAR(br.speed.to(), 5.0, kEpsilon); EXPECT_NEAR(fl.angle.Degrees().to(), 90.0, kEpsilon); EXPECT_NEAR(fr.angle.Degrees().to(), 90.0, kEpsilon); EXPECT_NEAR(bl.angle.Degrees().to(), 90.0, kEpsilon); EXPECT_NEAR(br.angle.Degrees().to(), 90.0, kEpsilon); } TEST_F(SwerveDriveKinematicsTest, StraightStrafeForwardKinematics) { SwerveModuleState state{5_mps, Rotation2d(90_deg)}; auto chassisSpeeds = m_kinematics.ToChassisSpeeds(state, state, state, state); EXPECT_NEAR(chassisSpeeds.vx.to(), 0.0, kEpsilon); EXPECT_NEAR(chassisSpeeds.vy.to(), 5.0, kEpsilon); EXPECT_NEAR(chassisSpeeds.omega.to(), 0.0, kEpsilon); } TEST_F(SwerveDriveKinematicsTest, TurnInPlaceInverseKinematics) { ChassisSpeeds speeds{0_mps, 0_mps, units::radians_per_second_t(2 * wpi::math::pi)}; auto [fl, fr, bl, br] = m_kinematics.ToSwerveModuleStates(speeds); EXPECT_NEAR(fl.speed.to(), 106.63, kEpsilon); EXPECT_NEAR(fr.speed.to(), 106.63, kEpsilon); EXPECT_NEAR(bl.speed.to(), 106.63, kEpsilon); EXPECT_NEAR(br.speed.to(), 106.63, kEpsilon); EXPECT_NEAR(fl.angle.Degrees().to(), 135.0, kEpsilon); EXPECT_NEAR(fr.angle.Degrees().to(), 45.0, kEpsilon); EXPECT_NEAR(bl.angle.Degrees().to(), -135.0, kEpsilon); EXPECT_NEAR(br.angle.Degrees().to(), -45.0, kEpsilon); } TEST_F(SwerveDriveKinematicsTest, TurnInPlaceForwardKinematics) { SwerveModuleState fl{106.629_mps, Rotation2d(135_deg)}; SwerveModuleState fr{106.629_mps, Rotation2d(45_deg)}; SwerveModuleState bl{106.629_mps, Rotation2d(-135_deg)}; SwerveModuleState br{106.629_mps, Rotation2d(-45_deg)}; auto chassisSpeeds = m_kinematics.ToChassisSpeeds(fl, fr, bl, br); EXPECT_NEAR(chassisSpeeds.vx.to(), 0.0, kEpsilon); EXPECT_NEAR(chassisSpeeds.vy.to(), 0.0, kEpsilon); EXPECT_NEAR(chassisSpeeds.omega.to(), 2 * wpi::math::pi, kEpsilon); } TEST_F(SwerveDriveKinematicsTest, OffCenterCORRotationInverseKinematics) { ChassisSpeeds speeds{0_mps, 0_mps, units::radians_per_second_t(2 * wpi::math::pi)}; auto [fl, fr, bl, br] = m_kinematics.ToSwerveModuleStates(speeds, m_fl); EXPECT_NEAR(fl.speed.to(), 0.0, kEpsilon); EXPECT_NEAR(fr.speed.to(), 150.796, kEpsilon); EXPECT_NEAR(bl.speed.to(), 150.796, kEpsilon); EXPECT_NEAR(br.speed.to(), 213.258, kEpsilon); EXPECT_NEAR(fl.angle.Degrees().to(), 0.0, kEpsilon); EXPECT_NEAR(fr.angle.Degrees().to(), 0.0, kEpsilon); EXPECT_NEAR(bl.angle.Degrees().to(), -90.0, kEpsilon); EXPECT_NEAR(br.angle.Degrees().to(), -45.0, kEpsilon); } TEST_F(SwerveDriveKinematicsTest, OffCenterCORRotationForwardKinematics) { SwerveModuleState fl{0.0_mps, Rotation2d(0_deg)}; SwerveModuleState fr{150.796_mps, Rotation2d(0_deg)}; SwerveModuleState bl{150.796_mps, Rotation2d(-90_deg)}; SwerveModuleState br{213.258_mps, Rotation2d(-45_deg)}; auto chassisSpeeds = m_kinematics.ToChassisSpeeds(fl, fr, bl, br); EXPECT_NEAR(chassisSpeeds.vx.to(), 75.398, kEpsilon); EXPECT_NEAR(chassisSpeeds.vy.to(), -75.398, kEpsilon); EXPECT_NEAR(chassisSpeeds.omega.to(), 2 * wpi::math::pi, kEpsilon); } TEST_F(SwerveDriveKinematicsTest, OffCenterCORRotationAndTranslationInverseKinematics) { ChassisSpeeds speeds{0_mps, 3.0_mps, 1.5_rad_per_s}; auto [fl, fr, bl, br] = m_kinematics.ToSwerveModuleStates(speeds, Translation2d(24_m, 0_m)); EXPECT_NEAR(fl.speed.to(), 23.43, kEpsilon); EXPECT_NEAR(fr.speed.to(), 23.43, kEpsilon); EXPECT_NEAR(bl.speed.to(), 54.08, kEpsilon); EXPECT_NEAR(br.speed.to(), 54.08, kEpsilon); EXPECT_NEAR(fl.angle.Degrees().to(), -140.19, kEpsilon); EXPECT_NEAR(fr.angle.Degrees().to(), -39.81, kEpsilon); EXPECT_NEAR(bl.angle.Degrees().to(), -109.44, kEpsilon); EXPECT_NEAR(br.angle.Degrees().to(), -70.56, kEpsilon); } TEST_F(SwerveDriveKinematicsTest, OffCenterCORRotationAndTranslationForwardKinematics) { SwerveModuleState fl{23.43_mps, Rotation2d(-140.19_deg)}; SwerveModuleState fr{23.43_mps, Rotation2d(-39.81_deg)}; SwerveModuleState bl{54.08_mps, Rotation2d(-109.44_deg)}; SwerveModuleState br{54.08_mps, Rotation2d(-70.56_deg)}; auto chassisSpeeds = m_kinematics.ToChassisSpeeds(fl, fr, bl, br); EXPECT_NEAR(chassisSpeeds.vx.to(), 0.0, kEpsilon); EXPECT_NEAR(chassisSpeeds.vy.to(), -33.0, kEpsilon); EXPECT_NEAR(chassisSpeeds.omega.to(), 1.5, kEpsilon); } TEST_F(SwerveDriveKinematicsTest, NormalizeTest) { SwerveModuleState state1{5.0_mps, Rotation2d()}; SwerveModuleState state2{6.0_mps, Rotation2d()}; SwerveModuleState state3{4.0_mps, Rotation2d()}; SwerveModuleState state4{7.0_mps, Rotation2d()}; std::array arr{state1, state2, state3, state4}; SwerveDriveKinematics<4>::NormalizeWheelSpeeds(&arr, 5.5_mps); double kFactor = 5.5 / 7.0; EXPECT_NEAR(arr[0].speed.to(), 5.0 * kFactor, kEpsilon); EXPECT_NEAR(arr[1].speed.to(), 6.0 * kFactor, kEpsilon); EXPECT_NEAR(arr[2].speed.to(), 4.0 * kFactor, kEpsilon); EXPECT_NEAR(arr[3].speed.to(), 7.0 * kFactor, kEpsilon); }