PX4 Firmware
PX4 Autopilot Software http://px4.io
VelocitySmoothing.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2018-2019 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 #include "VelocitySmoothing.hpp"
35 
36 #include <cstdio>
37 #include <float.h>
38 #include <mathlib/mathlib.h>
39 
40 VelocitySmoothing::VelocitySmoothing(float initial_accel, float initial_vel, float initial_pos)
41 {
42  reset(initial_accel, initial_vel, initial_pos);
43 }
44 
45 void VelocitySmoothing::reset(float accel, float vel, float pos)
46 {
47  _state.j = 0.f;
48  _state.a = accel;
49  _state.v = vel;
50  _state.x = pos;
51 
53 }
54 
55 float VelocitySmoothing::saturateT1ForAccel(float a0, float j_max, float T1, float a_max)
56 {
57  /* Check maximum acceleration, saturate and recompute T1 if needed */
58  float accel_T1 = a0 + j_max * T1;
59  float T1_new = T1;
60 
61  if (accel_T1 > a_max) {
62  T1_new = (a_max - a0) / j_max;
63 
64  } else if (accel_T1 < -a_max) {
65  T1_new = (-a_max - a0) / j_max;
66  }
67 
68  return T1_new;
69 }
70 
71 float VelocitySmoothing::computeT1(float a0, float v3, float j_max, float a_max)
72 {
73  float delta = 2.f * a0 * a0 + 4.f * j_max * v3;
74 
75  if (delta < 0.f) {
76  // Solution is not real
77  return 0.f;
78  }
79 
80  float sqrt_delta = sqrtf(delta);
81  float T1_plus = (-a0 + 0.5f * sqrt_delta) / j_max;
82  float T1_minus = (-a0 - 0.5f * sqrt_delta) / j_max;
83 
84  float T3_plus = a0 / j_max + T1_plus;
85  float T3_minus = a0 / j_max + T1_minus;
86 
87  float T1 = 0.f;
88 
89  if (T1_plus >= 0.f && T3_plus >= 0.f) {
90  T1 = T1_plus;
91 
92  } else if (T1_minus >= 0.f && T3_minus >= 0.f) {
93  T1 = T1_minus;
94  }
95 
96  T1 = saturateT1ForAccel(a0, j_max, T1, a_max);
97 
98  return math::max(T1, 0.f);
99 }
100 
101 float VelocitySmoothing::computeT1(float T123, float a0, float v3, float j_max, float a_max)
102 {
103  float a = -j_max;
104  float b = j_max * T123 - a0;
105  float delta = T123 * T123 * j_max * j_max + 2.f * T123 * a0 * j_max - a0 * a0 - 4.f * j_max * v3;
106 
107  if (delta < 0.f) {
108  // Solution is not real
109  return 0.f;
110  }
111 
112  float sqrt_delta = sqrtf(delta);
113  float denominator_inv = 1.f / (2.f * a);
114  float T1_plus = math::max((-b + sqrt_delta) * denominator_inv, 0.f);
115  float T1_minus = math::max((-b - sqrt_delta) * denominator_inv, 0.f);
116 
117  float T3_plus = a0 / j_max + T1_plus;
118  float T3_minus = a0 / j_max + T1_minus;
119 
120  float T13_plus = T1_plus + T3_plus;
121  float T13_minus = T1_minus + T3_minus;
122 
123  float T1 = 0.f;
124 
125  if (T13_plus > T123) {
126  T1 = T1_minus;
127 
128  } else if (T13_minus > T123) {
129  T1 = T1_plus;
130  }
131 
132  T1 = saturateT1ForAccel(a0, j_max, T1, a_max);
133 
134  return T1;
135 }
136 
137 
138 float VelocitySmoothing::computeT2(float T1, float T3, float a0, float v3, float j_max)
139 {
140  float T2 = 0.f;
141 
142  float den = a0 + j_max * T1;
143 
144  if (math::abs_t(den) > FLT_EPSILON) {
145  T2 = (-0.5f * T1 * T1 * j_max - T1 * T3 * j_max - T1 * a0 + 0.5f * T3 * T3 * j_max - T3 * a0 + v3) / den;
146  }
147 
148  return math::max(T2, 0.f);
149 }
150 
151 float VelocitySmoothing::computeT2(float T123, float T1, float T3)
152 {
153  float T2 = T123 - T1 - T3;
154  return math::max(T2, 0.f);
155 }
156 
157 float VelocitySmoothing::computeT3(float T1, float a0, float j_max)
158 {
159  float T3 = a0 / j_max + T1;
160  return math::max(T3, 0.f);
161 }
162 
163 void VelocitySmoothing::updateDurations(float vel_setpoint)
164 {
165  _vel_sp = math::constrain(vel_setpoint, -_max_vel, _max_vel);
166  _local_time = 0.f;
168 
170 
171  if (_direction != 0) {
173 
174  } else {
175  _T1 = _T2 = _T3 = 0.f;
176  }
177 }
178 
180 {
181  // Compute the velocity at which the trajectory will be
182  // when the acceleration will be zero
183  float vel_zero_acc = computeVelAtZeroAcc();
184 
185  /* Depending of the direction, start accelerating positively or negatively */
186  int direction = math::sign(_vel_sp - vel_zero_acc);
187 
188  if (direction == 0) {
189  // If by braking immediately the velocity is exactly
190  // the require one with zero acceleration, then brake
191  direction = math::sign(_state.a);
192  }
193 
194  return direction;
195 }
196 
198 {
199  float vel_zero_acc = _state.v;
200 
201  if (fabsf(_state.a) > FLT_EPSILON) {
202  float j_zero_acc = -math::sign(_state.a) * _max_jerk; // Required jerk to reduce the acceleration
203  float t_zero_acc = -_state.a / j_zero_acc; // Required time to cancel the current acceleration
204  vel_zero_acc = _state.v + _state.a * t_zero_acc + 0.5f * j_zero_acc * t_zero_acc * t_zero_acc;
205  }
206 
207  return vel_zero_acc;
208 }
209 
211 {
212  float jerk_max_T1 = _direction * _max_jerk;
213  float delta_v = _vel_sp - _state.v;
214 
215  // compute increasing acceleration time
216  _T1 = computeT1(_state.a, delta_v, jerk_max_T1, _max_accel);
217 
218  // compute decreasing acceleration time
219  _T3 = computeT3(_T1, _state.a, jerk_max_T1);
220 
221  // compute constant acceleration time
222  _T2 = computeT2(_T1, _T3, _state.a, delta_v, jerk_max_T1);
223 }
224 
225 Trajectory VelocitySmoothing::evaluatePoly(float j, float a0, float v0, float x0, float t, int d)
226 {
227  Trajectory traj;
228  float jt = d * j;
229  float t2 = t * t;
230  float t3 = t2 * t;
231 
232  traj.j = jt;
233  traj.a = a0 + jt * t;
234  traj.v = v0 + a0 * t + 0.5f * jt * t2;
235  traj.x = x0 + v0 * t + 0.5f * a0 * t2 + 1.f / 6.f * jt * t3;
236 
237  return traj;
238 }
239 
240 void VelocitySmoothing::updateTraj(float dt, float time_stretch)
241 {
242  _local_time += dt * time_stretch;
243  float t_remain = _local_time;
244 
245  float t1 = math::min(t_remain, _T1);
247  t_remain -= t1;
248 
249  if (t_remain > 0.f) {
250  float t2 = math::min(t_remain, _T2);
251  _state = evaluatePoly(0.f, _state.a, _state.v, _state.x, t2, 0.f);
252  t_remain -= t2;
253  }
254 
255  if (t_remain > 0.f) {
256  float t3 = math::min(t_remain, _T3);
258  t_remain -= t3;
259  }
260 
261  if (t_remain > 0.f) {
262  _state = evaluatePoly(0.f, 0.f, _state.v, _state.x, t_remain, 0.f);
263  }
264 }
265 
267 {
268  float desired_time = 0.f;
269  int longest_traj_index = 0;
270 
271  for (int i = 0; i < n_traj; i++) {
272  const float T123 = traj[i].getTotalTime();
273 
274  if (T123 > desired_time) {
275  desired_time = T123;
276  longest_traj_index = i;
277  }
278  }
279 
280  if (desired_time > FLT_EPSILON) {
281  for (int i = 0; i < n_traj; i++) {
282  if (i != longest_traj_index) {
283  traj[i].updateDurationsGivenTotalTime(desired_time);
284  }
285  }
286  }
287 }
288 
290 {
291  float jerk_max_T1 = _direction * _max_jerk;
292  float delta_v = _vel_sp - _state.v;
293 
294  // compute increasing acceleration time
295  _T1 = computeT1(T123, _state.a, delta_v, jerk_max_T1, _max_accel);
296 
297  // compute decreasing acceleration time
298  _T3 = computeT3(_T1, _state.a, jerk_max_T1);
299 
300  // compute constant acceleration time
301  _T2 = computeT2(T123, _T1, _T3);
302 }
constexpr _Tp constrain(_Tp val, _Tp min_val, _Tp max_val)
Definition: Limits.hpp:66
#define FLT_EPSILON
int computeDirection()
Compute the direction of the jerk to be applied in order to drive the current state to the desired on...
float computeVelAtZeroAcc()
Compute the velocity at which the trajectory will be if the maximum jerk is applied during the time r...
void updateDurationsGivenTotalTime(float T123)
Compute T1, T2, T3 depending on the current state and velocity setpoint.
static struct hrt_call t1
Definition: hrt_test.cpp:54
TODO: document the algorithm |T1| T2 |T3| __| |____ __ Jerk |_| / \ Acceleration ___/ ___ ;" / / V...
void updateTraj(float dt, float time_stretch=1.f)
Generate the trajectory (acceleration, velocity and position) by integrating the current jerk...
float computeT2(float T1, float T3, float a0, float v3, float j_max)
Compute constant acceleration time.
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
Definition: integration.cpp:8
void reset(float accel, float vel, float pos)
Reset the state.
float getTotalTime() const
void updateDurations(float vel_setpoint)
Compute T1, T2, T3 depending on the current state and velocity setpoint.
void updateDurationsMinimizeTotalTime()
Compute T1, T2, T3 depending on the current state and velocity setpoint.
float computeT1(float a0, float v3, float j_max, float a_max)
Compute increasing acceleration time.
constexpr _Tp min(_Tp a, _Tp b)
Definition: Limits.hpp:54
float _local_time
Current local time.
_Tp abs_t(_Tp val)
Definition: SearchMin.hpp:49
int sign(T val)
Definition: Functions.hpp:49
Trajectory evaluatePoly(float j, float a0, float v0, float x0, float t, int d)
Compute the jerk, acceleration, velocity and position of a jerk-driven polynomial trajectory at a giv...
VelocitySmoothing(float initial_accel=0.f, float initial_vel=0.f, float initial_pos=0.f)
constexpr _Tp max(_Tp a, _Tp b)
Definition: Limits.hpp:60
float dt
Definition: px4io.c:73
t2
Definition: calcH_YAW312.c:3
static void timeSynchronization(VelocitySmoothing *traj, int n_traj)
Synchronize several trajectories to have the same total time.
float _T1
Increasing acceleration [s].
float computeT3(float T1, float a0, float j_max)
Compute decreasing acceleration time.
float _T3
Decreasing acceleration [s].
float _T2
Constant acceleration [s].
t3
Definition: calcH_YAW312.c:4
float saturateT1ForAccel(float a0, float j_max, float T1, float a_max)
Saturate T1 in order to respect the maximum acceleration constraint.