2020-12-26 14:12:05 -08:00
|
|
|
// Copyright (c) FIRST and other WPILib contributors.
|
|
|
|
|
// Open Source Software; you can modify and/or share it under the terms of
|
|
|
|
|
// the WPILib BSD license file in the root directory of this project.
|
2020-09-24 23:05:27 -04:00
|
|
|
|
2023-08-28 15:13:34 -07:00
|
|
|
#include <gtest/gtest.h>
|
2020-09-24 23:05:27 -04:00
|
|
|
#include <units/current.h>
|
2020-09-27 09:31:29 -07:00
|
|
|
#include <units/math.h>
|
2020-09-24 23:05:27 -04:00
|
|
|
#include <units/moment_of_inertia.h>
|
|
|
|
|
|
|
|
|
|
#include "frc/controller/LinearPlantInversionFeedforward.h"
|
|
|
|
|
#include "frc/controller/RamseteController.h"
|
|
|
|
|
#include "frc/kinematics/DifferentialDriveKinematics.h"
|
|
|
|
|
#include "frc/simulation/DifferentialDrivetrainSim.h"
|
2021-01-06 21:40:25 -08:00
|
|
|
#include "frc/system/NumericalIntegration.h"
|
2020-09-24 23:05:27 -04:00
|
|
|
#include "frc/system/plant/DCMotor.h"
|
|
|
|
|
#include "frc/system/plant/LinearSystemId.h"
|
|
|
|
|
#include "frc/trajectory/TrajectoryGenerator.h"
|
|
|
|
|
#include "frc/trajectory/constraint/DifferentialDriveKinematicsConstraint.h"
|
|
|
|
|
|
2021-12-22 22:27:51 -08:00
|
|
|
TEST(DifferentialDrivetrainSimTest, Convergence) {
|
2020-09-24 23:05:27 -04:00
|
|
|
auto motor = frc::DCMotor::NEO(2);
|
|
|
|
|
auto plant = frc::LinearSystemId::DrivetrainVelocitySystem(
|
|
|
|
|
motor, 50_kg, 2_in, 12_in, 0.5_kg_sq_m, 1.0);
|
|
|
|
|
|
|
|
|
|
frc::DifferentialDriveKinematics kinematics{24_in};
|
2020-12-04 18:46:50 -08:00
|
|
|
frc::sim::DifferentialDrivetrainSim sim{
|
|
|
|
|
plant, 24_in, motor,
|
|
|
|
|
1.0, 2_in, {0.001, 0.001, 0.0001, 0.1, 0.1, 0.005, 0.005}};
|
2020-09-24 23:05:27 -04:00
|
|
|
|
|
|
|
|
frc::LinearPlantInversionFeedforward feedforward{plant, 20_ms};
|
|
|
|
|
frc::RamseteController ramsete;
|
|
|
|
|
|
2022-04-29 22:29:20 -07:00
|
|
|
feedforward.Reset(frc::Vectord<2>{0.0, 0.0});
|
2020-09-24 23:05:27 -04:00
|
|
|
|
|
|
|
|
// Ground truth.
|
2022-04-29 22:29:20 -07:00
|
|
|
frc::Vectord<7> groundTruthX = frc::Vectord<7>::Zero();
|
2020-09-24 23:05:27 -04:00
|
|
|
|
|
|
|
|
frc::TrajectoryConfig config{1_mps, 1_mps_sq};
|
|
|
|
|
config.AddConstraint(
|
|
|
|
|
frc::DifferentialDriveKinematicsConstraint(kinematics, 1_mps));
|
|
|
|
|
|
|
|
|
|
auto trajectory = frc::TrajectoryGenerator::GenerateTrajectory(
|
2022-08-17 13:42:36 -07:00
|
|
|
frc::Pose2d{}, {}, frc::Pose2d{2_m, 2_m, 0_rad}, config);
|
2020-09-24 23:05:27 -04:00
|
|
|
|
2021-12-22 22:27:51 -08:00
|
|
|
for (auto t = 0_s; t < trajectory.TotalTime(); t += 20_ms) {
|
|
|
|
|
auto state = trajectory.Sample(t);
|
2020-09-27 16:25:17 -04:00
|
|
|
auto ramseteOut = ramsete.Calculate(sim.GetPose(), state);
|
2020-09-24 23:05:27 -04:00
|
|
|
|
|
|
|
|
auto [l, r] = kinematics.ToWheelSpeeds(ramseteOut);
|
2021-10-25 08:58:12 -07:00
|
|
|
auto voltages =
|
2022-04-29 22:29:20 -07:00
|
|
|
feedforward.Calculate(frc::Vectord<2>{l.value(), r.value()});
|
2020-09-24 23:05:27 -04:00
|
|
|
|
|
|
|
|
// Sim periodic code.
|
2022-08-17 13:42:36 -07:00
|
|
|
sim.SetInputs(units::volt_t{voltages(0, 0)}, units::volt_t{voltages(1, 0)});
|
2020-09-24 23:05:27 -04:00
|
|
|
sim.Update(20_ms);
|
|
|
|
|
|
|
|
|
|
// Update ground truth.
|
2021-01-06 21:40:25 -08:00
|
|
|
groundTruthX = frc::RK4(
|
2022-04-29 22:29:20 -07:00
|
|
|
[&sim](const auto& x, const auto& u) -> frc::Vectord<7> {
|
2020-09-24 23:05:27 -04:00
|
|
|
return sim.Dynamics(x, u);
|
|
|
|
|
},
|
|
|
|
|
groundTruthX, voltages, 20_ms);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-16 23:42:46 -07:00
|
|
|
// 2 inch tolerance is OK since our ground truth is an approximation of the
|
|
|
|
|
// ODE solution using RK4 anyway
|
2021-10-25 08:58:12 -07:00
|
|
|
EXPECT_NEAR(groundTruthX(0, 0), sim.GetPose().X().value(), 0.05);
|
|
|
|
|
EXPECT_NEAR(groundTruthX(1, 0), sim.GetPose().Y().value(), 0.05);
|
|
|
|
|
EXPECT_NEAR(groundTruthX(2, 0), sim.GetHeading().Radians().value(), 0.01);
|
2020-09-24 23:05:27 -04:00
|
|
|
}
|
|
|
|
|
|
2021-12-22 22:27:51 -08:00
|
|
|
TEST(DifferentialDrivetrainSimTest, Current) {
|
2020-09-24 23:05:27 -04:00
|
|
|
auto motor = frc::DCMotor::NEO(2);
|
|
|
|
|
auto plant = frc::LinearSystemId::DrivetrainVelocitySystem(
|
|
|
|
|
motor, 50_kg, 2_in, 12_in, 0.5_kg_sq_m, 1.0);
|
|
|
|
|
|
|
|
|
|
frc::DifferentialDriveKinematics kinematics{24_in};
|
|
|
|
|
frc::sim::DifferentialDrivetrainSim sim{plant, 24_in, motor, 1.0, 2_in};
|
|
|
|
|
|
|
|
|
|
sim.SetInputs(-12_V, 12_V);
|
|
|
|
|
for (int i = 0; i < 10; ++i) {
|
|
|
|
|
sim.Update(20_ms);
|
|
|
|
|
}
|
|
|
|
|
EXPECT_TRUE(sim.GetCurrentDraw() > 0_A);
|
|
|
|
|
|
|
|
|
|
sim.SetInputs(12_V, 12_V);
|
|
|
|
|
for (int i = 0; i < 20; ++i) {
|
|
|
|
|
sim.Update(20_ms);
|
|
|
|
|
}
|
|
|
|
|
EXPECT_TRUE(sim.GetCurrentDraw() > 0_A);
|
|
|
|
|
|
|
|
|
|
sim.SetInputs(-12_V, 12_V);
|
|
|
|
|
for (int i = 0; i < 30; ++i) {
|
|
|
|
|
sim.Update(20_ms);
|
|
|
|
|
}
|
|
|
|
|
EXPECT_TRUE(sim.GetCurrentDraw() > 0_A);
|
|
|
|
|
}
|
|
|
|
|
|
2021-12-22 22:27:51 -08:00
|
|
|
TEST(DifferentialDrivetrainSimTest, ModelStability) {
|
2020-09-24 23:05:27 -04:00
|
|
|
auto motor = frc::DCMotor::NEO(2);
|
|
|
|
|
auto plant = frc::LinearSystemId::DrivetrainVelocitySystem(
|
|
|
|
|
motor, 50_kg, 2_in, 12_in, 2_kg_sq_m, 5.0);
|
|
|
|
|
|
|
|
|
|
frc::DifferentialDriveKinematics kinematics{24_in};
|
|
|
|
|
frc::sim::DifferentialDrivetrainSim sim{plant, 24_in, motor, 1.0, 2_in};
|
|
|
|
|
|
|
|
|
|
sim.SetInputs(2_V, 4_V);
|
|
|
|
|
|
2020-09-27 09:31:29 -07:00
|
|
|
// 10 seconds should be enough time to verify stability
|
|
|
|
|
for (int i = 0; i < 500; ++i) {
|
2020-09-24 23:05:27 -04:00
|
|
|
sim.Update(20_ms);
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-27 16:25:17 -04:00
|
|
|
EXPECT_LT(units::math::abs(sim.GetPose().Translation().Norm()), 100_m);
|
2020-09-24 23:05:27 -04:00
|
|
|
}
|