1#![allow(
2 dead_code,
3 clippy::too_many_arguments,
4 clippy::needless_borrows_for_generic_args
5)]
6
7const MAX_T: f64 = 100.0; const MIN_T: f64 = 5.0; #[derive(Debug, Clone)]
17pub struct QuinticPolynomial {
18 pub a0: f64,
19 pub a1: f64,
20 pub a2: f64,
21 pub a3: f64,
22 pub a4: f64,
23 pub a5: f64,
24}
25
26impl QuinticPolynomial {
27 pub fn new(xs: f64, vxs: f64, axs: f64, xe: f64, vxe: f64, axe: f64, time: f64) -> Self {
28 let a0 = xs;
29 let a1 = vxs;
30 let a2 = axs / 2.0;
31
32 let t2 = time * time;
33 let t3 = t2 * time;
34 let t4 = t3 * time;
35 let t5 = t4 * time;
36
37 let a_matrix = [
38 [t3, t4, t5],
39 [3.0 * t2, 4.0 * t3, 5.0 * t4],
40 [6.0 * time, 12.0 * t2, 20.0 * t3],
41 ];
42
43 let b = [
44 xe - a0 - a1 * time - a2 * t2,
45 vxe - a1 - 2.0 * a2 * time,
46 axe - 2.0 * a2,
47 ];
48
49 let det_a = Self::determinant_3x3(&a_matrix);
50
51 let mut a3_matrix = a_matrix;
52 a3_matrix[0][0] = b[0];
53 a3_matrix[1][0] = b[1];
54 a3_matrix[2][0] = b[2];
55 let a3 = Self::determinant_3x3(&a3_matrix) / det_a;
56
57 let mut a4_matrix = a_matrix;
58 a4_matrix[0][1] = b[0];
59 a4_matrix[1][1] = b[1];
60 a4_matrix[2][1] = b[2];
61 let a4 = Self::determinant_3x3(&a4_matrix) / det_a;
62
63 let mut a5_matrix = a_matrix;
64 a5_matrix[0][2] = b[0];
65 a5_matrix[1][2] = b[1];
66 a5_matrix[2][2] = b[2];
67 let a5 = Self::determinant_3x3(&a5_matrix) / det_a;
68
69 QuinticPolynomial {
70 a0,
71 a1,
72 a2,
73 a3,
74 a4,
75 a5,
76 }
77 }
78
79 fn determinant_3x3(matrix: &[[f64; 3]; 3]) -> f64 {
80 matrix[0][0] * (matrix[1][1] * matrix[2][2] - matrix[1][2] * matrix[2][1])
81 - matrix[0][1] * (matrix[1][0] * matrix[2][2] - matrix[1][2] * matrix[2][0])
82 + matrix[0][2] * (matrix[1][0] * matrix[2][1] - matrix[1][1] * matrix[2][0])
83 }
84
85 pub fn calc_point(&self, t: f64) -> f64 {
86 self.a0
87 + self.a1 * t
88 + self.a2 * t.powi(2)
89 + self.a3 * t.powi(3)
90 + self.a4 * t.powi(4)
91 + self.a5 * t.powi(5)
92 }
93
94 pub fn calc_first_derivative(&self, t: f64) -> f64 {
95 self.a1
96 + 2.0 * self.a2 * t
97 + 3.0 * self.a3 * t.powi(2)
98 + 4.0 * self.a4 * t.powi(3)
99 + 5.0 * self.a5 * t.powi(4)
100 }
101
102 pub fn calc_second_derivative(&self, t: f64) -> f64 {
103 2.0 * self.a2 + 6.0 * self.a3 * t + 12.0 * self.a4 * t.powi(2) + 20.0 * self.a5 * t.powi(3)
104 }
105
106 pub fn calc_third_derivative(&self, t: f64) -> f64 {
107 6.0 * self.a3 + 24.0 * self.a4 * t + 60.0 * self.a5 * t.powi(2)
108 }
109}
110
111#[derive(Debug)]
112pub struct QuinticPolynomialsPlanner {
113 pub time: Vec<f64>,
114 pub rx: Vec<f64>,
115 pub ry: Vec<f64>,
116 pub ryaw: Vec<f64>,
117 pub rv: Vec<f64>,
118 pub ra: Vec<f64>,
119 pub rj: Vec<f64>,
120}
121
122impl QuinticPolynomialsPlanner {
123 pub fn new() -> Self {
124 QuinticPolynomialsPlanner {
125 time: Vec::new(),
126 rx: Vec::new(),
127 ry: Vec::new(),
128 ryaw: Vec::new(),
129 rv: Vec::new(),
130 ra: Vec::new(),
131 rj: Vec::new(),
132 }
133 }
134
135 pub fn planning(
136 &mut self,
137 sx: f64,
138 sy: f64,
139 syaw: f64,
140 sv: f64,
141 sa: f64,
142 gx: f64,
143 gy: f64,
144 gyaw: f64,
145 gv: f64,
146 ga: f64,
147 max_accel: f64,
148 max_jerk: f64,
149 dt: f64,
150 ) -> bool {
151 let vxs = sv * syaw.cos();
152 let vys = sv * syaw.sin();
153 let vxg = gv * gyaw.cos();
154 let vyg = gv * gyaw.sin();
155
156 let axs = sa * syaw.cos();
157 let ays = sa * syaw.sin();
158 let axg = ga * gyaw.cos();
159 let ayg = ga * gyaw.sin();
160
161 let mut t = MIN_T;
162 while t < MAX_T {
163 let xqp = QuinticPolynomial::new(sx, vxs, axs, gx, vxg, axg, t);
164 let yqp = QuinticPolynomial::new(sy, vys, ays, gy, vyg, ayg, t);
165
166 self.time.clear();
167 self.rx.clear();
168 self.ry.clear();
169 self.ryaw.clear();
170 self.rv.clear();
171 self.ra.clear();
172 self.rj.clear();
173
174 let mut current_t = 0.0;
175 while current_t < t + dt - 1e-12 {
176 self.time.push(current_t);
177 self.rx.push(xqp.calc_point(current_t));
178 self.ry.push(yqp.calc_point(current_t));
179
180 let vx = xqp.calc_first_derivative(current_t);
181 let vy = yqp.calc_first_derivative(current_t);
182 let v = (vx * vx + vy * vy).sqrt();
183 let yaw = vy.atan2(vx);
184 self.rv.push(v);
185 self.ryaw.push(yaw);
186
187 let ax = xqp.calc_second_derivative(current_t);
188 let ay = yqp.calc_second_derivative(current_t);
189 let mut a = (ax * ax + ay * ay).sqrt();
190 if self.rv.len() >= 2
191 && self.rv[self.rv.len() - 1] - self.rv[self.rv.len() - 2] < 0.0
192 {
193 a *= -1.0;
194 }
195 self.ra.push(a);
196
197 let jx = xqp.calc_third_derivative(current_t);
198 let jy = yqp.calc_third_derivative(current_t);
199 let mut j = (jx * jx + jy * jy).sqrt();
200 if self.ra.len() >= 2
201 && self.ra[self.ra.len() - 1] - self.ra[self.ra.len() - 2] < 0.0
202 {
203 j *= -1.0;
204 }
205 self.rj.push(j);
206
207 current_t += dt;
208 }
209
210 let max_a = self.ra.iter().map(|x| x.abs()).fold(0.0, f64::max);
211 let max_j = self.rj.iter().map(|x| x.abs()).fold(0.0, f64::max);
212
213 if max_a <= max_accel && max_j <= max_jerk {
214 return true;
215 }
216
217 t += MIN_T;
218 }
219
220 false
221 }
222}
223
224impl Default for QuinticPolynomialsPlanner {
225 fn default() -> Self {
226 Self::new()
227 }
228}
229
230#[cfg(test)]
231#[allow(clippy::excessive_precision)]
232mod tests {
233 use super::*;
234
235 fn approx_eq(a: f64, b: f64, tol: f64) -> bool {
236 (a - b).abs() < tol
237 }
238
239 fn scalar_fingerprint(values: &[f64]) -> (f64, f64) {
240 let sum: f64 = values.iter().sum();
241 let weighted_sum: f64 = values
242 .iter()
243 .enumerate()
244 .map(|(index, value)| (index + 1) as f64 * value)
245 .sum();
246 (sum, weighted_sum)
247 }
248
249 #[test]
250 fn test_quintic_polynomial() {
251 let qp = QuinticPolynomial::new(0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 10.0);
252 assert!((qp.calc_point(0.0) - 0.0).abs() < 1e-10);
253 assert!((qp.calc_point(10.0) - 10.0).abs() < 1e-6);
254 }
255
256 #[test]
257 fn test_quintic_polynomial_matches_upstream_simple_reference() {
258 let qp = QuinticPolynomial::new(0.0, 0.0, 0.0, 10.0, 0.0, 0.0, 10.0);
259
260 assert!(approx_eq(qp.a0, 0.0, 1e-12));
261 assert!(approx_eq(qp.a1, 0.0, 1e-12));
262 assert!(approx_eq(qp.a2, 0.0, 1e-12));
263 assert!(approx_eq(qp.a3, 0.099_999_999_999_999_99, 1e-12));
264 assert!(approx_eq(qp.a4, -0.014_999_999_999_999_996, 1e-12));
265 assert!(approx_eq(qp.a5, 0.000_599_999_999_999_999_8, 1e-12));
266
267 let expected_states = [
268 (0.0, 0.0, 0.0, 0.0, 0.6),
269 (
270 5.0,
271 5.0,
272 1.875_000_000_000_001_3,
273 1.332_267_629_550_187_8e-15,
274 -0.299_999_999_999_999_5,
275 ),
276 (
277 10.0,
278 10.0,
279 7.105_427_357_601_002e-15,
280 3.552_713_678_800_501e-15,
281 0.600_000_000_000_000_5,
282 ),
283 ];
284
285 for (t, point, velocity, accel, jerk) in expected_states {
286 assert!(approx_eq(qp.calc_point(t), point, 1e-12));
287 assert!(approx_eq(qp.calc_first_derivative(t), velocity, 1e-12));
288 assert!(approx_eq(qp.calc_second_derivative(t), accel, 1e-12));
289 assert!(approx_eq(qp.calc_third_derivative(t), jerk, 1e-12));
290 }
291 }
292
293 #[test]
294 fn test_quintic_polynomials_planner() {
295 let mut planner = QuinticPolynomialsPlanner::new();
296 let result = planner.planning(
297 10.0,
298 10.0,
299 10.0_f64.to_radians(),
300 1.0,
301 0.1,
302 30.0,
303 -10.0,
304 20.0_f64.to_radians(),
305 1.0,
306 0.1,
307 1.0,
308 0.5,
309 0.1,
310 );
311 assert!(result);
312 assert!(!planner.rx.is_empty());
313 }
314
315 #[test]
316 fn test_quintic_polynomials_planner_matches_upstream_main_example() {
317 let mut planner = QuinticPolynomialsPlanner::new();
318 let result = planner.planning(
319 10.0,
320 10.0,
321 10.0_f64.to_radians(),
322 1.0,
323 0.1,
324 30.0,
325 -10.0,
326 20.0_f64.to_radians(),
327 1.0,
328 0.1,
329 1.0,
330 0.5,
331 0.1,
332 );
333
334 assert!(result);
335 assert_eq!(planner.time.len(), 151);
336 assert_eq!(planner.rx.len(), 151);
337 assert_eq!(planner.ry.len(), 151);
338 assert_eq!(planner.ryaw.len(), 151);
339 assert_eq!(planner.rv.len(), 151);
340 assert_eq!(planner.ra.len(), 151);
341 assert_eq!(planner.rj.len(), 151);
342 assert!(approx_eq(*planner.time.last().unwrap(), 15.0, 1e-12));
343
344 let expected_samples = [
345 (
346 0usize,
347 0.0,
348 10.0,
349 10.0,
350 10.0_f64.to_radians(),
351 1.0,
352 0.099_999_999_999_999_99,
353 0.427_280_794_153_487_6,
354 ),
355 (
356 1,
357 0.1,
358 10.098_982_615_546_902,
359 10.017_381_774_411_378,
360 0.172_447_377_225_515_92,
361 1.009_916_853_081_542_3,
362 0.106_821_796_693_630_91,
363 0.410_270_512_683_564_35,
364 ),
365 (
366 10,
367 1.0,
368 11.042_264_078_940_175,
369 10.118_588_516_101_896,
370 0.005_806_154_972_050_835,
371 1.106_637_942_606_725_2,
372 0.354_433_544_260_436_83,
373 0.267_611_399_963_759_2,
374 ),
375 (
376 50,
377 5.0,
378 16.610_137_614_251_27,
379 6.064_611_076_798_1,
380 -0.912_947_184_636_906_5,
381 2.664_216_406_735_696_4,
382 0.467_382_916_097_198_84,
383 -0.146_179_174_681_691_67,
384 ),
385 (
386 150,
387 15.0,
388 30.000_000_000_000_007,
389 -10.0,
390 20.0_f64.to_radians(),
391 1.000_000_000_000_003,
392 0.099_999_999_999_999_62,
393 -0.433_897_236_756_954_63,
394 ),
395 ];
396
397 for (index, time, rx, ry, yaw, v, a, j) in expected_samples {
398 assert!(approx_eq(planner.time[index], time, 1e-12));
399 assert!(approx_eq(planner.rx[index], rx, 1e-12));
400 assert!(approx_eq(planner.ry[index], ry, 1e-12));
401 assert!(approx_eq(planner.ryaw[index], yaw, 1e-12));
402 assert!(approx_eq(planner.rv[index], v, 1e-12));
403 assert!(approx_eq(planner.ra[index], a, 1e-12));
404 assert!(approx_eq(planner.rj[index], j, 1e-12));
405 }
406
407 let time_fp = scalar_fingerprint(&planner.time);
408 assert!(approx_eq(time_fp.0, 1_132.500_000_000_000_2, 1e-9));
409 assert!(approx_eq(time_fp.1, 114_759.999_999_999_97, 1e-6));
410
411 let rx_fp = scalar_fingerprint(&planner.rx);
412 assert!(approx_eq(rx_fp.0, 3_084.277_101_694_296, 1e-9));
413 assert!(approx_eq(rx_fp.1, 275_626.252_367_386_25, 1e-6));
414
415 let ry_fp = scalar_fingerprint(&planner.ry);
416 assert!(approx_eq(ry_fp.0, -23.379_117_661_761_498, 1e-9));
417 assert!(approx_eq(ry_fp.1, -52_763.587_503_238_03, 1e-6));
418
419 let yaw_fp = scalar_fingerprint(&planner.ryaw);
420 assert!(approx_eq(yaw_fp.0, -91.931_046_512_332_49, 1e-9));
421 assert!(approx_eq(yaw_fp.1, -6_931.617_159_195_794, 1e-6));
422
423 let velocity_fp = scalar_fingerprint(&planner.rv);
424 assert!(approx_eq(velocity_fp.0, 302.345_686_787_654_7, 1e-9));
425 assert!(approx_eq(velocity_fp.1, 22_418.061_584_864_976, 1e-6));
426
427 let accel_fp = scalar_fingerprint(&planner.ra);
428 assert!(approx_eq(accel_fp.0, 3.130_947_174_813_961, 1e-9));
429 assert!(approx_eq(accel_fp.1, -1_921.398_399_412_191_8, 1e-6));
430
431 let jerk_fp = scalar_fingerprint(&planner.rj);
432 assert!(approx_eq(jerk_fp.0, -6.835_206_957_044_357, 1e-9));
433 assert!(approx_eq(jerk_fp.1, -1_017.425_338_206_766_7, 1e-6));
434 }
435}