diff --git a/wpilibc/src/main/native/cpp/drive/DifferentialDrive.cpp b/wpilibc/src/main/native/cpp/drive/DifferentialDrive.cpp index b54b607720..eed9495dc3 100644 --- a/wpilibc/src/main/native/cpp/drive/DifferentialDrive.cpp +++ b/wpilibc/src/main/native/cpp/drive/DifferentialDrive.cpp @@ -112,9 +112,10 @@ DifferentialDrive::WheelSpeeds DifferentialDrive::ArcadeDriveIK( double maxInput = std::copysign(std::max(std::abs(xSpeed), std::abs(zRotation)), xSpeed); - if (xSpeed >= 0.0) { + // Sign is used because `xSpeed >= 0.0` succeeds for -0.0 + if (!std::signbit(xSpeed)) { // First quadrant, else second quadrant - if (zRotation >= 0.0) { + if (!std::signbit(zRotation)) { leftSpeed = maxInput; rightSpeed = xSpeed - zRotation; } else { @@ -123,7 +124,7 @@ DifferentialDrive::WheelSpeeds DifferentialDrive::ArcadeDriveIK( } } else { // Third quadrant, else fourth quadrant - if (zRotation >= 0.0) { + if (!std::signbit(zRotation)) { leftSpeed = xSpeed + zRotation; rightSpeed = maxInput; } else { diff --git a/wpilibc/src/test/native/cpp/drive/DifferentialDriveTest.cpp b/wpilibc/src/test/native/cpp/drive/DifferentialDriveTest.cpp index 1d13a77f8f..b930346939 100644 --- a/wpilibc/src/test/native/cpp/drive/DifferentialDriveTest.cpp +++ b/wpilibc/src/test/native/cpp/drive/DifferentialDriveTest.cpp @@ -6,6 +6,238 @@ #include "frc/drive/DifferentialDrive.h" #include "gtest/gtest.h" +TEST(DifferentialDriveTest, ArcadeDriveIK) { + // Forward + auto speeds = frc::DifferentialDrive::ArcadeDriveIK(1.0, 0.0, false); + EXPECT_DOUBLE_EQ(1.0, speeds.left); + EXPECT_DOUBLE_EQ(1.0, speeds.right); + + // Forward left turn + speeds = frc::DifferentialDrive::ArcadeDriveIK(0.5, -0.5, false); + EXPECT_DOUBLE_EQ(0.0, speeds.left); + EXPECT_DOUBLE_EQ(0.5, speeds.right); + + // Forward right turn + speeds = frc::DifferentialDrive::ArcadeDriveIK(0.5, 0.5, false); + EXPECT_DOUBLE_EQ(0.5, speeds.left); + EXPECT_DOUBLE_EQ(0.0, speeds.right); + + // Backward + speeds = frc::DifferentialDrive::ArcadeDriveIK(-1.0, 0.0, false); + EXPECT_DOUBLE_EQ(-1.0, speeds.left); + EXPECT_DOUBLE_EQ(-1.0, speeds.right); + + // Backward left turn + speeds = frc::DifferentialDrive::ArcadeDriveIK(-0.5, -0.5, false); + EXPECT_DOUBLE_EQ(-0.5, speeds.left); + EXPECT_DOUBLE_EQ(0.0, speeds.right); + + // Backward right turn + speeds = frc::DifferentialDrive::ArcadeDriveIK(-0.5, 0.5, false); + EXPECT_DOUBLE_EQ(0.0, speeds.left); + EXPECT_DOUBLE_EQ(-0.5, speeds.right); + + // Left turn (xSpeed with negative sign) + speeds = frc::DifferentialDrive::ArcadeDriveIK(-0.0, -1.0, false); + EXPECT_DOUBLE_EQ(-1.0, speeds.left); + EXPECT_DOUBLE_EQ(1.0, speeds.right); + + // Left turn (xSpeed with positive sign) + speeds = frc::DifferentialDrive::ArcadeDriveIK(0.0, -1.0, false); + EXPECT_DOUBLE_EQ(-1.0, speeds.left); + EXPECT_DOUBLE_EQ(1.0, speeds.right); + + // Right turn (xSpeed with negative sign) + speeds = frc::DifferentialDrive::ArcadeDriveIK(-0.0, 1.0, false); + EXPECT_DOUBLE_EQ(1.0, speeds.left); + EXPECT_DOUBLE_EQ(-1.0, speeds.right); + + // Right turn (xSpeed with positive sign) + speeds = frc::DifferentialDrive::ArcadeDriveIK(0.0, 1.0, false); + EXPECT_DOUBLE_EQ(1.0, speeds.left); + EXPECT_DOUBLE_EQ(-1.0, speeds.right); +} + +TEST(DifferentialDriveTest, ArcadeDriveIKSquared) { + // Forward + auto speeds = frc::DifferentialDrive::ArcadeDriveIK(1.0, 0.0, true); + EXPECT_DOUBLE_EQ(1.0, speeds.left); + EXPECT_DOUBLE_EQ(1.0, speeds.right); + + // Forward left turn + speeds = frc::DifferentialDrive::ArcadeDriveIK(0.5, -0.5, true); + EXPECT_DOUBLE_EQ(0.0, speeds.left); + EXPECT_DOUBLE_EQ(0.25, speeds.right); + + // Forward right turn + speeds = frc::DifferentialDrive::ArcadeDriveIK(0.5, 0.5, true); + EXPECT_DOUBLE_EQ(0.25, speeds.left); + EXPECT_DOUBLE_EQ(0.0, speeds.right); + + // Backward + speeds = frc::DifferentialDrive::ArcadeDriveIK(-1.0, 0.0, true); + EXPECT_DOUBLE_EQ(-1.0, speeds.left); + EXPECT_DOUBLE_EQ(-1.0, speeds.right); + + // Backward left turn + speeds = frc::DifferentialDrive::ArcadeDriveIK(-0.5, -0.5, true); + EXPECT_DOUBLE_EQ(-0.25, speeds.left); + EXPECT_DOUBLE_EQ(0.0, speeds.right); + + // Backward right turn + speeds = frc::DifferentialDrive::ArcadeDriveIK(-0.5, 0.5, true); + EXPECT_DOUBLE_EQ(0.0, speeds.left); + EXPECT_DOUBLE_EQ(-0.25, speeds.right); + + // Left turn (xSpeed with negative sign) + speeds = frc::DifferentialDrive::ArcadeDriveIK(-0.0, -1.0, false); + EXPECT_DOUBLE_EQ(-1.0, speeds.left); + EXPECT_DOUBLE_EQ(1.0, speeds.right); + + // Left turn (xSpeed with positive sign) + speeds = frc::DifferentialDrive::ArcadeDriveIK(0.0, -1.0, false); + EXPECT_DOUBLE_EQ(-1.0, speeds.left); + EXPECT_DOUBLE_EQ(1.0, speeds.right); + + // Right turn (xSpeed with negative sign) + speeds = frc::DifferentialDrive::ArcadeDriveIK(-0.0, 1.0, false); + EXPECT_DOUBLE_EQ(1.0, speeds.left); + EXPECT_DOUBLE_EQ(-1.0, speeds.right); + + // Right turn (xSpeed with positive sign) + speeds = frc::DifferentialDrive::ArcadeDriveIK(0.0, 1.0, false); + EXPECT_DOUBLE_EQ(1.0, speeds.left); + EXPECT_DOUBLE_EQ(-1.0, speeds.right); +} + +TEST(DifferentialDriveTest, CurvatureDriveIK) { + // Forward + auto speeds = frc::DifferentialDrive::CurvatureDriveIK(1.0, 0.0, false); + EXPECT_DOUBLE_EQ(1.0, speeds.left); + EXPECT_DOUBLE_EQ(1.0, speeds.right); + + // Forward left turn + speeds = frc::DifferentialDrive::CurvatureDriveIK(0.5, -0.5, false); + EXPECT_DOUBLE_EQ(0.25, speeds.left); + EXPECT_DOUBLE_EQ(0.75, speeds.right); + + // Forward right turn + speeds = frc::DifferentialDrive::CurvatureDriveIK(0.5, 0.5, false); + EXPECT_DOUBLE_EQ(0.75, speeds.left); + EXPECT_DOUBLE_EQ(0.25, speeds.right); + + // Backward + speeds = frc::DifferentialDrive::CurvatureDriveIK(-1.0, 0.0, false); + EXPECT_DOUBLE_EQ(-1.0, speeds.left); + EXPECT_DOUBLE_EQ(-1.0, speeds.right); + + // Backward left turn + speeds = frc::DifferentialDrive::CurvatureDriveIK(-0.5, -0.5, false); + EXPECT_DOUBLE_EQ(-0.75, speeds.left); + EXPECT_DOUBLE_EQ(-0.25, speeds.right); + + // Backward right turn + speeds = frc::DifferentialDrive::CurvatureDriveIK(-0.5, 0.5, false); + EXPECT_DOUBLE_EQ(-0.25, speeds.left); + EXPECT_DOUBLE_EQ(-0.75, speeds.right); +} + +TEST(DifferentialDriveTest, CurvatureDriveIKTurnInPlace) { + // Forward + auto speeds = frc::DifferentialDrive::CurvatureDriveIK(1.0, 0.0, true); + EXPECT_DOUBLE_EQ(1.0, speeds.left); + EXPECT_DOUBLE_EQ(1.0, speeds.right); + + // Forward left turn + speeds = frc::DifferentialDrive::CurvatureDriveIK(0.5, -0.5, true); + EXPECT_DOUBLE_EQ(0.0, speeds.left); + EXPECT_DOUBLE_EQ(1.0, speeds.right); + + // Forward right turn + speeds = frc::DifferentialDrive::CurvatureDriveIK(0.5, 0.5, true); + EXPECT_DOUBLE_EQ(1.0, speeds.left); + EXPECT_DOUBLE_EQ(0.0, speeds.right); + + // Backward + speeds = frc::DifferentialDrive::CurvatureDriveIK(-1.0, 0.0, true); + EXPECT_DOUBLE_EQ(-1.0, speeds.left); + EXPECT_DOUBLE_EQ(-1.0, speeds.right); + + // Backward left turn + speeds = frc::DifferentialDrive::CurvatureDriveIK(-0.5, -0.5, true); + EXPECT_DOUBLE_EQ(-1.0, speeds.left); + EXPECT_DOUBLE_EQ(0.0, speeds.right); + + // Backward right turn + speeds = frc::DifferentialDrive::CurvatureDriveIK(-0.5, 0.5, true); + EXPECT_DOUBLE_EQ(0.0, speeds.left); + EXPECT_DOUBLE_EQ(-1.0, speeds.right); +} + +TEST(DifferentialDriveTest, TankDriveIK) { + // Forward + auto speeds = frc::DifferentialDrive::TankDriveIK(1.0, 1.0, false); + EXPECT_DOUBLE_EQ(1.0, speeds.left); + EXPECT_DOUBLE_EQ(1.0, speeds.right); + + // Forward left turn + speeds = frc::DifferentialDrive::TankDriveIK(0.5, 1.0, false); + EXPECT_DOUBLE_EQ(0.5, speeds.left); + EXPECT_DOUBLE_EQ(1.0, speeds.right); + + // Forward right turn + speeds = frc::DifferentialDrive::TankDriveIK(1.0, 0.5, false); + EXPECT_DOUBLE_EQ(1.0, speeds.left); + EXPECT_DOUBLE_EQ(0.5, speeds.right); + + // Backward + speeds = frc::DifferentialDrive::TankDriveIK(-1.0, -1.0, false); + EXPECT_DOUBLE_EQ(-1.0, speeds.left); + EXPECT_DOUBLE_EQ(-1.0, speeds.right); + + // Backward left turn + speeds = frc::DifferentialDrive::TankDriveIK(-0.5, -1.0, false); + EXPECT_DOUBLE_EQ(-0.5, speeds.left); + EXPECT_DOUBLE_EQ(-1.0, speeds.right); + + // Backward right turn + speeds = frc::DifferentialDrive::TankDriveIK(-0.5, 1.0, false); + EXPECT_DOUBLE_EQ(-0.5, speeds.left); + EXPECT_DOUBLE_EQ(1.0, speeds.right); +} + +TEST(DifferentialDriveTest, TankDriveIKSquared) { + // Forward + auto speeds = frc::DifferentialDrive::TankDriveIK(1.0, 1.0, true); + EXPECT_DOUBLE_EQ(1.0, speeds.left); + EXPECT_DOUBLE_EQ(1.0, speeds.right); + + // Forward left turn + speeds = frc::DifferentialDrive::TankDriveIK(0.5, 1.0, true); + EXPECT_DOUBLE_EQ(0.25, speeds.left); + EXPECT_DOUBLE_EQ(1.0, speeds.right); + + // Forward right turn + speeds = frc::DifferentialDrive::TankDriveIK(1.0, 0.5, true); + EXPECT_DOUBLE_EQ(1.0, speeds.left); + EXPECT_DOUBLE_EQ(0.25, speeds.right); + + // Backward + speeds = frc::DifferentialDrive::TankDriveIK(-1.0, -1.0, true); + EXPECT_DOUBLE_EQ(-1.0, speeds.left); + EXPECT_DOUBLE_EQ(-1.0, speeds.right); + + // Backward left turn + speeds = frc::DifferentialDrive::TankDriveIK(-0.5, -1.0, true); + EXPECT_DOUBLE_EQ(-0.25, speeds.left); + EXPECT_DOUBLE_EQ(-1.0, speeds.right); + + // Backward right turn + speeds = frc::DifferentialDrive::TankDriveIK(-1.0, -0.5, true); + EXPECT_DOUBLE_EQ(-1.0, speeds.left); + EXPECT_DOUBLE_EQ(-0.25, speeds.right); +} + TEST(DifferentialDriveTest, ArcadeDrive) { frc::MockMotorController left; frc::MockMotorController right; diff --git a/wpilibc/src/test/native/cpp/drive/KilloughDriveTest.cpp b/wpilibc/src/test/native/cpp/drive/KilloughDriveTest.cpp index 510b377c55..c23c7b0c7d 100644 --- a/wpilibc/src/test/native/cpp/drive/KilloughDriveTest.cpp +++ b/wpilibc/src/test/native/cpp/drive/KilloughDriveTest.cpp @@ -8,6 +8,80 @@ #include "frc/drive/KilloughDrive.h" #include "gtest/gtest.h" +TEST(KilloughDriveTest, CartesianIK) { + frc::MockMotorController left; + frc::MockMotorController right; + frc::MockMotorController back; + frc::KilloughDrive drive{left, right, back}; + + // Forward + auto speeds = drive.DriveCartesianIK(1.0, 0.0, 0.0); + EXPECT_DOUBLE_EQ(0.5, speeds.left); + EXPECT_DOUBLE_EQ(-0.5, speeds.right); + EXPECT_NEAR(0.0, speeds.back, 1e-9); + + // Left + speeds = drive.DriveCartesianIK(0.0, -1.0, 0.0); + EXPECT_DOUBLE_EQ(-std::sqrt(3) / 2, speeds.left); + EXPECT_DOUBLE_EQ(-std::sqrt(3) / 2, speeds.right); + EXPECT_DOUBLE_EQ(1.0, speeds.back); + + // Right + speeds = drive.DriveCartesianIK(0.0, 1.0, 0.0); + EXPECT_DOUBLE_EQ(std::sqrt(3) / 2, speeds.left); + EXPECT_DOUBLE_EQ(std::sqrt(3) / 2, speeds.right); + EXPECT_DOUBLE_EQ(-1.0, speeds.back); + + // Rotate CCW + speeds = drive.DriveCartesianIK(0.0, 0.0, -1.0); + EXPECT_DOUBLE_EQ(-1.0, speeds.left); + EXPECT_DOUBLE_EQ(-1.0, speeds.right); + EXPECT_DOUBLE_EQ(-1.0, speeds.back); + + // Rotate CW + speeds = drive.DriveCartesianIK(0.0, 0.0, 1.0); + EXPECT_DOUBLE_EQ(1.0, speeds.left); + EXPECT_DOUBLE_EQ(1.0, speeds.right); + EXPECT_DOUBLE_EQ(1.0, speeds.back); +} + +TEST(KilloughDriveTest, CartesianIKGyro90CW) { + frc::MockMotorController left; + frc::MockMotorController right; + frc::MockMotorController back; + frc::KilloughDrive drive{left, right, back}; + + // Forward in global frame; left in robot frame + auto speeds = drive.DriveCartesianIK(1.0, 0.0, 0.0, 90.0); + EXPECT_DOUBLE_EQ(-std::sqrt(3) / 2, speeds.left); + EXPECT_DOUBLE_EQ(-std::sqrt(3) / 2, speeds.right); + EXPECT_DOUBLE_EQ(1.0, speeds.back); + + // Left in global frame; backward in robot frame + speeds = drive.DriveCartesianIK(0.0, -1.0, 0.0, 90.0); + EXPECT_DOUBLE_EQ(-0.5, speeds.left); + EXPECT_NEAR(0.5, speeds.right, 1e-9); + EXPECT_NEAR(0.0, speeds.back, 1e-9); + + // Right in global frame; forward in robot frame + speeds = drive.DriveCartesianIK(0.0, 1.0, 0.0, 90.0); + EXPECT_DOUBLE_EQ(0.5, speeds.left); + EXPECT_NEAR(-0.5, speeds.right, 1e-9); + EXPECT_NEAR(0.0, speeds.back, 1e-9); + + // Rotate CCW + speeds = drive.DriveCartesianIK(0.0, 0.0, -1.0, 90.0); + EXPECT_DOUBLE_EQ(-1.0, speeds.left); + EXPECT_DOUBLE_EQ(-1.0, speeds.right); + EXPECT_DOUBLE_EQ(-1.0, speeds.back); + + // Rotate CW + speeds = drive.DriveCartesianIK(0.0, 0.0, 1.0, 90.0); + EXPECT_DOUBLE_EQ(1.0, speeds.left); + EXPECT_DOUBLE_EQ(1.0, speeds.right); + EXPECT_DOUBLE_EQ(1.0, speeds.back); +} + TEST(KilloughDriveTest, Cartesian) { frc::MockMotorController left; frc::MockMotorController right; diff --git a/wpilibc/src/test/native/cpp/drive/MecanumDriveTest.cpp b/wpilibc/src/test/native/cpp/drive/MecanumDriveTest.cpp index fe0a73bd4e..2990848129 100644 --- a/wpilibc/src/test/native/cpp/drive/MecanumDriveTest.cpp +++ b/wpilibc/src/test/native/cpp/drive/MecanumDriveTest.cpp @@ -6,12 +6,86 @@ #include "frc/drive/MecanumDrive.h" #include "gtest/gtest.h" +TEST(MecanumDriveTest, CartesianIK) { + // Forward + auto speeds = frc::MecanumDrive::DriveCartesianIK(1.0, 0.0, 0.0); + EXPECT_DOUBLE_EQ(1.0, speeds.frontLeft); + EXPECT_DOUBLE_EQ(1.0, speeds.frontRight); + EXPECT_DOUBLE_EQ(1.0, speeds.rearLeft); + EXPECT_DOUBLE_EQ(1.0, speeds.rearRight); + + // Left + speeds = frc::MecanumDrive::DriveCartesianIK(0.0, -1.0, 0.0); + EXPECT_DOUBLE_EQ(-1.0, speeds.frontLeft); + EXPECT_DOUBLE_EQ(1.0, speeds.frontRight); + EXPECT_DOUBLE_EQ(1.0, speeds.rearLeft); + EXPECT_DOUBLE_EQ(-1.0, speeds.rearRight); + + // Right + speeds = frc::MecanumDrive::DriveCartesianIK(0.0, 1.0, 0.0); + EXPECT_DOUBLE_EQ(1.0, speeds.frontLeft); + EXPECT_DOUBLE_EQ(-1.0, speeds.frontRight); + EXPECT_DOUBLE_EQ(-1.0, speeds.rearLeft); + EXPECT_DOUBLE_EQ(1.0, speeds.rearRight); + + // Rotate CCW + speeds = frc::MecanumDrive::DriveCartesianIK(0.0, 0.0, -1.0); + EXPECT_DOUBLE_EQ(-1.0, speeds.frontLeft); + EXPECT_DOUBLE_EQ(1.0, speeds.frontRight); + EXPECT_DOUBLE_EQ(-1.0, speeds.rearLeft); + EXPECT_DOUBLE_EQ(1.0, speeds.rearRight); + + // Rotate CW + speeds = frc::MecanumDrive::DriveCartesianIK(0.0, 0.0, 1.0); + EXPECT_DOUBLE_EQ(1.0, speeds.frontLeft); + EXPECT_DOUBLE_EQ(-1.0, speeds.frontRight); + EXPECT_DOUBLE_EQ(1.0, speeds.rearLeft); + EXPECT_DOUBLE_EQ(-1.0, speeds.rearRight); +} + +TEST(MecanumDriveTest, CartesianIKGyro90CW) { + // Forward in global frame; left in robot frame + auto speeds = frc::MecanumDrive::DriveCartesianIK(1.0, 0.0, 0.0, 90.0); + EXPECT_DOUBLE_EQ(-1.0, speeds.frontLeft); + EXPECT_DOUBLE_EQ(1.0, speeds.frontRight); + EXPECT_DOUBLE_EQ(1.0, speeds.rearLeft); + EXPECT_DOUBLE_EQ(-1.0, speeds.rearRight); + + // Left in global frame; backward in robot frame + speeds = frc::MecanumDrive::DriveCartesianIK(0.0, -1.0, 0.0, 90.0); + EXPECT_DOUBLE_EQ(-1.0, speeds.frontLeft); + EXPECT_DOUBLE_EQ(-1.0, speeds.frontRight); + EXPECT_DOUBLE_EQ(-1.0, speeds.rearLeft); + EXPECT_DOUBLE_EQ(-1.0, speeds.rearRight); + + // Right in global frame; forward in robot frame + speeds = frc::MecanumDrive::DriveCartesianIK(0.0, 1.0, 0.0, 90.0); + EXPECT_DOUBLE_EQ(1.0, speeds.frontLeft); + EXPECT_DOUBLE_EQ(1.0, speeds.frontRight); + EXPECT_DOUBLE_EQ(1.0, speeds.rearLeft); + EXPECT_DOUBLE_EQ(1.0, speeds.rearRight); + + // Rotate CCW + speeds = frc::MecanumDrive::DriveCartesianIK(0.0, 0.0, -1.0, 90.0); + EXPECT_DOUBLE_EQ(-1.0, speeds.frontLeft); + EXPECT_DOUBLE_EQ(1.0, speeds.frontRight); + EXPECT_DOUBLE_EQ(-1.0, speeds.rearLeft); + EXPECT_DOUBLE_EQ(1.0, speeds.rearRight); + + // Rotate CW + speeds = frc::MecanumDrive::DriveCartesianIK(0.0, 0.0, 1.0, 90.0); + EXPECT_DOUBLE_EQ(1.0, speeds.frontLeft); + EXPECT_DOUBLE_EQ(-1.0, speeds.frontRight); + EXPECT_DOUBLE_EQ(1.0, speeds.rearLeft); + EXPECT_DOUBLE_EQ(-1.0, speeds.rearRight); +} + TEST(MecanumDriveTest, Cartesian) { frc::MockMotorController fl; - frc::MockMotorController fr; frc::MockMotorController rl; + frc::MockMotorController fr; frc::MockMotorController rr; - frc::MecanumDrive drive{fl, fr, rl, rr}; + frc::MecanumDrive drive{fl, rl, fr, rr}; drive.SetDeadband(0.0); // Forward @@ -38,15 +112,15 @@ TEST(MecanumDriveTest, Cartesian) { // Rotate CCW drive.DriveCartesian(0.0, 0.0, -1.0); EXPECT_DOUBLE_EQ(-1.0, fl.Get()); - EXPECT_DOUBLE_EQ(-1.0, fr.Get()); - EXPECT_DOUBLE_EQ(1.0, rl.Get()); + EXPECT_DOUBLE_EQ(1.0, fr.Get()); + EXPECT_DOUBLE_EQ(-1.0, rl.Get()); EXPECT_DOUBLE_EQ(1.0, rr.Get()); // Rotate CW drive.DriveCartesian(0.0, 0.0, 1.0); EXPECT_DOUBLE_EQ(1.0, fl.Get()); - EXPECT_DOUBLE_EQ(1.0, fr.Get()); - EXPECT_DOUBLE_EQ(-1.0, rl.Get()); + EXPECT_DOUBLE_EQ(-1.0, fr.Get()); + EXPECT_DOUBLE_EQ(1.0, rl.Get()); EXPECT_DOUBLE_EQ(-1.0, rr.Get()); } @@ -55,7 +129,7 @@ TEST(MecanumDriveTest, CartesianGyro90CW) { frc::MockMotorController fr; frc::MockMotorController rl; frc::MockMotorController rr; - frc::MecanumDrive drive{fl, fr, rl, rr}; + frc::MecanumDrive drive{fl, rl, fr, rr}; drive.SetDeadband(0.0); // Forward in global frame; left in robot frame @@ -82,15 +156,15 @@ TEST(MecanumDriveTest, CartesianGyro90CW) { // Rotate CCW drive.DriveCartesian(0.0, 0.0, -1.0, 90.0); EXPECT_DOUBLE_EQ(-1.0, fl.Get()); - EXPECT_DOUBLE_EQ(-1.0, fr.Get()); - EXPECT_DOUBLE_EQ(1.0, rl.Get()); + EXPECT_DOUBLE_EQ(1.0, fr.Get()); + EXPECT_DOUBLE_EQ(-1.0, rl.Get()); EXPECT_DOUBLE_EQ(1.0, rr.Get()); // Rotate CW drive.DriveCartesian(0.0, 0.0, 1.0, 90.0); EXPECT_DOUBLE_EQ(1.0, fl.Get()); - EXPECT_DOUBLE_EQ(1.0, fr.Get()); - EXPECT_DOUBLE_EQ(-1.0, rl.Get()); + EXPECT_DOUBLE_EQ(-1.0, fr.Get()); + EXPECT_DOUBLE_EQ(1.0, rl.Get()); EXPECT_DOUBLE_EQ(-1.0, rr.Get()); } @@ -99,7 +173,7 @@ TEST(MecanumDriveTest, Polar) { frc::MockMotorController fr; frc::MockMotorController rl; frc::MockMotorController rr; - frc::MecanumDrive drive{fl, fr, rl, rr}; + frc::MecanumDrive drive{fl, rl, fr, rr}; drive.SetDeadband(0.0); // Forward @@ -126,14 +200,14 @@ TEST(MecanumDriveTest, Polar) { // Rotate CCW drive.DrivePolar(0.0, 0.0, -1.0); EXPECT_DOUBLE_EQ(-1.0, fl.Get()); - EXPECT_DOUBLE_EQ(-1.0, fr.Get()); - EXPECT_DOUBLE_EQ(1.0, rl.Get()); + EXPECT_DOUBLE_EQ(1.0, fr.Get()); + EXPECT_DOUBLE_EQ(-1.0, rl.Get()); EXPECT_DOUBLE_EQ(1.0, rr.Get()); // Rotate CW drive.DrivePolar(0.0, 0.0, 1.0); EXPECT_DOUBLE_EQ(1.0, fl.Get()); - EXPECT_DOUBLE_EQ(1.0, fr.Get()); - EXPECT_DOUBLE_EQ(-1.0, rl.Get()); + EXPECT_DOUBLE_EQ(-1.0, fr.Get()); + EXPECT_DOUBLE_EQ(1.0, rl.Get()); EXPECT_DOUBLE_EQ(-1.0, rr.Get()); } diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/DifferentialDrive.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/DifferentialDrive.java index 610be8f154..6b2d1eecb1 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/DifferentialDrive.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/DifferentialDrive.java @@ -280,9 +280,9 @@ public class DifferentialDrive extends RobotDriveBase implements Sendable, AutoC double maxInput = Math.copySign(Math.max(Math.abs(xSpeed), Math.abs(zRotation)), xSpeed); - if (xSpeed >= 0.0) { + if (Double.compare(xSpeed, 0.0) >= 0) { // First quadrant, else second quadrant - if (zRotation >= 0.0) { + if (Double.compare(zRotation, 0.0) >= 0) { leftSpeed = maxInput; rightSpeed = xSpeed - zRotation; } else { @@ -291,7 +291,7 @@ public class DifferentialDrive extends RobotDriveBase implements Sendable, AutoC } } else { // Third quadrant, else fourth quadrant - if (zRotation >= 0.0) { + if (Double.compare(zRotation, 0.0) >= 0) { leftSpeed = xSpeed + zRotation; rightSpeed = maxInput; } else { diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/KilloughDrive.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/KilloughDrive.java index 157b05e3db..9915c87da6 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/KilloughDrive.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/KilloughDrive.java @@ -233,6 +233,23 @@ public class KilloughDrive extends RobotDriveBase implements Sendable, AutoClose 0.0); } + /** + * Cartesian inverse kinematics for Killough platform. + * + *
Angles are measured clockwise from the positive X axis. The robot's speed is independent + * from its angle or rotation rate. + * + * @param ySpeed The robot's speed along the Y axis [-1.0..1.0]. Right is positive. + * @param xSpeed The robot's speed along the X axis [-1.0..1.0]. Forward is positive. + * @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is + * positive. + * @return Wheel speeds [-1.0..1.0]. + */ + @SuppressWarnings("ParameterName") + public WheelSpeeds driveCartesianIK(double ySpeed, double xSpeed, double zRotation) { + return driveCartesianIK(ySpeed, xSpeed, zRotation, 0.0); + } + /** * Cartesian inverse kinematics for Killough platform. * diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/MecanumDrive.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/MecanumDrive.java index aa2577f874..d22593f0a8 100644 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/MecanumDrive.java +++ b/wpilibj/src/main/java/edu/wpi/first/wpilibj/drive/MecanumDrive.java @@ -209,6 +209,23 @@ public class MecanumDrive extends RobotDriveBase implements Sendable, AutoClosea 0.0); } + /** + * Cartesian inverse kinematics for Mecanum platform. + * + *
Angles are measured clockwise from the positive X axis. The robot's speed is independent + * from its angle or rotation rate. + * + * @param ySpeed The robot's speed along the Y axis [-1.0..1.0]. Forward is positive. + * @param xSpeed The robot's speed along the X axis [-1.0..1.0]. Right is positive. + * @param zRotation The robot's rotation rate around the Z axis [-1.0..1.0]. Clockwise is + * positive. + * @return Wheel speeds [-1.0..1.0]. + */ + @SuppressWarnings("ParameterName") + public static WheelSpeeds driveCartesianIK(double ySpeed, double xSpeed, double zRotation) { + return driveCartesianIK(ySpeed, xSpeed, zRotation, 0.0); + } + /** * Cartesian inverse kinematics for Mecanum platform. * diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/drive/DifferentialDriveTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/drive/DifferentialDriveTest.java index e7f2e3178b..afeac0b93b 100644 --- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/drive/DifferentialDriveTest.java +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/drive/DifferentialDriveTest.java @@ -10,6 +10,244 @@ import edu.wpi.first.wpilibj.motorcontrol.MockMotorController; import org.junit.jupiter.api.Test; class DifferentialDriveTest { + @Test + void testArcadeDriveIK() { + // Forward + var speeds = DifferentialDrive.arcadeDriveIK(1.0, 0.0, false); + assertEquals(1.0, speeds.left, 1e-9); + assertEquals(1.0, speeds.right, 1e-9); + + // Forward left turn + speeds = DifferentialDrive.arcadeDriveIK(0.5, -0.5, false); + assertEquals(0.0, speeds.left, 1e-9); + assertEquals(0.5, speeds.right, 1e-9); + + // Forward right turn + speeds = DifferentialDrive.arcadeDriveIK(0.5, 0.5, false); + assertEquals(0.5, speeds.left, 1e-9); + assertEquals(0.0, speeds.right, 1e-9); + + // Backward + speeds = DifferentialDrive.arcadeDriveIK(-1.0, 0.0, false); + assertEquals(-1.0, speeds.left, 1e-9); + assertEquals(-1.0, speeds.right, 1e-9); + + // Backward left turn + speeds = DifferentialDrive.arcadeDriveIK(-0.5, -0.5, false); + assertEquals(-0.5, speeds.left, 1e-9); + assertEquals(0.0, speeds.right, 1e-9); + + // Backward right turn + speeds = DifferentialDrive.arcadeDriveIK(-0.5, 0.5, false); + assertEquals(0.0, speeds.left, 1e-9); + assertEquals(-0.5, speeds.right, 1e-9); + + // Left turn (xSpeed with negative sign) + speeds = DifferentialDrive.arcadeDriveIK(-0.0, -1.0, false); + assertEquals(-1.0, speeds.left, 1e-9); + assertEquals(1.0, speeds.right, 1e-9); + + // Left turn (xSpeed with positive sign) + speeds = DifferentialDrive.arcadeDriveIK(0.0, -1.0, false); + assertEquals(-1.0, speeds.left, 1e-9); + assertEquals(1.0, speeds.right, 1e-9); + + // Right turn (xSpeed with negative sign) + speeds = DifferentialDrive.arcadeDriveIK(-0.0, 1.0, false); + assertEquals(1.0, speeds.left, 1e-9); + assertEquals(-1.0, speeds.right, 1e-9); + + // Right turn (xSpeed with positive sign) + speeds = DifferentialDrive.arcadeDriveIK(0.0, 1.0, false); + assertEquals(1.0, speeds.left, 1e-9); + assertEquals(-1.0, speeds.right, 1e-9); + } + + @Test + void testArcadeDriveIKSquared() { + // Forward + var speeds = DifferentialDrive.arcadeDriveIK(1.0, 0.0, true); + assertEquals(1.0, speeds.left, 1e-9); + assertEquals(1.0, speeds.right, 1e-9); + + // Forward left turn + speeds = DifferentialDrive.arcadeDriveIK(0.5, -0.5, true); + assertEquals(0.0, speeds.left, 1e-9); + assertEquals(0.25, speeds.right, 1e-9); + + // Forward right turn + speeds = DifferentialDrive.arcadeDriveIK(0.5, 0.5, true); + assertEquals(0.25, speeds.left, 1e-9); + assertEquals(0.0, speeds.right, 1e-9); + + // Backward + speeds = DifferentialDrive.arcadeDriveIK(-1.0, 0.0, true); + assertEquals(-1.0, speeds.left, 1e-9); + assertEquals(-1.0, speeds.right, 1e-9); + + // Backward left turn + speeds = DifferentialDrive.arcadeDriveIK(-0.5, -0.5, true); + assertEquals(-0.25, speeds.left, 1e-9); + assertEquals(0.0, speeds.right, 1e-9); + + // Backward right turn + speeds = DifferentialDrive.arcadeDriveIK(-0.5, 0.5, true); + assertEquals(0.0, speeds.left, 1e-9); + assertEquals(-0.25, speeds.right, 1e-9); + + // Left turn (xSpeed with negative sign) + speeds = DifferentialDrive.arcadeDriveIK(-0.0, -1.0, false); + assertEquals(-1.0, speeds.left, 1e-9); + assertEquals(1.0, speeds.right, 1e-9); + + // Left turn (xSpeed with positive sign) + speeds = DifferentialDrive.arcadeDriveIK(0.0, -1.0, false); + assertEquals(-1.0, speeds.left, 1e-9); + assertEquals(1.0, speeds.right, 1e-9); + + // Right turn (xSpeed with negative sign) + speeds = DifferentialDrive.arcadeDriveIK(-0.0, 1.0, false); + assertEquals(1.0, speeds.left, 1e-9); + assertEquals(-1.0, speeds.right, 1e-9); + + // Right turn (xSpeed with positive sign) + speeds = DifferentialDrive.arcadeDriveIK(0.0, 1.0, false); + assertEquals(1.0, speeds.left, 1e-9); + assertEquals(-1.0, speeds.right, 1e-9); + } + + @Test + void testCurvatureDriveIK() { + // Forward + var speeds = DifferentialDrive.curvatureDriveIK(1.0, 0.0, false); + assertEquals(1.0, speeds.left, 1e-9); + assertEquals(1.0, speeds.right, 1e-9); + + // Forward left turn + speeds = DifferentialDrive.curvatureDriveIK(0.5, -0.5, false); + assertEquals(0.25, speeds.left, 1e-9); + assertEquals(0.75, speeds.right, 1e-9); + + // Forward right turn + speeds = DifferentialDrive.curvatureDriveIK(0.5, 0.5, false); + assertEquals(0.75, speeds.left, 1e-9); + assertEquals(0.25, speeds.right, 1e-9); + + // Backward + speeds = DifferentialDrive.curvatureDriveIK(-1.0, 0.0, false); + assertEquals(-1.0, speeds.left, 1e-9); + assertEquals(-1.0, speeds.right, 1e-9); + + // Backward left turn + speeds = DifferentialDrive.curvatureDriveIK(-0.5, -0.5, false); + assertEquals(-0.75, speeds.left, 1e-9); + assertEquals(-0.25, speeds.right, 1e-9); + + // Backward right turn + speeds = DifferentialDrive.curvatureDriveIK(-0.5, 0.5, false); + assertEquals(-0.25, speeds.left, 1e-9); + assertEquals(-0.75, speeds.right, 1e-9); + } + + @Test + void testCurvatureDriveIKTurnInPlace() { + // Forward + var speeds = DifferentialDrive.curvatureDriveIK(1.0, 0.0, true); + assertEquals(1.0, speeds.left, 1e-9); + assertEquals(1.0, speeds.right, 1e-9); + + // Forward left turn + speeds = DifferentialDrive.curvatureDriveIK(0.5, -0.5, true); + assertEquals(0.0, speeds.left, 1e-9); + assertEquals(1.0, speeds.right, 1e-9); + + // Forward right turn + speeds = DifferentialDrive.curvatureDriveIK(0.5, 0.5, true); + assertEquals(1.0, speeds.left, 1e-9); + assertEquals(0.0, speeds.right, 1e-9); + + // Backward + speeds = DifferentialDrive.curvatureDriveIK(-1.0, 0.0, true); + assertEquals(-1.0, speeds.left, 1e-9); + assertEquals(-1.0, speeds.right, 1e-9); + + // Backward left turn + speeds = DifferentialDrive.curvatureDriveIK(-0.5, -0.5, true); + assertEquals(-1.0, speeds.left, 1e-9); + assertEquals(0.0, speeds.right, 1e-9); + + // Backward right turn + speeds = DifferentialDrive.curvatureDriveIK(-0.5, 0.5, true); + assertEquals(0.0, speeds.left, 1e-9); + assertEquals(-1.0, speeds.right, 1e-9); + } + + @Test + void testTankDriveIK() { + // Forward + var speeds = DifferentialDrive.tankDriveIK(1.0, 1.0, false); + assertEquals(1.0, speeds.left, 1e-9); + assertEquals(1.0, speeds.right, 1e-9); + + // Forward left turn + speeds = DifferentialDrive.tankDriveIK(0.5, 1.0, false); + assertEquals(0.5, speeds.left, 1e-9); + assertEquals(1.0, speeds.right, 1e-9); + + // Forward right turn + speeds = DifferentialDrive.tankDriveIK(1.0, 0.5, false); + assertEquals(1.0, speeds.left, 1e-9); + assertEquals(0.5, speeds.right, 1e-9); + + // Backward + speeds = DifferentialDrive.tankDriveIK(-1.0, -1.0, false); + assertEquals(-1.0, speeds.left, 1e-9); + assertEquals(-1.0, speeds.right, 1e-9); + + // Backward left turn + speeds = DifferentialDrive.tankDriveIK(-0.5, -1.0, false); + assertEquals(-0.5, speeds.left, 1e-9); + assertEquals(-1.0, speeds.right, 1e-9); + + // Backward right turn + speeds = DifferentialDrive.tankDriveIK(-0.5, 1.0, false); + assertEquals(-0.5, speeds.left, 1e-9); + assertEquals(1.0, speeds.right, 1e-9); + } + + @Test + void testTankDriveIKSquared() { + // Forward + var speeds = DifferentialDrive.tankDriveIK(1.0, 1.0, true); + assertEquals(1.0, speeds.left, 1e-9); + assertEquals(1.0, speeds.right, 1e-9); + + // Forward left turn + speeds = DifferentialDrive.tankDriveIK(0.5, 1.0, true); + assertEquals(0.25, speeds.left, 1e-9); + assertEquals(1.0, speeds.right, 1e-9); + + // Forward right turn + speeds = DifferentialDrive.tankDriveIK(1.0, 0.5, true); + assertEquals(1.0, speeds.left, 1e-9); + assertEquals(0.25, speeds.right, 1e-9); + + // Backward + speeds = DifferentialDrive.tankDriveIK(-1.0, -1.0, true); + assertEquals(-1.0, speeds.left, 1e-9); + assertEquals(-1.0, speeds.right, 1e-9); + + // Backward left turn + speeds = DifferentialDrive.tankDriveIK(-0.5, -1.0, true); + assertEquals(-0.25, speeds.left, 1e-9); + assertEquals(-1.0, speeds.right, 1e-9); + + // Backward right turn + speeds = DifferentialDrive.tankDriveIK(-1.0, -0.5, true); + assertEquals(-1.0, speeds.left, 1e-9); + assertEquals(-0.25, speeds.right, 1e-9); + } + @Test void testArcadeDrive() { var left = new MockMotorController(); diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/drive/KilloughDriveTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/drive/KilloughDriveTest.java index 7d06d9f818..99858d94de 100644 --- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/drive/KilloughDriveTest.java +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/drive/KilloughDriveTest.java @@ -10,6 +10,82 @@ import edu.wpi.first.wpilibj.motorcontrol.MockMotorController; import org.junit.jupiter.api.Test; class KilloughDriveTest { + @Test + void testCartesianIK() { + var left = new MockMotorController(); + var right = new MockMotorController(); + var back = new MockMotorController(); + var drive = new KilloughDrive(left, right, back); + + // Forward + var speeds = drive.driveCartesianIK(1.0, 0.0, 0.0); + assertEquals(0.5, speeds.left, 1e-9); + assertEquals(-0.5, speeds.right, 1e-9); + assertEquals(0.0, speeds.back, 1e-9); + + // Left + speeds = drive.driveCartesianIK(0.0, -1.0, 0.0); + assertEquals(-Math.sqrt(3) / 2, speeds.left, 1e-9); + assertEquals(-Math.sqrt(3) / 2, speeds.right, 1e-9); + assertEquals(1.0, speeds.back, 1e-9); + + // Right + speeds = drive.driveCartesianIK(0.0, 1.0, 0.0); + assertEquals(Math.sqrt(3) / 2, speeds.left, 1e-9); + assertEquals(Math.sqrt(3) / 2, speeds.right, 1e-9); + assertEquals(-1.0, speeds.back, 1e-9); + + // Rotate CCW + speeds = drive.driveCartesianIK(0.0, 0.0, -1.0); + assertEquals(-1.0, speeds.left, 1e-9); + assertEquals(-1.0, speeds.right, 1e-9); + assertEquals(-1.0, speeds.back, 1e-9); + + // Rotate CW + speeds = drive.driveCartesianIK(0.0, 0.0, 1.0); + assertEquals(1.0, speeds.left, 1e-9); + assertEquals(1.0, speeds.right, 1e-9); + assertEquals(1.0, speeds.back, 1e-9); + } + + @Test + void testCartesianIKGyro90CW() { + var left = new MockMotorController(); + var right = new MockMotorController(); + var back = new MockMotorController(); + var drive = new KilloughDrive(left, right, back); + + // Forward in global frame; left in robot frame + var speeds = drive.driveCartesianIK(1.0, 0.0, 0.0, 90.0); + assertEquals(-Math.sqrt(3) / 2, speeds.left, 1e-9); + assertEquals(-Math.sqrt(3) / 2, speeds.right, 1e-9); + assertEquals(1.0, speeds.back, 1e-9); + + // Left in global frame; backward in robot frame + speeds = drive.driveCartesianIK(0.0, -1.0, 0.0, 90.0); + assertEquals(-0.5, speeds.left, 1e-9); + assertEquals(0.5, speeds.right, 1e-9); + assertEquals(0.0, speeds.back, 1e-9); + + // Right in global frame; forward in robot frame + speeds = drive.driveCartesianIK(0.0, 1.0, 0.0, 90.0); + assertEquals(0.5, speeds.left, 1e-9); + assertEquals(-0.5, speeds.right, 1e-9); + assertEquals(0.0, speeds.back, 1e-9); + + // Rotate CCW + speeds = drive.driveCartesianIK(0.0, 0.0, -1.0, 90.0); + assertEquals(-1.0, speeds.left, 1e-9); + assertEquals(-1.0, speeds.right, 1e-9); + assertEquals(-1.0, speeds.back, 1e-9); + + // Rotate CW + speeds = drive.driveCartesianIK(0.0, 0.0, 1.0, 90.0); + assertEquals(1.0, speeds.left, 1e-9); + assertEquals(1.0, speeds.right, 1e-9); + assertEquals(1.0, speeds.back, 1e-9); + } + @Test void testCartesian() { var left = new MockMotorController(); @@ -50,7 +126,7 @@ class KilloughDriveTest { } @Test - void testCartesiangyro90CW() { + void testCartesianGyro90CW() { var left = new MockMotorController(); var right = new MockMotorController(); var back = new MockMotorController(); diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/drive/MecanumDriveTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/drive/MecanumDriveTest.java index 70a07a2226..bf3349c6d8 100644 --- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/drive/MecanumDriveTest.java +++ b/wpilibj/src/test/java/edu/wpi/first/wpilibj/drive/MecanumDriveTest.java @@ -10,13 +10,89 @@ import edu.wpi.first.wpilibj.motorcontrol.MockMotorController; import org.junit.jupiter.api.Test; class MecanumDriveTest { + @Test + void testCartesianIK() { + // Forward + var speeds = MecanumDrive.driveCartesianIK(1.0, 0.0, 0.0); + assertEquals(1.0, speeds.frontLeft, 1e-9); + assertEquals(1.0, speeds.frontRight, 1e-9); + assertEquals(1.0, speeds.rearLeft, 1e-9); + assertEquals(1.0, speeds.rearRight, 1e-9); + + // Left + speeds = MecanumDrive.driveCartesianIK(0.0, -1.0, 0.0); + assertEquals(-1.0, speeds.frontLeft, 1e-9); + assertEquals(1.0, speeds.frontRight, 1e-9); + assertEquals(1.0, speeds.rearLeft, 1e-9); + assertEquals(-1.0, speeds.rearRight, 1e-9); + + // Right + speeds = MecanumDrive.driveCartesianIK(0.0, 1.0, 0.0); + assertEquals(1.0, speeds.frontLeft, 1e-9); + assertEquals(-1.0, speeds.frontRight, 1e-9); + assertEquals(-1.0, speeds.rearLeft, 1e-9); + assertEquals(1.0, speeds.rearRight, 1e-9); + + // Rotate CCW + speeds = MecanumDrive.driveCartesianIK(0.0, 0.0, -1.0); + assertEquals(-1.0, speeds.frontLeft, 1e-9); + assertEquals(1.0, speeds.frontRight, 1e-9); + assertEquals(-1.0, speeds.rearLeft, 1e-9); + assertEquals(1.0, speeds.rearRight, 1e-9); + + // Rotate CW + speeds = MecanumDrive.driveCartesianIK(0.0, 0.0, 1.0); + assertEquals(1.0, speeds.frontLeft, 1e-9); + assertEquals(-1.0, speeds.frontRight, 1e-9); + assertEquals(1.0, speeds.rearLeft, 1e-9); + assertEquals(-1.0, speeds.rearRight, 1e-9); + } + + @Test + void testCartesianIKGyro90CW() { + // Forward in global frame; left in robot frame + var speeds = MecanumDrive.driveCartesianIK(1.0, 0.0, 0.0, 90.0); + assertEquals(-1.0, speeds.frontLeft, 1e-9); + assertEquals(1.0, speeds.frontRight, 1e-9); + assertEquals(1.0, speeds.rearLeft, 1e-9); + assertEquals(-1.0, speeds.rearRight, 1e-9); + + // Left in global frame; backward in robot frame + speeds = MecanumDrive.driveCartesianIK(0.0, -1.0, 0.0, 90.0); + assertEquals(-1.0, speeds.frontLeft, 1e-9); + assertEquals(-1.0, speeds.frontRight, 1e-9); + assertEquals(-1.0, speeds.rearLeft, 1e-9); + assertEquals(-1.0, speeds.rearRight, 1e-9); + + // Right in global frame; forward in robot frame + speeds = MecanumDrive.driveCartesianIK(0.0, 1.0, 0.0, 90.0); + assertEquals(1.0, speeds.frontLeft, 1e-9); + assertEquals(1.0, speeds.frontRight, 1e-9); + assertEquals(1.0, speeds.rearLeft, 1e-9); + assertEquals(1.0, speeds.rearRight, 1e-9); + + // Rotate CCW + speeds = MecanumDrive.driveCartesianIK(0.0, 0.0, -1.0, 90.0); + assertEquals(-1.0, speeds.frontLeft, 1e-9); + assertEquals(1.0, speeds.frontRight, 1e-9); + assertEquals(-1.0, speeds.rearLeft, 1e-9); + assertEquals(1.0, speeds.rearRight, 1e-9); + + // Rotate CW + speeds = MecanumDrive.driveCartesianIK(0.0, 0.0, 1.0, 90.0); + assertEquals(1.0, speeds.frontLeft, 1e-9); + assertEquals(-1.0, speeds.frontRight, 1e-9); + assertEquals(1.0, speeds.rearLeft, 1e-9); + assertEquals(-1.0, speeds.rearRight, 1e-9); + } + @Test void testCartesian() { var fl = new MockMotorController(); var fr = new MockMotorController(); var rl = new MockMotorController(); var rr = new MockMotorController(); - var drive = new MecanumDrive(fl, fr, rl, rr); + var drive = new MecanumDrive(fl, rl, fr, rr); drive.setDeadband(0.0); // Forward @@ -43,25 +119,25 @@ class MecanumDriveTest { // Rotate CCW drive.driveCartesian(0.0, 0.0, -1.0); assertEquals(-1.0, fl.get(), 1e-9); - assertEquals(-1.0, fr.get(), 1e-9); - assertEquals(1.0, rl.get(), 1e-9); + assertEquals(1.0, fr.get(), 1e-9); + assertEquals(-1.0, rl.get(), 1e-9); assertEquals(1.0, rr.get(), 1e-9); // Rotate CW drive.driveCartesian(0.0, 0.0, 1.0); assertEquals(1.0, fl.get(), 1e-9); - assertEquals(1.0, fr.get(), 1e-9); - assertEquals(-1.0, rl.get(), 1e-9); + assertEquals(-1.0, fr.get(), 1e-9); + assertEquals(1.0, rl.get(), 1e-9); assertEquals(-1.0, rr.get(), 1e-9); } @Test - void testCartesiangyro90CW() { + void testCartesianGyro90CW() { var fl = new MockMotorController(); var fr = new MockMotorController(); var rl = new MockMotorController(); var rr = new MockMotorController(); - var drive = new MecanumDrive(fl, fr, rl, rr); + var drive = new MecanumDrive(fl, rl, fr, rr); drive.setDeadband(0.0); // Forward in global frame; left in robot frame @@ -88,15 +164,15 @@ class MecanumDriveTest { // Rotate CCW drive.driveCartesian(0.0, 0.0, -1.0, 90.0); assertEquals(-1.0, fl.get(), 1e-9); - assertEquals(-1.0, fr.get(), 1e-9); - assertEquals(1.0, rl.get(), 1e-9); + assertEquals(1.0, fr.get(), 1e-9); + assertEquals(-1.0, rl.get(), 1e-9); assertEquals(1.0, rr.get(), 1e-9); // Rotate CW drive.driveCartesian(0.0, 0.0, 1.0, 90.0); assertEquals(1.0, fl.get(), 1e-9); - assertEquals(1.0, fr.get(), 1e-9); - assertEquals(-1.0, rl.get(), 1e-9); + assertEquals(-1.0, fr.get(), 1e-9); + assertEquals(1.0, rl.get(), 1e-9); assertEquals(-1.0, rr.get(), 1e-9); } @@ -106,7 +182,7 @@ class MecanumDriveTest { var fr = new MockMotorController(); var rl = new MockMotorController(); var rr = new MockMotorController(); - var drive = new MecanumDrive(fl, fr, rl, rr); + var drive = new MecanumDrive(fl, rl, fr, rr); drive.setDeadband(0.0); // Forward @@ -133,15 +209,15 @@ class MecanumDriveTest { // Rotate CCW drive.drivePolar(0.0, 0.0, -1.0); assertEquals(-1.0, fl.get(), 1e-9); - assertEquals(-1.0, fr.get(), 1e-9); - assertEquals(1.0, rl.get(), 1e-9); + assertEquals(1.0, fr.get(), 1e-9); + assertEquals(-1.0, rl.get(), 1e-9); assertEquals(1.0, rr.get(), 1e-9); // Rotate CW drive.drivePolar(0.0, 0.0, 1.0); assertEquals(1.0, fl.get(), 1e-9); - assertEquals(1.0, fr.get(), 1e-9); - assertEquals(-1.0, rl.get(), 1e-9); + assertEquals(-1.0, fr.get(), 1e-9); + assertEquals(1.0, rl.get(), 1e-9); assertEquals(-1.0, rr.get(), 1e-9); } }