blob: 938ca75ba0378c0bf7e0d7c46a7889eecf119723 [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#include "aos/util/trapezoid_profile.h"
briansf0165ca2013-03-02 06:17:47 +00002
John Park33858a32018-09-28 23:05:48 -07003#include "aos/logging/logging.h"
Brian Silverman38ea9bf2014-04-19 22:57:54 -07004
briansf0165ca2013-03-02 06:17:47 +00005using ::Eigen::Matrix;
6
Stephan Pleinesf63bde82024-01-13 15:59:33 -08007namespace aos::util {
briansf0165ca2013-03-02 06:17:47 +00008
Austin Schuh214e9c12016-11-25 17:26:20 -08009TrapezoidProfile::TrapezoidProfile(::std::chrono::nanoseconds delta_time)
10 : maximum_acceleration_(0), maximum_velocity_(0), timestep_(delta_time) {
briansf0165ca2013-03-02 06:17:47 +000011 output_.setZero();
12}
13
James Kuszmaul651fc3f2019-05-15 21:14:25 -070014void TrapezoidProfile::UpdateVals(double acceleration, double delta_time) {
15 output_(0) +=
16 output_(1) * delta_time + 0.5 * acceleration * delta_time * delta_time;
briansf0165ca2013-03-02 06:17:47 +000017 output_(1) += acceleration * delta_time;
18}
19
James Kuszmaul651fc3f2019-05-15 21:14:25 -070020const Matrix<double, 2, 1> &TrapezoidProfile::Update(double goal_position,
21 double goal_velocity) {
briansf0165ca2013-03-02 06:17:47 +000022 CalculateTimes(goal_position - output_(0), goal_velocity);
23
James Kuszmaul651fc3f2019-05-15 21:14:25 -070024 double next_timestep = ::aos::time::DurationInSeconds(timestep_);
briansf0165ca2013-03-02 06:17:47 +000025
26 if (acceleration_time_ > next_timestep) {
27 UpdateVals(acceleration_, next_timestep);
28 } else {
29 UpdateVals(acceleration_, acceleration_time_);
30
31 next_timestep -= acceleration_time_;
32 if (constant_time_ > next_timestep) {
33 UpdateVals(0, next_timestep);
34 } else {
35 UpdateVals(0, constant_time_);
36 next_timestep -= constant_time_;
37 if (deceleration_time_ > next_timestep) {
38 UpdateVals(deceleration_, next_timestep);
39 } else {
40 UpdateVals(deceleration_, deceleration_time_);
41 next_timestep -= deceleration_time_;
42 UpdateVals(0, next_timestep);
43 }
44 }
45 }
46
47 return output_;
48}
49
50void TrapezoidProfile::CalculateTimes(double distance_to_target,
51 double goal_velocity) {
52 if (distance_to_target == 0) {
53 // We're there. Stop everything.
54 // TODO(aschuh): Deal with velocity not right.
55 acceleration_time_ = 0;
56 acceleration_ = 0;
57 constant_time_ = 0;
58 deceleration_time_ = 0;
59 deceleration_ = 0;
60 return;
61 } else if (distance_to_target < 0) {
62 // Recurse with everything inverted.
63 output_(1) *= -1;
Diana Vandenberg19bb9e22016-02-03 21:24:31 -080064 CalculateTimes(-distance_to_target, -goal_velocity);
briansf0165ca2013-03-02 06:17:47 +000065 output_(1) *= -1;
66 acceleration_ *= -1;
67 deceleration_ *= -1;
68 return;
69 }
70
71 constant_time_ = 0;
72 acceleration_ = maximum_acceleration_;
Diana Vandenberg19bb9e22016-02-03 21:24:31 -080073 double maximum_acceleration_velocity =
74 distance_to_target * 2 * std::abs(acceleration_) +
75 output_(1) * output_(1);
briansf0165ca2013-03-02 06:17:47 +000076 if (maximum_acceleration_velocity > 0) {
77 maximum_acceleration_velocity = sqrt(maximum_acceleration_velocity);
78 } else {
79 maximum_acceleration_velocity = -sqrt(-maximum_acceleration_velocity);
80 }
81
82 // Since we know what we'd have to do if we kept after it to decelerate, we
83 // know the sign of the acceleration.
84 if (maximum_acceleration_velocity > goal_velocity) {
85 deceleration_ = -maximum_acceleration_;
86 } else {
87 deceleration_ = maximum_acceleration_;
88 }
89
90 // We now know the top velocity we can get to.
James Kuszmaul651fc3f2019-05-15 21:14:25 -070091 double top_velocity = sqrt(
92 (distance_to_target + (output_(1) * output_(1)) / (2.0 * acceleration_) +
93 (goal_velocity * goal_velocity) / (2.0 * deceleration_)) /
94 (-1.0 / (2.0 * deceleration_) + 1.0 / (2.0 * acceleration_)));
briansf0165ca2013-03-02 06:17:47 +000095
96 // If it can go too fast, we now know how long we get to accelerate for and
97 // how long to go at constant velocity.
98 if (top_velocity > maximum_velocity_) {
James Kuszmaul651fc3f2019-05-15 21:14:25 -070099 acceleration_time_ =
100 (maximum_velocity_ - output_(1)) / maximum_acceleration_;
101 constant_time_ =
102 (distance_to_target + (goal_velocity * goal_velocity -
103 maximum_velocity_ * maximum_velocity_) /
104 (2.0 * maximum_acceleration_)) /
105 maximum_velocity_;
briansf0165ca2013-03-02 06:17:47 +0000106 } else {
James Kuszmaul651fc3f2019-05-15 21:14:25 -0700107 acceleration_time_ = (top_velocity - output_(1)) / acceleration_;
briansf0165ca2013-03-02 06:17:47 +0000108 }
109
Austin Schuhf257f3c2019-10-27 21:00:43 -0700110 AOS_CHECK_GT(top_velocity, -maximum_velocity_);
briansf0165ca2013-03-02 06:17:47 +0000111
Ben Fredricksonf33d6532015-03-15 00:29:29 -0700112 if (output_(1) > maximum_velocity_) {
113 constant_time_ = 0;
114 acceleration_time_ = 0;
115 }
116
James Kuszmaul651fc3f2019-05-15 21:14:25 -0700117 deceleration_time_ = (goal_velocity - top_velocity) / deceleration_;
briansf0165ca2013-03-02 06:17:47 +0000118}
119
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800120} // namespace aos::util