blob: 05e79ca42e02a3320a9c4b048f5be968f6059f33 [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#include "aos/util/trapezoid_profile.h"
briansf0165ca2013-03-02 06:17:47 +00002
Austin Schuhe197a962024-02-20 18:10:12 -08003#include "glog/logging.h"
briansf0165ca2013-03-02 06:17:47 +00004
Stephan Pleinesf63bde82024-01-13 15:59:33 -08005namespace aos::util {
briansf0165ca2013-03-02 06:17:47 +00006
Austin Schuhe197a962024-02-20 18:10:12 -08007AsymmetricTrapezoidProfile::AsymmetricTrapezoidProfile(
8 ::std::chrono::nanoseconds delta_time)
9 : timestep_(delta_time) {
briansf0165ca2013-03-02 06:17:47 +000010 output_.setZero();
11}
12
Austin Schuhe197a962024-02-20 18:10:12 -080013void AsymmetricTrapezoidProfile::UpdateVals(double acceleration,
14 double delta_time) {
James Kuszmaul651fc3f2019-05-15 21:14:25 -070015 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
Austin Schuhe197a962024-02-20 18:10:12 -080020const Eigen::Matrix<double, 2, 1> &AsymmetricTrapezoidProfile::Update(
21 double goal_position, double goal_velocity) {
22 CalculateTimes(goal_position - output_(0), goal_velocity, output_);
briansf0165ca2013-03-02 06:17:47 +000023
James Kuszmaul651fc3f2019-05-15 21:14:25 -070024 double next_timestep = ::aos::time::DurationInSeconds(timestep_);
briansf0165ca2013-03-02 06:17:47 +000025
Austin Schuhe197a962024-02-20 18:10:12 -080026 if (deceleration_reversal_time_ > next_timestep) {
27 UpdateVals(deceleration_reversal_, next_timestep);
28 return output_;
29 }
30
31 UpdateVals(deceleration_reversal_, deceleration_reversal_time_);
32 next_timestep -= deceleration_reversal_time_;
33
briansf0165ca2013-03-02 06:17:47 +000034 if (acceleration_time_ > next_timestep) {
35 UpdateVals(acceleration_, next_timestep);
Austin Schuhe197a962024-02-20 18:10:12 -080036 return output_;
37 }
briansf0165ca2013-03-02 06:17:47 +000038
Austin Schuhe197a962024-02-20 18:10:12 -080039 UpdateVals(acceleration_, acceleration_time_);
40 next_timestep -= acceleration_time_;
41
42 if (constant_time_ > next_timestep) {
43 UpdateVals(0, next_timestep);
44 return output_;
45 }
46
47 UpdateVals(0, constant_time_);
48 next_timestep -= constant_time_;
49 if (deceleration_time_ > next_timestep) {
50 UpdateVals(deceleration_, next_timestep);
51 } else {
52 UpdateVals(deceleration_, deceleration_time_);
53 next_timestep -= deceleration_time_;
54 UpdateVals(0, next_timestep);
55
56 if (next_timestep >= 0 && goal_velocity == 0) {
57 output_(0) = goal_position;
58 output_(1) = goal_velocity;
briansf0165ca2013-03-02 06:17:47 +000059 }
60 }
61
62 return output_;
63}
64
Austin Schuhe197a962024-02-20 18:10:12 -080065void AsymmetricTrapezoidProfile::CalculateTimes(
66 double distance_to_target, double goal_velocity,
67 Eigen::Matrix<double, 2, 1> current) {
briansf0165ca2013-03-02 06:17:47 +000068 if (distance_to_target == 0) {
69 // We're there. Stop everything.
70 // TODO(aschuh): Deal with velocity not right.
71 acceleration_time_ = 0;
72 acceleration_ = 0;
73 constant_time_ = 0;
74 deceleration_time_ = 0;
75 deceleration_ = 0;
Austin Schuhe197a962024-02-20 18:10:12 -080076 deceleration_reversal_time_ = 0;
77 deceleration_reversal_ = 0;
briansf0165ca2013-03-02 06:17:47 +000078 return;
79 } else if (distance_to_target < 0) {
80 // Recurse with everything inverted.
Austin Schuhe197a962024-02-20 18:10:12 -080081 current(1) *= -1;
82 CalculateTimes(-distance_to_target, -goal_velocity, current);
briansf0165ca2013-03-02 06:17:47 +000083 acceleration_ *= -1;
84 deceleration_ *= -1;
Austin Schuhe197a962024-02-20 18:10:12 -080085 deceleration_reversal_ *= -1;
briansf0165ca2013-03-02 06:17:47 +000086 return;
87 }
88
89 constant_time_ = 0;
90 acceleration_ = maximum_acceleration_;
Austin Schuhe197a962024-02-20 18:10:12 -080091
92 // Calculate the fastest speed we could get going to by the distance to
93 // target. We will have normalized everything out to be a positive distance
94 // by now so we never have to deal with going "backwards".
Diana Vandenberg19bb9e22016-02-03 21:24:31 -080095 double maximum_acceleration_velocity =
96 distance_to_target * 2 * std::abs(acceleration_) +
Austin Schuhe197a962024-02-20 18:10:12 -080097 current(1) * current(1);
98 CHECK_GE(maximum_acceleration_velocity, 0);
99 maximum_acceleration_velocity = sqrt(maximum_acceleration_velocity);
briansf0165ca2013-03-02 06:17:47 +0000100
Austin Schuhe197a962024-02-20 18:10:12 -0800101 // If we could get going faster than the target, we will need to decelerate
102 // after accelerating.
briansf0165ca2013-03-02 06:17:47 +0000103 if (maximum_acceleration_velocity > goal_velocity) {
Austin Schuhe197a962024-02-20 18:10:12 -0800104 deceleration_ = -maximum_deceleration_;
briansf0165ca2013-03-02 06:17:47 +0000105 } else {
Austin Schuhe197a962024-02-20 18:10:12 -0800106 // We couldn't get up to speed by the destination. Set our decel to
107 // accelerate to keep accelerating to get up to speed.
108 //
109 // Note: goal_velocity != 0 isn't well tested, use at your own risk.
110 LOG(FATAL) << "Untested";
briansf0165ca2013-03-02 06:17:47 +0000111 deceleration_ = maximum_acceleration_;
112 }
113
Austin Schuhe197a962024-02-20 18:10:12 -0800114 // If we are going away from the goal, we will need to change directions.
115 if (current(1) < 0) {
116 deceleration_reversal_time_ = current(1) / deceleration_;
117 deceleration_reversal_ = -deceleration_;
118 } else if ((goal_velocity - current(1)) * (goal_velocity + current(1)) <
119 2.0 * deceleration_ * distance_to_target) {
120 // Then, can we stop in time if we get after it? If so, we don't need to
121 // decel first before running the profile.
122 deceleration_reversal_time_ = -current(1) / deceleration_;
123 deceleration_reversal_ = deceleration_;
124 } else {
125 // Otherwise, we are all good and don't need to handle reversing.
126 deceleration_reversal_time_ = 0.0;
127 deceleration_reversal_ = 0.0;
128 }
129
130 current(0) += current(1) * deceleration_reversal_time_ +
131 0.5 * deceleration_reversal_ * deceleration_reversal_time_ *
132 deceleration_reversal_time_;
133 current(1) += deceleration_reversal_ * deceleration_reversal_time_;
134 // OK, now we've compensated for slowing down.
135
briansf0165ca2013-03-02 06:17:47 +0000136 // We now know the top velocity we can get to.
Austin Schuhe197a962024-02-20 18:10:12 -0800137 const double top_velocity = sqrt(
138 (distance_to_target + (current(1) * current(1)) / (2.0 * acceleration_) +
James Kuszmaul651fc3f2019-05-15 21:14:25 -0700139 (goal_velocity * goal_velocity) / (2.0 * deceleration_)) /
140 (-1.0 / (2.0 * deceleration_) + 1.0 / (2.0 * acceleration_)));
briansf0165ca2013-03-02 06:17:47 +0000141
142 // If it can go too fast, we now know how long we get to accelerate for and
143 // how long to go at constant velocity.
144 if (top_velocity > maximum_velocity_) {
James Kuszmaul651fc3f2019-05-15 21:14:25 -0700145 acceleration_time_ =
Austin Schuhe197a962024-02-20 18:10:12 -0800146 (maximum_velocity_ - current(1)) / maximum_acceleration_;
Austin Schuhb3b799e2024-02-20 14:20:12 -0800147 constant_time_ = ((-0.5 * maximum_acceleration_ * acceleration_time_ *
148 acceleration_time_ -
Austin Schuhe197a962024-02-20 18:10:12 -0800149 current(1) * acceleration_time_) +
Austin Schuhb3b799e2024-02-20 14:20:12 -0800150 distance_to_target +
151 (goal_velocity * goal_velocity -
152 maximum_velocity_ * maximum_velocity_) /
Austin Schuhe197a962024-02-20 18:10:12 -0800153 (2.0 * maximum_deceleration_)) /
Austin Schuhb3b799e2024-02-20 14:20:12 -0800154 maximum_velocity_;
briansf0165ca2013-03-02 06:17:47 +0000155 } else {
Austin Schuhe197a962024-02-20 18:10:12 -0800156 acceleration_time_ = (top_velocity - current(1)) / acceleration_;
briansf0165ca2013-03-02 06:17:47 +0000157 }
158
Austin Schuhe197a962024-02-20 18:10:12 -0800159 CHECK_GT(top_velocity, -maximum_velocity_);
briansf0165ca2013-03-02 06:17:47 +0000160
Austin Schuhe197a962024-02-20 18:10:12 -0800161 if (current(1) > maximum_velocity_) {
Ben Fredricksonf33d6532015-03-15 00:29:29 -0700162 constant_time_ = 0;
163 acceleration_time_ = 0;
164 }
165
Austin Schuhb3b799e2024-02-20 14:20:12 -0800166 deceleration_time_ =
167 (goal_velocity - ::std::min(top_velocity, maximum_velocity_)) /
168 deceleration_;
Austin Schuhe197a962024-02-20 18:10:12 -0800169 if (acceleration_time_ <= 0) acceleration_time_ = 0;
Austin Schuhb3b799e2024-02-20 14:20:12 -0800170 if (constant_time_ <= 0) constant_time_ = 0;
171 if (deceleration_time_ <= 0) deceleration_time_ = 0;
briansf0165ca2013-03-02 06:17:47 +0000172}
173
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800174} // namespace aos::util