brians | f0165ca | 2013-03-02 06:17:47 +0000 | [diff] [blame] | 1 | #include "aos/common/util/trapezoid_profile.h" |
| 2 | |
Brian Silverman | 38ea9bf | 2014-04-19 22:57:54 -0700 | [diff] [blame] | 3 | #include "aos/common/logging/logging.h" |
| 4 | |
brians | f0165ca | 2013-03-02 06:17:47 +0000 | [diff] [blame] | 5 | using ::Eigen::Matrix; |
| 6 | |
| 7 | namespace aos { |
| 8 | namespace util { |
| 9 | |
| 10 | TrapezoidProfile::TrapezoidProfile(const time::Time &delta_time) |
| 11 | : maximum_acceleration_(0), |
| 12 | maximum_velocity_(0), |
| 13 | timestep_(delta_time) { |
| 14 | output_.setZero(); |
| 15 | } |
| 16 | |
| 17 | void TrapezoidProfile::UpdateVals(double acceleration, |
| 18 | double delta_time) { |
| 19 | output_(0) += output_(1) * delta_time + |
| 20 | 0.5 * acceleration * delta_time * delta_time; |
| 21 | output_(1) += acceleration * delta_time; |
| 22 | } |
| 23 | |
| 24 | const Matrix<double, 2, 1> &TrapezoidProfile::Update( |
| 25 | double goal_position, |
| 26 | double goal_velocity) { |
| 27 | CalculateTimes(goal_position - output_(0), goal_velocity); |
| 28 | |
| 29 | double next_timestep = timestep_.ToSeconds(); |
| 30 | |
| 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 | |
| 55 | void 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; |
| 69 | CalculateTimes(-distance_to_target, |
| 70 | -goal_velocity); |
| 71 | output_(1) *= -1; |
| 72 | acceleration_ *= -1; |
| 73 | deceleration_ *= -1; |
| 74 | return; |
| 75 | } |
| 76 | |
| 77 | constant_time_ = 0; |
| 78 | acceleration_ = maximum_acceleration_; |
| 79 | double maximum_acceleration_velocity = distance_to_target * 2 * |
| 80 | std::abs(acceleration_) + output_(1) * output_(1); |
| 81 | 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 Silverman | fe457de | 2014-05-26 22:04:08 -0700 | [diff] [blame] | 118 | CHECK_GT(top_velocity, -maximum_velocity_); |
brians | f0165ca | 2013-03-02 06:17:47 +0000 | [diff] [blame] | 119 | |
| 120 | deceleration_time_ = (goal_velocity - top_velocity) / |
| 121 | deceleration_; |
| 122 | } |
| 123 | |
| 124 | } // namespace util |
| 125 | } // namespace aos |