brians | f0165ca | 2013-03-02 06:17:47 +0000 | [diff] [blame] | 1 | #include "aos/common/util/trapezoid_profile.h" |
| 2 | |
| 3 | #include <assert.h> |
| 4 | |
Brian Silverman | 38ea9bf | 2014-04-19 22:57:54 -0700 | [diff] [blame^] | 5 | #include "aos/common/logging/logging.h" |
| 6 | |
brians | f0165ca | 2013-03-02 06:17:47 +0000 | [diff] [blame] | 7 | using ::Eigen::Matrix; |
| 8 | |
| 9 | namespace aos { |
| 10 | namespace util { |
| 11 | |
| 12 | TrapezoidProfile::TrapezoidProfile(const time::Time &delta_time) |
| 13 | : maximum_acceleration_(0), |
| 14 | maximum_velocity_(0), |
| 15 | timestep_(delta_time) { |
| 16 | output_.setZero(); |
| 17 | } |
| 18 | |
| 19 | void 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 | |
| 26 | const 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 | |
| 57 | void 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 |