blob: 92b99963bd03300cc886fd2f55abc472b402cdd4 [file] [log] [blame]
Austin Schuh60e77942022-05-16 17:48:24 -07001#include "aos/util/trapezoid_profile.h"
briansf0165ca2013-03-02 06:17:47 +00002
3#include "Eigen/Dense"
Austin Schuh60e77942022-05-16 17:48:24 -07004#include "gtest/gtest.h"
briansf0165ca2013-03-02 06:17:47 +00005
Stephan Pleinesf63bde82024-01-13 15:59:33 -08006namespace aos::util::testing {
briansf0165ca2013-03-02 06:17:47 +00007
8class TrapezoidProfileTest : public ::testing::Test {
9 public:
10 EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
11
12 protected:
13 TrapezoidProfileTest() : profile_(delta_time) {
14 position_.setZero();
15 profile_.set_maximum_acceleration(0.75);
16 profile_.set_maximum_velocity(1.75);
17 }
18
19 // Runs an iteration.
Austin Schuh60e77942022-05-16 17:48:24 -070020 void RunIteration(double goal_position, double goal_velocity) {
21 position_ = profile_.Update(goal_position, goal_velocity);
briansf0165ca2013-03-02 06:17:47 +000022 }
23
24 const Eigen::Matrix<double, 2, 1> &position() { return position_; }
25
26 TrapezoidProfile profile_;
27
28 ::testing::AssertionResult At(double position, double velocity) {
briansd412b3f2013-03-03 21:13:44 +000029 static const double kDoubleNear = 0.00001;
30 if (::std::abs(velocity - position_(1)) > kDoubleNear) {
Austin Schuh60e77942022-05-16 17:48:24 -070031 return ::testing::AssertionFailure()
32 << "velocity is " << position_(1) << " not " << velocity;
briansf0165ca2013-03-02 06:17:47 +000033 }
briansd412b3f2013-03-03 21:13:44 +000034 if (::std::abs(position - position_(0)) > kDoubleNear) {
Austin Schuh60e77942022-05-16 17:48:24 -070035 return ::testing::AssertionFailure()
36 << "position is " << position_(0) << " not " << position;
briansf0165ca2013-03-02 06:17:47 +000037 }
Austin Schuh60e77942022-05-16 17:48:24 -070038 return ::testing::AssertionSuccess()
39 << "at " << position << " moving at " << velocity;
briansf0165ca2013-03-02 06:17:47 +000040 }
41
42 private:
Austin Schuh214e9c12016-11-25 17:26:20 -080043 static constexpr ::std::chrono::nanoseconds delta_time =
44 ::std::chrono::milliseconds(10);
briansf0165ca2013-03-02 06:17:47 +000045
46 Eigen::Matrix<double, 2, 1> position_;
47};
Austin Schuh214e9c12016-11-25 17:26:20 -080048
49constexpr ::std::chrono::nanoseconds TrapezoidProfileTest::delta_time;
briansf0165ca2013-03-02 06:17:47 +000050
51TEST_F(TrapezoidProfileTest, ReachesGoal) {
52 for (int i = 0; i < 450; ++i) {
53 RunIteration(3, 0);
54 }
55 EXPECT_TRUE(At(3, 0));
56}
57
Ben Fredricksonf33d6532015-03-15 00:29:29 -070058// Tests that decresing the maximum velocity in the middle when it is already
59// moving faster than the new max is handled correctly.
60TEST_F(TrapezoidProfileTest, ContinousUnderVelChange) {
61 profile_.set_maximum_velocity(1.75);
62 RunIteration(12.0, 0);
63 double last_pos = position()(0);
64 double last_vel = 1.75;
65 for (int i = 0; i < 1600; ++i) {
66 if (i == 400) {
67 profile_.set_maximum_velocity(0.75);
68 }
69 RunIteration(12.0, 0);
70 if (i >= 400) {
71 EXPECT_TRUE(::std::abs(last_pos - position()(0)) <= 1.75 * 0.01);
72 EXPECT_NEAR(last_vel, ::std::abs(last_pos - position()(0)), 0.0001);
73 }
74 last_vel = ::std::abs(last_pos - position()(0));
75 last_pos = position()(0);
76 }
77 EXPECT_TRUE(At(12.0, 0));
78}
79
briansf0165ca2013-03-02 06:17:47 +000080// There is some somewhat tricky code for dealing with going backwards.
81TEST_F(TrapezoidProfileTest, Backwards) {
82 for (int i = 0; i < 400; ++i) {
83 RunIteration(-2, 0);
84 }
85 EXPECT_TRUE(At(-2, 0));
86}
87
88TEST_F(TrapezoidProfileTest, SwitchGoalInMiddle) {
89 for (int i = 0; i < 200; ++i) {
90 RunIteration(-2, 0);
91 }
92 EXPECT_FALSE(At(-2, 0));
93 for (int i = 0; i < 550; ++i) {
94 RunIteration(0, 0);
95 }
96 EXPECT_TRUE(At(0, 0));
97}
98
99// Checks to make sure that it hits top speed.
100TEST_F(TrapezoidProfileTest, TopSpeed) {
101 for (int i = 0; i < 200; ++i) {
102 RunIteration(4, 0);
103 }
104 EXPECT_NEAR(1.5, position()(1), 10e-5);
105 for (int i = 0; i < 2000; ++i) {
106 RunIteration(4, 0);
107 }
108 EXPECT_TRUE(At(4, 0));
109}
110
Austin Schuh5d571d02017-02-11 12:28:17 -0800111// Tests that the position and velocity exactly match at the end. Some code we
112// have assumes this to be true as a simplification.
113TEST_F(TrapezoidProfileTest, ExactlyReachesGoal) {
114 for (int i = 0; i < 450; ++i) {
115 RunIteration(1, 0);
116 }
117 EXPECT_EQ(position()(1), 0.0);
118 EXPECT_EQ(position()(0), 1.0);
119}
120
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800121} // namespace aos::util::testing