blob: 4bd65fa0e54b6740e43ec5258675f69088aa065b [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 Schuh99f7c6a2024-06-25 22:07:44 -07009#include "absl/log/check.h"
10#include "absl/log/log.h"
briansf0165ca2013-03-02 06:17:47 +000011
Stephan Pleinesb1177672024-05-27 17:48:32 -070012#include "aos/time/time.h"
13
Stephan Pleinesf63bde82024-01-13 15:59:33 -080014namespace aos::util {
briansf0165ca2013-03-02 06:17:47 +000015
Austin Schuhe197a962024-02-20 18:10:12 -080016AsymmetricTrapezoidProfile::AsymmetricTrapezoidProfile(
17 ::std::chrono::nanoseconds delta_time)
18 : timestep_(delta_time) {
briansf0165ca2013-03-02 06:17:47 +000019 output_.setZero();
20}
21
Austin Schuhe197a962024-02-20 18:10:12 -080022void AsymmetricTrapezoidProfile::UpdateVals(double acceleration,
23 double delta_time) {
James Kuszmaul651fc3f2019-05-15 21:14:25 -070024 output_(0) +=
25 output_(1) * delta_time + 0.5 * acceleration * delta_time * delta_time;
briansf0165ca2013-03-02 06:17:47 +000026 output_(1) += acceleration * delta_time;
27}
28
Austin Schuhe197a962024-02-20 18:10:12 -080029const Eigen::Matrix<double, 2, 1> &AsymmetricTrapezoidProfile::Update(
30 double goal_position, double goal_velocity) {
31 CalculateTimes(goal_position - output_(0), goal_velocity, output_);
briansf0165ca2013-03-02 06:17:47 +000032
James Kuszmaul651fc3f2019-05-15 21:14:25 -070033 double next_timestep = ::aos::time::DurationInSeconds(timestep_);
briansf0165ca2013-03-02 06:17:47 +000034
Austin Schuhe197a962024-02-20 18:10:12 -080035 if (deceleration_reversal_time_ > next_timestep) {
36 UpdateVals(deceleration_reversal_, next_timestep);
37 return output_;
38 }
39
40 UpdateVals(deceleration_reversal_, deceleration_reversal_time_);
41 next_timestep -= deceleration_reversal_time_;
42
briansf0165ca2013-03-02 06:17:47 +000043 if (acceleration_time_ > next_timestep) {
44 UpdateVals(acceleration_, next_timestep);
Austin Schuhe197a962024-02-20 18:10:12 -080045 return output_;
46 }
briansf0165ca2013-03-02 06:17:47 +000047
Austin Schuhe197a962024-02-20 18:10:12 -080048 UpdateVals(acceleration_, acceleration_time_);
49 next_timestep -= acceleration_time_;
50
51 if (constant_time_ > next_timestep) {
52 UpdateVals(0, next_timestep);
53 return output_;
54 }
55
56 UpdateVals(0, constant_time_);
57 next_timestep -= constant_time_;
58 if (deceleration_time_ > next_timestep) {
59 UpdateVals(deceleration_, next_timestep);
60 } else {
61 UpdateVals(deceleration_, deceleration_time_);
62 next_timestep -= deceleration_time_;
63 UpdateVals(0, next_timestep);
64
65 if (next_timestep >= 0 && goal_velocity == 0) {
66 output_(0) = goal_position;
67 output_(1) = goal_velocity;
briansf0165ca2013-03-02 06:17:47 +000068 }
69 }
70
71 return output_;
72}
73
Austin Schuhe197a962024-02-20 18:10:12 -080074void AsymmetricTrapezoidProfile::CalculateTimes(
75 double distance_to_target, double goal_velocity,
76 Eigen::Matrix<double, 2, 1> current) {
briansf0165ca2013-03-02 06:17:47 +000077 if (distance_to_target == 0) {
78 // We're there. Stop everything.
79 // TODO(aschuh): Deal with velocity not right.
80 acceleration_time_ = 0;
81 acceleration_ = 0;
82 constant_time_ = 0;
83 deceleration_time_ = 0;
84 deceleration_ = 0;
Austin Schuhe197a962024-02-20 18:10:12 -080085 deceleration_reversal_time_ = 0;
86 deceleration_reversal_ = 0;
briansf0165ca2013-03-02 06:17:47 +000087 return;
88 } else if (distance_to_target < 0) {
89 // Recurse with everything inverted.
Austin Schuhe197a962024-02-20 18:10:12 -080090 current(1) *= -1;
91 CalculateTimes(-distance_to_target, -goal_velocity, current);
briansf0165ca2013-03-02 06:17:47 +000092 acceleration_ *= -1;
93 deceleration_ *= -1;
Austin Schuhe197a962024-02-20 18:10:12 -080094 deceleration_reversal_ *= -1;
briansf0165ca2013-03-02 06:17:47 +000095 return;
96 }
97
98 constant_time_ = 0;
99 acceleration_ = maximum_acceleration_;
Austin Schuhe197a962024-02-20 18:10:12 -0800100
101 // Calculate the fastest speed we could get going to by the distance to
102 // target. We will have normalized everything out to be a positive distance
103 // by now so we never have to deal with going "backwards".
Diana Vandenberg19bb9e22016-02-03 21:24:31 -0800104 double maximum_acceleration_velocity =
105 distance_to_target * 2 * std::abs(acceleration_) +
Austin Schuhe197a962024-02-20 18:10:12 -0800106 current(1) * current(1);
107 CHECK_GE(maximum_acceleration_velocity, 0);
108 maximum_acceleration_velocity = sqrt(maximum_acceleration_velocity);
briansf0165ca2013-03-02 06:17:47 +0000109
Austin Schuhe197a962024-02-20 18:10:12 -0800110 // If we could get going faster than the target, we will need to decelerate
111 // after accelerating.
briansf0165ca2013-03-02 06:17:47 +0000112 if (maximum_acceleration_velocity > goal_velocity) {
Austin Schuhe197a962024-02-20 18:10:12 -0800113 deceleration_ = -maximum_deceleration_;
briansf0165ca2013-03-02 06:17:47 +0000114 } else {
Austin Schuhe197a962024-02-20 18:10:12 -0800115 // We couldn't get up to speed by the destination. Set our decel to
116 // accelerate to keep accelerating to get up to speed.
117 //
118 // Note: goal_velocity != 0 isn't well tested, use at your own risk.
119 LOG(FATAL) << "Untested";
briansf0165ca2013-03-02 06:17:47 +0000120 deceleration_ = maximum_acceleration_;
121 }
122
Austin Schuhe197a962024-02-20 18:10:12 -0800123 // If we are going away from the goal, we will need to change directions.
124 if (current(1) < 0) {
125 deceleration_reversal_time_ = current(1) / deceleration_;
126 deceleration_reversal_ = -deceleration_;
127 } else if ((goal_velocity - current(1)) * (goal_velocity + current(1)) <
128 2.0 * deceleration_ * distance_to_target) {
129 // Then, can we stop in time if we get after it? If so, we don't need to
130 // decel first before running the profile.
131 deceleration_reversal_time_ = -current(1) / deceleration_;
132 deceleration_reversal_ = deceleration_;
133 } else {
134 // Otherwise, we are all good and don't need to handle reversing.
135 deceleration_reversal_time_ = 0.0;
136 deceleration_reversal_ = 0.0;
137 }
138
139 current(0) += current(1) * deceleration_reversal_time_ +
140 0.5 * deceleration_reversal_ * deceleration_reversal_time_ *
141 deceleration_reversal_time_;
142 current(1) += deceleration_reversal_ * deceleration_reversal_time_;
143 // OK, now we've compensated for slowing down.
144
briansf0165ca2013-03-02 06:17:47 +0000145 // We now know the top velocity we can get to.
Austin Schuhe197a962024-02-20 18:10:12 -0800146 const double top_velocity = sqrt(
147 (distance_to_target + (current(1) * current(1)) / (2.0 * acceleration_) +
James Kuszmaul651fc3f2019-05-15 21:14:25 -0700148 (goal_velocity * goal_velocity) / (2.0 * deceleration_)) /
149 (-1.0 / (2.0 * deceleration_) + 1.0 / (2.0 * acceleration_)));
briansf0165ca2013-03-02 06:17:47 +0000150
151 // If it can go too fast, we now know how long we get to accelerate for and
152 // how long to go at constant velocity.
153 if (top_velocity > maximum_velocity_) {
James Kuszmaul651fc3f2019-05-15 21:14:25 -0700154 acceleration_time_ =
Austin Schuhe197a962024-02-20 18:10:12 -0800155 (maximum_velocity_ - current(1)) / maximum_acceleration_;
Austin Schuhb3b799e2024-02-20 14:20:12 -0800156 constant_time_ = ((-0.5 * maximum_acceleration_ * acceleration_time_ *
157 acceleration_time_ -
Austin Schuhe197a962024-02-20 18:10:12 -0800158 current(1) * acceleration_time_) +
Austin Schuhb3b799e2024-02-20 14:20:12 -0800159 distance_to_target +
160 (goal_velocity * goal_velocity -
161 maximum_velocity_ * maximum_velocity_) /
Austin Schuhe197a962024-02-20 18:10:12 -0800162 (2.0 * maximum_deceleration_)) /
Austin Schuhb3b799e2024-02-20 14:20:12 -0800163 maximum_velocity_;
briansf0165ca2013-03-02 06:17:47 +0000164 } else {
Austin Schuhe197a962024-02-20 18:10:12 -0800165 acceleration_time_ = (top_velocity - current(1)) / acceleration_;
briansf0165ca2013-03-02 06:17:47 +0000166 }
167
Austin Schuhe197a962024-02-20 18:10:12 -0800168 CHECK_GT(top_velocity, -maximum_velocity_);
briansf0165ca2013-03-02 06:17:47 +0000169
Austin Schuhe197a962024-02-20 18:10:12 -0800170 if (current(1) > maximum_velocity_) {
Ben Fredricksonf33d6532015-03-15 00:29:29 -0700171 constant_time_ = 0;
172 acceleration_time_ = 0;
173 }
174
Austin Schuhb3b799e2024-02-20 14:20:12 -0800175 deceleration_time_ =
176 (goal_velocity - ::std::min(top_velocity, maximum_velocity_)) /
177 deceleration_;
Austin Schuhe197a962024-02-20 18:10:12 -0800178 if (acceleration_time_ <= 0) acceleration_time_ = 0;
Austin Schuhb3b799e2024-02-20 14:20:12 -0800179 if (constant_time_ <= 0) constant_time_ = 0;
180 if (deceleration_time_ <= 0) deceleration_time_ = 0;
briansf0165ca2013-03-02 06:17:47 +0000181}
182
Stephan Pleinesf63bde82024-01-13 15:59:33 -0800183} // namespace aos::util