John Park | 33858a3 | 2018-09-28 23:05:48 -0700 | [diff] [blame] | 1 | #include "aos/util/trapezoid_profile.h" |
brians | f0165ca | 2013-03-02 06:17:47 +0000 | [diff] [blame] | 2 | |
John Park | 33858a3 | 2018-09-28 23:05:48 -0700 | [diff] [blame] | 3 | #include "aos/logging/logging.h" |
Brian Silverman | 38ea9bf | 2014-04-19 22:57:54 -0700 | [diff] [blame] | 4 | |
brians | f0165ca | 2013-03-02 06:17:47 +0000 | [diff] [blame] | 5 | using ::Eigen::Matrix; |
| 6 | |
Stephan Pleines | f63bde8 | 2024-01-13 15:59:33 -0800 | [diff] [blame^] | 7 | namespace aos::util { |
brians | f0165ca | 2013-03-02 06:17:47 +0000 | [diff] [blame] | 8 | |
Austin Schuh | 214e9c1 | 2016-11-25 17:26:20 -0800 | [diff] [blame] | 9 | TrapezoidProfile::TrapezoidProfile(::std::chrono::nanoseconds delta_time) |
| 10 | : maximum_acceleration_(0), maximum_velocity_(0), timestep_(delta_time) { |
brians | f0165ca | 2013-03-02 06:17:47 +0000 | [diff] [blame] | 11 | output_.setZero(); |
| 12 | } |
| 13 | |
James Kuszmaul | 651fc3f | 2019-05-15 21:14:25 -0700 | [diff] [blame] | 14 | void TrapezoidProfile::UpdateVals(double acceleration, double delta_time) { |
| 15 | output_(0) += |
| 16 | output_(1) * delta_time + 0.5 * acceleration * delta_time * delta_time; |
brians | f0165ca | 2013-03-02 06:17:47 +0000 | [diff] [blame] | 17 | output_(1) += acceleration * delta_time; |
| 18 | } |
| 19 | |
James Kuszmaul | 651fc3f | 2019-05-15 21:14:25 -0700 | [diff] [blame] | 20 | const Matrix<double, 2, 1> &TrapezoidProfile::Update(double goal_position, |
| 21 | double goal_velocity) { |
brians | f0165ca | 2013-03-02 06:17:47 +0000 | [diff] [blame] | 22 | CalculateTimes(goal_position - output_(0), goal_velocity); |
| 23 | |
James Kuszmaul | 651fc3f | 2019-05-15 21:14:25 -0700 | [diff] [blame] | 24 | double next_timestep = ::aos::time::DurationInSeconds(timestep_); |
brians | f0165ca | 2013-03-02 06:17:47 +0000 | [diff] [blame] | 25 | |
| 26 | if (acceleration_time_ > next_timestep) { |
| 27 | UpdateVals(acceleration_, next_timestep); |
| 28 | } else { |
| 29 | UpdateVals(acceleration_, acceleration_time_); |
| 30 | |
| 31 | next_timestep -= acceleration_time_; |
| 32 | if (constant_time_ > next_timestep) { |
| 33 | UpdateVals(0, next_timestep); |
| 34 | } else { |
| 35 | UpdateVals(0, constant_time_); |
| 36 | next_timestep -= constant_time_; |
| 37 | if (deceleration_time_ > next_timestep) { |
| 38 | UpdateVals(deceleration_, next_timestep); |
| 39 | } else { |
| 40 | UpdateVals(deceleration_, deceleration_time_); |
| 41 | next_timestep -= deceleration_time_; |
| 42 | UpdateVals(0, next_timestep); |
| 43 | } |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | return output_; |
| 48 | } |
| 49 | |
| 50 | void TrapezoidProfile::CalculateTimes(double distance_to_target, |
| 51 | double goal_velocity) { |
| 52 | if (distance_to_target == 0) { |
| 53 | // We're there. Stop everything. |
| 54 | // TODO(aschuh): Deal with velocity not right. |
| 55 | acceleration_time_ = 0; |
| 56 | acceleration_ = 0; |
| 57 | constant_time_ = 0; |
| 58 | deceleration_time_ = 0; |
| 59 | deceleration_ = 0; |
| 60 | return; |
| 61 | } else if (distance_to_target < 0) { |
| 62 | // Recurse with everything inverted. |
| 63 | output_(1) *= -1; |
Diana Vandenberg | 19bb9e2 | 2016-02-03 21:24:31 -0800 | [diff] [blame] | 64 | CalculateTimes(-distance_to_target, -goal_velocity); |
brians | f0165ca | 2013-03-02 06:17:47 +0000 | [diff] [blame] | 65 | output_(1) *= -1; |
| 66 | acceleration_ *= -1; |
| 67 | deceleration_ *= -1; |
| 68 | return; |
| 69 | } |
| 70 | |
| 71 | constant_time_ = 0; |
| 72 | acceleration_ = maximum_acceleration_; |
Diana Vandenberg | 19bb9e2 | 2016-02-03 21:24:31 -0800 | [diff] [blame] | 73 | double maximum_acceleration_velocity = |
| 74 | distance_to_target * 2 * std::abs(acceleration_) + |
| 75 | output_(1) * output_(1); |
brians | f0165ca | 2013-03-02 06:17:47 +0000 | [diff] [blame] | 76 | if (maximum_acceleration_velocity > 0) { |
| 77 | maximum_acceleration_velocity = sqrt(maximum_acceleration_velocity); |
| 78 | } else { |
| 79 | maximum_acceleration_velocity = -sqrt(-maximum_acceleration_velocity); |
| 80 | } |
| 81 | |
| 82 | // Since we know what we'd have to do if we kept after it to decelerate, we |
| 83 | // know the sign of the acceleration. |
| 84 | if (maximum_acceleration_velocity > goal_velocity) { |
| 85 | deceleration_ = -maximum_acceleration_; |
| 86 | } else { |
| 87 | deceleration_ = maximum_acceleration_; |
| 88 | } |
| 89 | |
| 90 | // We now know the top velocity we can get to. |
James Kuszmaul | 651fc3f | 2019-05-15 21:14:25 -0700 | [diff] [blame] | 91 | double top_velocity = sqrt( |
| 92 | (distance_to_target + (output_(1) * output_(1)) / (2.0 * acceleration_) + |
| 93 | (goal_velocity * goal_velocity) / (2.0 * deceleration_)) / |
| 94 | (-1.0 / (2.0 * deceleration_) + 1.0 / (2.0 * acceleration_))); |
brians | f0165ca | 2013-03-02 06:17:47 +0000 | [diff] [blame] | 95 | |
| 96 | // If it can go too fast, we now know how long we get to accelerate for and |
| 97 | // how long to go at constant velocity. |
| 98 | if (top_velocity > maximum_velocity_) { |
James Kuszmaul | 651fc3f | 2019-05-15 21:14:25 -0700 | [diff] [blame] | 99 | acceleration_time_ = |
| 100 | (maximum_velocity_ - output_(1)) / maximum_acceleration_; |
| 101 | constant_time_ = |
| 102 | (distance_to_target + (goal_velocity * goal_velocity - |
| 103 | maximum_velocity_ * maximum_velocity_) / |
| 104 | (2.0 * maximum_acceleration_)) / |
| 105 | maximum_velocity_; |
brians | f0165ca | 2013-03-02 06:17:47 +0000 | [diff] [blame] | 106 | } else { |
James Kuszmaul | 651fc3f | 2019-05-15 21:14:25 -0700 | [diff] [blame] | 107 | acceleration_time_ = (top_velocity - output_(1)) / acceleration_; |
brians | f0165ca | 2013-03-02 06:17:47 +0000 | [diff] [blame] | 108 | } |
| 109 | |
Austin Schuh | f257f3c | 2019-10-27 21:00:43 -0700 | [diff] [blame] | 110 | AOS_CHECK_GT(top_velocity, -maximum_velocity_); |
brians | f0165ca | 2013-03-02 06:17:47 +0000 | [diff] [blame] | 111 | |
Ben Fredrickson | f33d653 | 2015-03-15 00:29:29 -0700 | [diff] [blame] | 112 | if (output_(1) > maximum_velocity_) { |
| 113 | constant_time_ = 0; |
| 114 | acceleration_time_ = 0; |
| 115 | } |
| 116 | |
James Kuszmaul | 651fc3f | 2019-05-15 21:14:25 -0700 | [diff] [blame] | 117 | deceleration_time_ = (goal_velocity - top_velocity) / deceleration_; |
brians | f0165ca | 2013-03-02 06:17:47 +0000 | [diff] [blame] | 118 | } |
| 119 | |
Stephan Pleines | f63bde8 | 2024-01-13 15:59:33 -0800 | [diff] [blame^] | 120 | } // namespace aos::util |