blob: a1e8abb9b4b5044a03942df4af15037674c61e4b [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
7namespace aos {
8namespace util {
9
Austin Schuh214e9c12016-11-25 17:26:20 -080010TrapezoidProfile::TrapezoidProfile(::std::chrono::nanoseconds delta_time)
11 : maximum_acceleration_(0), maximum_velocity_(0), timestep_(delta_time) {
briansf0165ca2013-03-02 06:17:47 +000012 output_.setZero();
13}
14
James Kuszmaul651fc3f2019-05-15 21:14:25 -070015void TrapezoidProfile::UpdateVals(double acceleration, double delta_time) {
16 output_(0) +=
17 output_(1) * delta_time + 0.5 * acceleration * delta_time * delta_time;
briansf0165ca2013-03-02 06:17:47 +000018 output_(1) += acceleration * delta_time;
19}
20
James Kuszmaul651fc3f2019-05-15 21:14:25 -070021const Matrix<double, 2, 1> &TrapezoidProfile::Update(double goal_position,
22 double goal_velocity) {
briansf0165ca2013-03-02 06:17:47 +000023 CalculateTimes(goal_position - output_(0), goal_velocity);
24
James Kuszmaul651fc3f2019-05-15 21:14:25 -070025 double next_timestep = ::aos::time::DurationInSeconds(timestep_);
briansf0165ca2013-03-02 06:17:47 +000026
27 if (acceleration_time_ > next_timestep) {
28 UpdateVals(acceleration_, next_timestep);
29 } else {
30 UpdateVals(acceleration_, acceleration_time_);
31
32 next_timestep -= acceleration_time_;
33 if (constant_time_ > next_timestep) {
34 UpdateVals(0, next_timestep);
35 } else {
36 UpdateVals(0, constant_time_);
37 next_timestep -= constant_time_;
38 if (deceleration_time_ > next_timestep) {
39 UpdateVals(deceleration_, next_timestep);
40 } else {
41 UpdateVals(deceleration_, deceleration_time_);
42 next_timestep -= deceleration_time_;
43 UpdateVals(0, next_timestep);
44 }
45 }
46 }
47
48 return output_;
49}
50
51void TrapezoidProfile::CalculateTimes(double distance_to_target,
52 double goal_velocity) {
53 if (distance_to_target == 0) {
54 // We're there. Stop everything.
55 // TODO(aschuh): Deal with velocity not right.
56 acceleration_time_ = 0;
57 acceleration_ = 0;
58 constant_time_ = 0;
59 deceleration_time_ = 0;
60 deceleration_ = 0;
61 return;
62 } else if (distance_to_target < 0) {
63 // Recurse with everything inverted.
64 output_(1) *= -1;
Diana Vandenberg19bb9e22016-02-03 21:24:31 -080065 CalculateTimes(-distance_to_target, -goal_velocity);
briansf0165ca2013-03-02 06:17:47 +000066 output_(1) *= -1;
67 acceleration_ *= -1;
68 deceleration_ *= -1;
69 return;
70 }
71
72 constant_time_ = 0;
73 acceleration_ = maximum_acceleration_;
Diana Vandenberg19bb9e22016-02-03 21:24:31 -080074 double maximum_acceleration_velocity =
75 distance_to_target * 2 * std::abs(acceleration_) +
76 output_(1) * output_(1);
briansf0165ca2013-03-02 06:17:47 +000077 if (maximum_acceleration_velocity > 0) {
78 maximum_acceleration_velocity = sqrt(maximum_acceleration_velocity);
79 } else {
80 maximum_acceleration_velocity = -sqrt(-maximum_acceleration_velocity);
81 }
82
83 // Since we know what we'd have to do if we kept after it to decelerate, we
84 // know the sign of the acceleration.
85 if (maximum_acceleration_velocity > goal_velocity) {
86 deceleration_ = -maximum_acceleration_;
87 } else {
88 deceleration_ = maximum_acceleration_;
89 }
90
91 // We now know the top velocity we can get to.
James Kuszmaul651fc3f2019-05-15 21:14:25 -070092 double top_velocity = sqrt(
93 (distance_to_target + (output_(1) * output_(1)) / (2.0 * acceleration_) +
94 (goal_velocity * goal_velocity) / (2.0 * deceleration_)) /
95 (-1.0 / (2.0 * deceleration_) + 1.0 / (2.0 * acceleration_)));
briansf0165ca2013-03-02 06:17:47 +000096
97 // If it can go too fast, we now know how long we get to accelerate for and
98 // how long to go at constant velocity.
99 if (top_velocity > maximum_velocity_) {
James Kuszmaul651fc3f2019-05-15 21:14:25 -0700100 acceleration_time_ =
101 (maximum_velocity_ - output_(1)) / maximum_acceleration_;
102 constant_time_ =
103 (distance_to_target + (goal_velocity * goal_velocity -
104 maximum_velocity_ * maximum_velocity_) /
105 (2.0 * maximum_acceleration_)) /
106 maximum_velocity_;
briansf0165ca2013-03-02 06:17:47 +0000107 } else {
James Kuszmaul651fc3f2019-05-15 21:14:25 -0700108 acceleration_time_ = (top_velocity - output_(1)) / acceleration_;
briansf0165ca2013-03-02 06:17:47 +0000109 }
110
Brian Silvermanfe457de2014-05-26 22:04:08 -0700111 CHECK_GT(top_velocity, -maximum_velocity_);
briansf0165ca2013-03-02 06:17:47 +0000112
Ben Fredricksonf33d6532015-03-15 00:29:29 -0700113 if (output_(1) > maximum_velocity_) {
114 constant_time_ = 0;
115 acceleration_time_ = 0;
116 }
117
James Kuszmaul651fc3f2019-05-15 21:14:25 -0700118 deceleration_time_ = (goal_velocity - top_velocity) / deceleration_;
briansf0165ca2013-03-02 06:17:47 +0000119}
120
121} // namespace util
122} // namespace aos