blob: be61889910b1038ab6bacd98ea355da0bd7ca4cd [file] [log] [blame]
John Park33858a32018-09-28 23:05:48 -07001#include "aos/util/trapezoid_profile.h"
briansf0165ca2013-03-02 06:17:47 +00002
Stephan Pleinesb1177672024-05-27 17:48:32 -07003#include <math.h>
4
5#include <algorithm>
6#include <cstdlib>
7#include <ostream>
8
Austin Schuhe197a962024-02-20 18:10:12 -08009#include "glog/logging.h"
briansf0165ca2013-03-02 06:17:47 +000010
Stephan Pleinesb1177672024-05-27 17:48:32 -070011#include "aos/time/time.h"
12
Stephan Pleinesf63bde82024-01-13 15:59:33 -080013namespace aos::util {
briansf0165ca2013-03-02 06:17:47 +000014
Austin Schuhe197a962024-02-20 18:10:12 -080015AsymmetricTrapezoidProfile::AsymmetricTrapezoidProfile(
16 ::std::chrono::nanoseconds delta_time)
17 : timestep_(delta_time) {
briansf0165ca2013-03-02 06:17:47 +000018 output_.setZero();
19}
20
Austin Schuhe197a962024-02-20 18:10:12 -080021void AsymmetricTrapezoidProfile::UpdateVals(double acceleration,
22 double delta_time) {
James Kuszmaul651fc3f2019-05-15 21:14:25 -070023 output_(0) +=
24 output_(1) * delta_time + 0.5 * acceleration * delta_time * delta_time;
briansf0165ca2013-03-02 06:17:47 +000025 output_(1) += acceleration * delta_time;
26}
27
Austin Schuhe197a962024-02-20 18:10:12 -080028const Eigen::Matrix<double, 2, 1> &AsymmetricTrapezoidProfile::Update(
29 double goal_position, double goal_velocity) {
30 CalculateTimes(goal_position - output_(0), goal_velocity, output_);
briansf0165ca2013-03-02 06:17:47 +000031
James Kuszmaul651fc3f2019-05-15 21:14:25 -070032 double next_timestep = ::aos::time::DurationInSeconds(timestep_);
briansf0165ca2013-03-02 06:17:47 +000033
Austin Schuhe197a962024-02-20 18:10:12 -080034 if (deceleration_reversal_time_ > next_timestep) {
35 UpdateVals(deceleration_reversal_, next_timestep);
36 return output_;
37 }
38
39 UpdateVals(deceleration_reversal_, deceleration_reversal_time_);
40 next_timestep -= deceleration_reversal_time_;
41
briansf0165ca2013-03-02 06:17:47 +000042 if (acceleration_time_ > next_timestep) {
43 UpdateVals(acceleration_, next_timestep);
Austin Schuhe197a962024-02-20 18:10:12 -080044 return output_;
45 }
briansf0165ca2013-03-02 06:17:47 +000046
Austin Schuhe197a962024-02-20 18:10:12 -080047 UpdateVals(acceleration_, acceleration_time_);
48 next_timestep -= acceleration_time_;
49
50 if (constant_time_ > next_timestep) {
51 UpdateVals(0, next_timestep);
52 return output_;
53 }
54
55 UpdateVals(0, constant_time_);
56 next_timestep -= constant_time_;
57 if (deceleration_time_ > next_timestep) {
58 UpdateVals(deceleration_, next_timestep);
59 } else {
60 UpdateVals(deceleration_, deceleration_time_);
61 next_timestep -= deceleration_time_;
62 UpdateVals(0, next_timestep);
63
64 if (next_timestep >= 0 && goal_velocity == 0) {
65 output_(0) = goal_position;
66 output_(1) = goal_velocity;
briansf0165ca2013-03-02 06:17:47 +000067 }
68 }
69
70 return output_;
71}
72
Austin Schuhe197a962024-02-20 18:10:12 -080073void AsymmetricTrapezoidProfile::CalculateTimes(
74 double distance_to_target, double goal_velocity,
75 Eigen::Matrix<double, 2, 1> current) {
briansf0165ca2013-03-02 06:17:47 +000076 if (distance_to_target == 0) {
77 // We're there. Stop everything.
78 // TODO(aschuh): Deal with velocity not right.
79 acceleration_time_ = 0;
80 acceleration_ = 0;
81 constant_time_ = 0;
82 deceleration_time_ = 0;
83 deceleration_ = 0;
Austin Schuhe197a962024-02-20 18:10:12 -080084 deceleration_reversal_time_ = 0;
85 deceleration_reversal_ = 0;
briansf0165ca2013-03-02 06:17:47 +000086 return;
87 } else if (distance_to_target < 0) {
88 // Recurse with everything inverted.
Austin Schuhe197a962024-02-20 18:10:12 -080089 current(1) *= -1;
90 CalculateTimes(-distance_to_target, -goal_velocity, current);
briansf0165ca2013-03-02 06:17:47 +000091 acceleration_ *= -1;
92 deceleration_ *= -1;
Austin Schuhe197a962024-02-20 18:10:12 -080093 deceleration_reversal_ *= -1;
briansf0165ca2013-03-02 06:17:47 +000094 return;
95 }
96
97 constant_time_ = 0;
98 acceleration_ = maximum_acceleration_;
Austin Schuhe197a962024-02-20 18:10:12 -080099
100 // Calculate the fastest speed we could get going to by the distance to
101 // target. We will have normalized everything out to be a positive distance
102 // by now so we never have to deal with going "backwards".
Diana Vandenberg19bb9e22016-02-03 21:24:31 -0800103 double maximum_acceleration_velocity =
104 distance_to_target * 2 * std::abs(acceleration_) +
Austin Schuhe197a962024-02-20 18:10:12 -0800105 current(1) * current(1);
106 CHECK_GE(maximum_acceleration_velocity, 0);
107 maximum_acceleration_velocity = sqrt(maximum_acceleration_velocity);
briansf0165ca2013-03-02 06:17:47 +0000108
Austin Schuhe197a962024-02-20 18:10:12 -0800109 // If we could get going faster than the target, we will need to decelerate
110 // after accelerating.
briansf0165ca2013-03-02 06:17:47 +0000111 if (maximum_acceleration_velocity > goal_velocity) {
Austin Schuhe197a962024-02-20 18:10:12 -0800112 deceleration_ = -maximum_deceleration_;
briansf0165ca2013-03-02 06:17:47 +0000113 } else {
Austin Schuhe197a962024-02-20 18:10:12 -0800114 // We couldn't get up to speed by the destination. Set our decel to
115 // accelerate to keep accelerating to get up to speed.
116 //
117 // Note: goal_velocity != 0 isn't well tested, use at your own risk.
118 LOG(FATAL) << "Untested";
briansf0165ca2013-03-02 06:17:47 +0000119 deceleration_ = maximum_acceleration_;
120 }
121
Austin Schuhe197a962024-02-20 18:10:12 -0800122 // If we are going away from the goal, we will need to change directions.
123 if (current(1) < 0) {
124 deceleration_reversal_time_ = current(1) / deceleration_;
125 deceleration_reversal_ = -deceleration_;
126 } else if ((goal_velocity - current(1)) * (goal_velocity + current(1)) <
127 2.0 * deceleration_ * distance_to_target) {
128 // Then, can we stop in time if we get after it? If so, we don't need to
129 // decel first before running the profile.
130 deceleration_reversal_time_ = -current(1) / deceleration_;
131 deceleration_reversal_ = deceleration_;
132 } else {
133 // Otherwise, we are all good and don't need to handle reversing.
134 deceleration_reversal_time_ = 0.0;
135 deceleration_reversal_ = 0.0;
136 }
137
138 current(0) += current(1) * deceleration_reversal_time_ +
139 0.5 * deceleration_reversal_ * deceleration_reversal_time_ *
140 deceleration_reversal_time_;
141 current(1) += deceleration_reversal_ * deceleration_reversal_time_;
142 // OK, now we've compensated for slowing down.
143
briansf0165ca2013-03-02 06:17:47 +0000144 // We now know the top velocity we can get to.
Austin Schuhe197a962024-02-20 18:10:12 -0800145 const double top_velocity = sqrt(
146 (distance_to_target + (current(1) * current(1)) / (2.0 * acceleration_) +
James Kuszmaul651fc3f2019-05-15 21:14:25 -0700147 (goal_velocity * goal_velocity) / (2.0 * deceleration_)) /
148 (-1.0 / (2.0 * deceleration_) + 1.0 / (2.0 * acceleration_)));
briansf0165ca2013-03-02 06:17:47 +0000149
150 // If it can go too fast, we now know how long we get to accelerate for and
151 // how long to go at constant velocity.
152 if (top_velocity > maximum_velocity_) {
James Kuszmaul651fc3f2019-05-15 21:14:25 -0700153 acceleration_time_ =
Austin Schuhe197a962024-02-20 18:10:12 -0800154 (maximum_velocity_ - current(1)) / maximum_acceleration_;
Austin Schuhb3b799e2024-02-20 14:20:12 -0800155 constant_time_ = ((-0.5 * maximum_acceleration_ * acceleration_time_ *
156 acceleration_time_ -
Austin Schuhe197a962024-02-20 18:10:12 -0800157 current(1) * acceleration_time_) +
Austin Schuhb3b799e2024-02-20 14:20:12 -0800158 distance_to_target +
159 (goal_velocity * goal_velocity -
160 maximum_velocity_ * maximum_velocity_) /
Austin Schuhe197a962024-02-20 18:10:12 -0800161 (2.0 * maximum_deceleration_)) /
Austin Schuhb3b799e2024-02-20 14:20:12 -0800162 maximum_velocity_;
briansf0165ca2013-03-02 06:17:47 +0000163 } else {
Austin Schuhe197a962024-02-20 18:10:12 -0800164 acceleration_time_ = (top_velocity - current(1)) / acceleration_;
briansf0165ca2013-03-02 06:17:47 +0000165 }
166
Austin Schuhe197a962024-02-20 18:10:12 -0800167 CHECK_GT(top_velocity, -maximum_velocity_);
briansf0165ca2013-03-02 06:17:47 +0000168
Austin Schuhe197a962024-02-20 18:10:12 -0800169 if (current(1) > maximum_velocity_) {
Ben Fredricksonf33d6532015-03-15 00:29:29 -0700170 constant_time_ = 0;
171 acceleration_time_ = 0;
172 }
173
Austin Schuhb3b799e2024-02-20 14:20:12 -0800174 deceleration_time_ =
175 (goal_velocity - ::std::min(top_velocity, maximum_velocity_)) /
176 deceleration_;
Austin Schuhe197a962024-02-20 18:10:12 -0800177 if (acceleration_time_ <= 0) acceleration_time_ = 0;
Austin Schuhb3b799e2024-02-20 14:20:12 -0800178 if (constant_time_ <= 0) constant_time_ = 0;
179 if (deceleration_time_ <= 0) deceleration_time_ = 0;
briansf0165ca2013-03-02 06:17:47 +0000180}
181
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800182} // namespace aos::util