blob: 4c5f07d5332af87d00b4d0ab9472a1d12abd49ed [file] [log] [blame]
briansf0165ca2013-03-02 06:17:47 +00001#include "aos/common/util/trapezoid_profile.h"
2
3#include <assert.h>
4
Brian Silverman38ea9bf2014-04-19 22:57:54 -07005#include "aos/common/logging/logging.h"
6
briansf0165ca2013-03-02 06:17:47 +00007using ::Eigen::Matrix;
8
9namespace aos {
10namespace util {
11
12TrapezoidProfile::TrapezoidProfile(const time::Time &delta_time)
13 : maximum_acceleration_(0),
14 maximum_velocity_(0),
15 timestep_(delta_time) {
16 output_.setZero();
17}
18
19void TrapezoidProfile::UpdateVals(double acceleration,
20 double delta_time) {
21 output_(0) += output_(1) * delta_time +
22 0.5 * acceleration * delta_time * delta_time;
23 output_(1) += acceleration * delta_time;
24}
25
26const Matrix<double, 2, 1> &TrapezoidProfile::Update(
27 double goal_position,
28 double goal_velocity) {
29 CalculateTimes(goal_position - output_(0), goal_velocity);
30
31 double next_timestep = timestep_.ToSeconds();
32
33 if (acceleration_time_ > next_timestep) {
34 UpdateVals(acceleration_, next_timestep);
35 } else {
36 UpdateVals(acceleration_, acceleration_time_);
37
38 next_timestep -= acceleration_time_;
39 if (constant_time_ > next_timestep) {
40 UpdateVals(0, next_timestep);
41 } else {
42 UpdateVals(0, constant_time_);
43 next_timestep -= constant_time_;
44 if (deceleration_time_ > next_timestep) {
45 UpdateVals(deceleration_, next_timestep);
46 } else {
47 UpdateVals(deceleration_, deceleration_time_);
48 next_timestep -= deceleration_time_;
49 UpdateVals(0, next_timestep);
50 }
51 }
52 }
53
54 return output_;
55}
56
57void TrapezoidProfile::CalculateTimes(double distance_to_target,
58 double goal_velocity) {
59 if (distance_to_target == 0) {
60 // We're there. Stop everything.
61 // TODO(aschuh): Deal with velocity not right.
62 acceleration_time_ = 0;
63 acceleration_ = 0;
64 constant_time_ = 0;
65 deceleration_time_ = 0;
66 deceleration_ = 0;
67 return;
68 } else if (distance_to_target < 0) {
69 // Recurse with everything inverted.
70 output_(1) *= -1;
71 CalculateTimes(-distance_to_target,
72 -goal_velocity);
73 output_(1) *= -1;
74 acceleration_ *= -1;
75 deceleration_ *= -1;
76 return;
77 }
78
79 constant_time_ = 0;
80 acceleration_ = maximum_acceleration_;
81 double maximum_acceleration_velocity = distance_to_target * 2 *
82 std::abs(acceleration_) + output_(1) * output_(1);
83 if (maximum_acceleration_velocity > 0) {
84 maximum_acceleration_velocity = sqrt(maximum_acceleration_velocity);
85 } else {
86 maximum_acceleration_velocity = -sqrt(-maximum_acceleration_velocity);
87 }
88
89 // Since we know what we'd have to do if we kept after it to decelerate, we
90 // know the sign of the acceleration.
91 if (maximum_acceleration_velocity > goal_velocity) {
92 deceleration_ = -maximum_acceleration_;
93 } else {
94 deceleration_ = maximum_acceleration_;
95 }
96
97 // We now know the top velocity we can get to.
98 double top_velocity = sqrt((distance_to_target +
99 (output_(1) * output_(1)) /
100 (2.0 * acceleration_) +
101 (goal_velocity * goal_velocity) /
102 (2.0 * deceleration_)) /
103 (-1.0 / (2.0 * deceleration_) +
104 1.0 / (2.0 * acceleration_)));
105
106 // If it can go too fast, we now know how long we get to accelerate for and
107 // how long to go at constant velocity.
108 if (top_velocity > maximum_velocity_) {
109 acceleration_time_ = (maximum_velocity_ - output_(1)) /
110 maximum_acceleration_;
111 constant_time_ = (distance_to_target +
112 (goal_velocity * goal_velocity -
113 maximum_velocity_ * maximum_velocity_) /
114 (2.0 * maximum_acceleration_)) / maximum_velocity_;
115 } else {
116 acceleration_time_ = (top_velocity - output_(1)) /
117 acceleration_;
118 }
119
120 assert(top_velocity > -maximum_velocity_);
121
122 deceleration_time_ = (goal_velocity - top_velocity) /
123 deceleration_;
124}
125
126} // namespace util
127} // namespace aos