blob: e58324f5889b8c3889d31340b309c4002e0a58d6 [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
15void TrapezoidProfile::UpdateVals(double acceleration,
16 double delta_time) {
17 output_(0) += output_(1) * delta_time +
18 0.5 * acceleration * delta_time * delta_time;
19 output_(1) += acceleration * delta_time;
20}
21
22const Matrix<double, 2, 1> &TrapezoidProfile::Update(
23 double goal_position,
24 double goal_velocity) {
25 CalculateTimes(goal_position - output_(0), goal_velocity);
26
Austin Schuh214e9c12016-11-25 17:26:20 -080027 double next_timestep =
28 ::std::chrono::duration_cast<::std::chrono::duration<double>>(timestep_)
29 .count();
briansf0165ca2013-03-02 06:17:47 +000030
31 if (acceleration_time_ > next_timestep) {
32 UpdateVals(acceleration_, next_timestep);
33 } else {
34 UpdateVals(acceleration_, acceleration_time_);
35
36 next_timestep -= acceleration_time_;
37 if (constant_time_ > next_timestep) {
38 UpdateVals(0, next_timestep);
39 } else {
40 UpdateVals(0, constant_time_);
41 next_timestep -= constant_time_;
42 if (deceleration_time_ > next_timestep) {
43 UpdateVals(deceleration_, next_timestep);
44 } else {
45 UpdateVals(deceleration_, deceleration_time_);
46 next_timestep -= deceleration_time_;
47 UpdateVals(0, next_timestep);
48 }
49 }
50 }
51
52 return output_;
53}
54
55void TrapezoidProfile::CalculateTimes(double distance_to_target,
56 double goal_velocity) {
57 if (distance_to_target == 0) {
58 // We're there. Stop everything.
59 // TODO(aschuh): Deal with velocity not right.
60 acceleration_time_ = 0;
61 acceleration_ = 0;
62 constant_time_ = 0;
63 deceleration_time_ = 0;
64 deceleration_ = 0;
65 return;
66 } else if (distance_to_target < 0) {
67 // Recurse with everything inverted.
68 output_(1) *= -1;
Diana Vandenberg19bb9e22016-02-03 21:24:31 -080069 CalculateTimes(-distance_to_target, -goal_velocity);
briansf0165ca2013-03-02 06:17:47 +000070 output_(1) *= -1;
71 acceleration_ *= -1;
72 deceleration_ *= -1;
73 return;
74 }
75
76 constant_time_ = 0;
77 acceleration_ = maximum_acceleration_;
Diana Vandenberg19bb9e22016-02-03 21:24:31 -080078 double maximum_acceleration_velocity =
79 distance_to_target * 2 * std::abs(acceleration_) +
80 output_(1) * output_(1);
briansf0165ca2013-03-02 06:17:47 +000081 if (maximum_acceleration_velocity > 0) {
82 maximum_acceleration_velocity = sqrt(maximum_acceleration_velocity);
83 } else {
84 maximum_acceleration_velocity = -sqrt(-maximum_acceleration_velocity);
85 }
86
87 // Since we know what we'd have to do if we kept after it to decelerate, we
88 // know the sign of the acceleration.
89 if (maximum_acceleration_velocity > goal_velocity) {
90 deceleration_ = -maximum_acceleration_;
91 } else {
92 deceleration_ = maximum_acceleration_;
93 }
94
95 // We now know the top velocity we can get to.
96 double top_velocity = sqrt((distance_to_target +
97 (output_(1) * output_(1)) /
98 (2.0 * acceleration_) +
99 (goal_velocity * goal_velocity) /
100 (2.0 * deceleration_)) /
101 (-1.0 / (2.0 * deceleration_) +
102 1.0 / (2.0 * acceleration_)));
103
104 // If it can go too fast, we now know how long we get to accelerate for and
105 // how long to go at constant velocity.
106 if (top_velocity > maximum_velocity_) {
107 acceleration_time_ = (maximum_velocity_ - output_(1)) /
108 maximum_acceleration_;
109 constant_time_ = (distance_to_target +
110 (goal_velocity * goal_velocity -
111 maximum_velocity_ * maximum_velocity_) /
112 (2.0 * maximum_acceleration_)) / maximum_velocity_;
113 } else {
114 acceleration_time_ = (top_velocity - output_(1)) /
115 acceleration_;
116 }
117
Brian Silvermanfe457de2014-05-26 22:04:08 -0700118 CHECK_GT(top_velocity, -maximum_velocity_);
briansf0165ca2013-03-02 06:17:47 +0000119
Ben Fredricksonf33d6532015-03-15 00:29:29 -0700120 if (output_(1) > maximum_velocity_) {
121 constant_time_ = 0;
122 acceleration_time_ = 0;
123 }
124
briansf0165ca2013-03-02 06:17:47 +0000125 deceleration_time_ = (goal_velocity - top_velocity) /
126 deceleration_;
127}
128
129} // namespace util
130} // namespace aos