0


自动驾驶规划 - 5次多项式拟合

简介

自动驾驶运动规划中会用到各种曲线,主要用于生成车辆的轨迹,常见的轨迹生成算法,如贝塞尔曲线,样条曲线,以及apollo EM Planner的五次多项式曲线,城市场景中使用的是分段多项式曲线,在EM Planner和Lattice Planner中思路是,都是先通过动态规划生成点,再用5次多项式生成曲线连接两个点(虽然后面的版本改动很大,至少lattice planner目前还是这个方法)。

在这里可以看出5次多项式的作用,就是生成轨迹,这里的轨迹不一定是车行驶的轨迹,比如S—T图中的线,是用来做速度规划的。****如下图:

请添加图片描述

在apollo里面用到了,3-5次多项式,

  • cubic_polynomial_curve1d,三次多项式曲线
  • quartic_polynomial_curve1d,四次多项式曲线-
  • quintic_polynomial_curve1d,五次多项式曲线

3次多项式

  1. f
  2. (
  3. x
  4. )
  5. =
  6. C
  7. 0
  8. +
  9. C
  10. 1
  11. x
  12. +
  13. C
  14. 2
  15. x
  16. 2
  17. +
  18. C
  19. 3
  20. x
  21. 3
  22. (
  23. 1
  24. )
  25. f(x) = C_0 + C_1x + C_2x^2+ C_3x^3 ----(1)
  26. f(x)=C0​+C1x+C2x2+C3x3−−−−(1)

x求导====>

  1. f
  2. (
  3. x
  4. )
  5. =
  6. C
  7. 1
  8. +
  9. 2
  10. C
  11. 2
  12. x
  13. +
  14. 3
  15. C
  16. 3
  17. x
  18. 2
  19. f'(x) = C_1 + 2C_2x+ 3C_3x^2
  20. f′(x)=C1​+2C2​x+3C3​x2
  21. f
  22. (
  23. x
  24. )
  25. =
  26. 2
  27. C
  28. 2
  29. +
  30. 6
  31. C
  32. 3
  33. x
  34. f(x) = 2C_2+ 6C_3x
  35. f(x)=2C2​+6C3​x

因为是连接两个已知点,所以两个轨迹点的信息是已知的。
如已知,当x=0,代如得:

  1. f
  2. (
  3. 0
  4. )
  5. =
  6. C
  7. 0
  8. f
  9. (
  10. 0
  11. )
  12. =
  13. C
  14. 1
  15. f
  16. (
  17. 0
  18. )
  19. =
  20. 2
  21. C
  22. 2
  23. f(0) = C_0 f'(0) = C_1;f''(0) =2C_2
  24. f(0)=C0​;f′(0)=C1​;f′′(0)=2C2​

所以

  1. C
  2. 0
  3. =
  4. f
  5. (
  6. 0
  7. )
  8. C
  9. 1
  10. =
  11. f
  12. (
  13. 0
  14. )
  15. C
  16. 2
  17. =
  18. f
  19. (
  20. 0
  21. )
  22. /
  23. 2
  24. C_0 = f(0);C_1 = f'(0); C_2 = f''(0)/2
  25. C0​=f(0);C1​=f′(0);C2​=f′′(0)/2

将终点 (X_end,f(X_end))带入得到C_3

  1. C
  2. 3
  3. =
  4. (
  5. f
  6. (
  7. x
  8. p
  9. )
  10. C
  11. 0
  12. C
  13. 1
  14. x
  15. p
  16. C
  17. 2
  18. x
  19. p
  20. 2
  21. )
  22. /
  23. x
  24. p
  25. 3
  26. C_3 = (f(x_p)-C_0-C_1x_p-C_2x_p^2)/x_p^3
  27. C3​=(f(xp​)−C0​−C1xp​−C2xp2​)/xp3

(1)式的所有未知参数都求出,代入x可以得到两点间的轨迹。

apollo中3次多项式的计算

  1. // cubic_polynomial_curve1d.cc
  2. CubicPolynomialCurve1d::CubicPolynomialCurve1d(constdouble x0,constdouble dx0,constdouble ddx0,constdouble x1,constdouble param){ComputeCoefficients(x0, dx0, ddx0, x1, param);
  3. param_ = param;
  4. start_condition_[0]= x0;
  5. start_condition_[1]= dx0;
  6. start_condition_[2]= ddx0;
  7. end_condition_ = x1;}void CubicPolynomialCurve1d::ComputeCoefficients(constdouble x0,constdouble dx0,constdouble ddx0,constdouble x1,constdouble param){DCHECK(param >0.0);constdouble p2 = param * param;constdouble p3 = param * p2;
  8. coef_[0]= x0;
  9. coef_[1]= dx0;
  10. coef_[2]=0.5* ddx0;
  11. coef_[3]=(x1 - x0 - dx0 * param - coef_[2]* p2)/ p3;}

5次多项式

  1. f
  2. (
  3. x
  4. )
  5. =
  6. C
  7. 0
  8. +
  9. C
  10. 1
  11. x
  12. +
  13. C
  14. 2
  15. x
  16. 2
  17. +
  18. C
  19. 3
  20. x
  21. 3
  22. +
  23. C
  24. 4
  25. x
  26. 4
  27. +
  28. C
  29. 5
  30. x
  31. 5
  32. (
  33. 3
  34. 1
  35. )
  36. f(x) = C_0 + C_1x + C_2x^2+ C_3x^3+C_4x^4+C_5x^5 ----(3-1)
  37. f(x)=C0​+C1x+C2x2+C3x3+C4x4+C5x5−−−−(31)

x求导====>

  1. f
  2. (
  3. x
  4. )
  5. =
  6. C
  7. 1
  8. +
  9. 2
  10. C
  11. 2
  12. x
  13. +
  14. 3
  15. C
  16. 3
  17. x
  18. 2
  19. +
  20. 4
  21. C
  22. 4
  23. x
  24. 3
  25. +
  26. 5
  27. C
  28. 5
  29. x
  30. 4
  31. (
  32. 3
  33. 2
  34. )
  35. f'(x) = C_1 + 2C_2x+ 3C_3x^2+4C_4x^3+5C_5x^4----(3-2)
  36. f′(x)=C1​+2C2​x+3C3​x2+4C4​x3+5C5​x4−−−−(3−2)
  37. f
  38. (
  39. x
  40. )
  41. =
  42. 2
  43. C
  44. 2
  45. +
  46. 6
  47. C
  48. 3
  49. x
  50. +
  51. 12
  52. C
  53. 4
  54. x
  55. 2
  56. +
  57. 20
  58. C
  59. 5
  60. x
  61. 3
  62. (
  63. 3
  64. 3
  65. )
  66. f''(x) = 2C_2+ 6C_3x+12C_4x^2+20C_5x^3----(3-3)
  67. f′′(x)=2C2​+6C3​x+12C4​x2+20C5​x3−−−−(3−3)

因为是连接两个已知点,所以两个轨迹点的信息是已知的。
如已知,当x=0,代如得:

  1. f
  2. (
  3. 0
  4. )
  5. =
  6. C
  7. 0
  8. f
  9. (
  10. 0
  11. )
  12. =
  13. C
  14. 1
  15. f
  16. (
  17. 0
  18. )
  19. =
  20. 2
  21. C
  22. 2
  23. f(0) = C_0 f'(0) = C_1;f''(0) =2C_2
  24. f(0)=C0​;f′(0)=C1​;f′′(0)=2C2​

所以

  1. C
  2. 0
  3. =
  4. f
  5. (
  6. 0
  7. )
  8. C
  9. 1
  10. =
  11. f
  12. (
  13. 0
  14. )
  15. C
  16. 2
  17. =
  18. f
  19. (
  20. 0
  21. )
  22. /
  23. 2
  24. C_0 = f(0);C_1 = f'(0); C_2 = f''(0)/2
  25. C0​=f(0);C1​=f′(0);C2​=f′′(0)/2

将终点 **(x_e,f(x_e))带入 (3-1) (3-2) (3-3)**。

得到

  1. f
  2. (
  3. x
  4. e
  5. )
  6. =
  7. C
  8. 0
  9. +
  10. C
  11. 1
  12. x
  13. e
  14. +
  15. C
  16. 2
  17. x
  18. e
  19. 2
  20. +
  21. C
  22. 3
  23. x
  24. e
  25. 3
  26. +
  27. C
  28. 4
  29. x
  30. e
  31. 4
  32. +
  33. C
  34. 5
  35. x
  36. e
  37. 5
  38. (
  39. 3
  40. 4
  41. )
  42. f(x_e) = C_0 + C_1x_e + C_2x_e^2+ C_3x_e^3+C_4x_e^4+C_5x_e^5 ----(3-4)
  43. f(xe​)=C0​+C1xe​+C2xe2​+C3xe3​+C4xe4​+C5xe5​−−−−(34)

x求导====>

  1. f
  2. (
  3. x
  4. )
  5. =
  6. C
  7. 1
  8. +
  9. 2
  10. C
  11. 2
  12. x
  13. e
  14. +
  15. 3
  16. C
  17. 3
  18. x
  19. e
  20. 2
  21. +
  22. 4
  23. C
  24. 4
  25. x
  26. e
  27. 3
  28. +
  29. 5
  30. C
  31. 5
  32. x
  33. e
  34. 4
  35. (
  36. 3
  37. 5
  38. )
  39. f'(x) = C_1 + 2C_2x_e+ 3C_3x_e^2+4C_4x_e^3+5C_5x_e^4----(3-5)
  40. f′(x)=C1​+2C2​xe​+3C3​xe2​+4C4​xe3​+5C5​xe4​−−−−(3−5)
  41. f
  42. (
  43. x
  44. )
  45. =
  46. 2
  47. C
  48. 2
  49. +
  50. 6
  51. C
  52. 3
  53. x
  54. e
  55. +
  56. 12
  57. C
  58. 4
  59. x
  60. e
  61. 2
  62. +
  63. 20
  64. C
  65. 5
  66. x
  67. e
  68. 3
  69. (
  70. 3
  71. 6
  72. )
  73. f''(x) = 2C_2+ 6C_3x_e+12C_4x_e^2+20C_5x_e^3----(3-6)
  74. f′′(x)=2C2​+6C3​xe​+12C4​xe2​+20C5​xe3​−−−−(3−6)

联立可得

  1. C
  2. 3
  3. =
  4. 10
  5. (
  6. f
  7. (
  8. x
  9. p
  10. )
  11. 1
  12. /
  13. 2
  14. f
  15. (
  16. 0
  17. )
  18. x
  19. p
  20. 2
  21. f
  22. (
  23. 0
  24. )
  25. x
  26. p
  27. f
  28. (
  29. 0
  30. )
  31. )
  32. 4
  33. (
  34. f
  35. (
  36. x
  37. p
  38. )
  39. f
  40. (
  41. 0
  42. )
  43. x
  44. p
  45. f
  46. (
  47. 0
  48. )
  49. )
  50. x
  51. p
  52. +
  53. 1
  54. /
  55. 2
  56. (
  57. f
  58. (
  59. x
  60. p
  61. )
  62. f
  63. (
  64. 0
  65. )
  66. )
  67. x
  68. p
  69. 2
  70. x
  71. p
  72. 3
  73. C_3 = \frac{10(f(x_p)-1/2*f''(0)x_p^2-f'(0)x_p-f(0))-4(f'(x_p)-f''(0)x_p-f'(0))x_p+1/2*(f''(x_p)-f''(0))x_p^2}{x_p^3}
  74. C3​=xp3​10(f(xp​)−1/2∗f′′(0)xp2​−f′(0)xp​−f(0))−4(f′(xp​)−f′′(0)xp​−f′(0))xp​+1/2∗(f′′(xp​)−f′′(0))xp2​​
  75. C
  76. 4
  77. =
  78. 15
  79. (
  80. f
  81. (
  82. x
  83. p
  84. )
  85. 1
  86. /
  87. 2
  88. f
  89. (
  90. 0
  91. )
  92. x
  93. p
  94. 2
  95. f
  96. (
  97. 0
  98. )
  99. x
  100. p
  101. f
  102. (
  103. 0
  104. )
  105. )
  106. +
  107. 7
  108. (
  109. f
  110. (
  111. x
  112. p
  113. )
  114. f
  115. (
  116. 0
  117. )
  118. x
  119. p
  120. f
  121. (
  122. 0
  123. )
  124. )
  125. x
  126. p
  127. 1
  128. /
  129. 2
  130. (
  131. f
  132. (
  133. x
  134. p
  135. )
  136. f
  137. (
  138. 0
  139. )
  140. )
  141. x
  142. p
  143. 2
  144. x
  145. p
  146. 4
  147. C_4 = \frac{-15(f(x_p)-1/2*f''(0)x_p^2-f'(0)x_p-f(0))+7(f'(x_p)-f''(0)x_p-f'(0))x_p-1/2*(f''(x_p)-f''(0))x_p^2}{x_p^4}
  148. C4​=xp4​−15(f(xp​)−1/2f′′(0)xp2​−f′(0)xp​−f(0))+7(f′(xp​)−f′′(0)xp​−f′(0))xp​−1/2∗(f′′(xp​)−f′′(0))xp2​​
  149. C
  150. 5
  151. =
  152. 6
  153. (
  154. f
  155. (
  156. x
  157. p
  158. )
  159. 1
  160. /
  161. 2
  162. f
  163. (
  164. 0
  165. )
  166. x
  167. p
  168. 2
  169. f
  170. (
  171. 0
  172. )
  173. x
  174. p
  175. f
  176. (
  177. 0
  178. )
  179. )
  180. 3
  181. (
  182. f
  183. (
  184. x
  185. p
  186. )
  187. f
  188. (
  189. 0
  190. )
  191. x
  192. p
  193. f
  194. (
  195. 0
  196. )
  197. )
  198. x
  199. p
  200. +
  201. 1
  202. /
  203. 2
  204. (
  205. f
  206. (
  207. x
  208. p
  209. )
  210. f
  211. (
  212. 0
  213. )
  214. )
  215. x
  216. p
  217. 2
  218. x
  219. p
  220. 5
  221. C_5 = \frac{6(f(x_p)-1/2*f''(0)x_p^2-f'(0)x_p-f(0))-3(f'(x_p)-f''(0)x_p-f'(0))x_p+1/2*(f''(x_p)-f''(0))x_p^2}{x_p^5}
  222. C5​=xp5​6(f(xp​)−1/2∗f′′(0)xp2​−f′(0)xp​−f(0))−3(f′(xp​)−f′′(0)xp​−f′(0))xp​+1/2∗(f′′(xp​)−f′′(0))xp2​​

apollo中5次多项式的计算

  1. void QuinticPolynomialCurve1d::ComputeCoefficients(constdouble x0,constdouble dx0,constdouble ddx0,constdouble x1,constdouble dx1,constdouble ddx1,constdouble p){CHECK_GT(p,0.0);
  2. coef_[0]= x0;
  3. coef_[1]= dx0;
  4. coef_[2]= ddx0 /2.0;constdouble p2 = p * p;constdouble p3 = p * p2;// the direct analytical method is at least 6 times faster than using matrix// inversion.constdouble c0 =(x1 -0.5* p2 * ddx0 - dx0 * p - x0)/ p3;constdouble c1 =(dx1 - ddx0 * p - dx0)/ p2;constdouble c2 =(ddx1 - ddx0)/ p;
  5. coef_[3]=0.5*(20.0* c0 -8.0* c1 + c2);
  6. coef_[4]=(-15.0* c0 +7.0* c1 - c2)/ p;
  7. coef_[5]=(6.0* c0 -3.0* c1 +0.5* c2)/ p2;}

5次多项式拟合

  1. import math
  2. import matplotlib.pyplot as plt
  3. import numpy as np
  4. # parameter
  5. MAX_T =100.0# maximum time to the goal [s]
  6. MIN_T =5.0# minimum time to the goal[s]
  7. show_animation =TrueclassQuinticPolynomial:def__init__(self, xs, vxs, axs, xe, vxe, axe, time):# calc coefficient of quintic polynomial# See jupyter notebook document for derivation of this equation.# 根据初始状态c0 c1 c2
  8. self.a0 = xs # x(t)
  9. self.a1 = vxs # v(t)
  10. self.a2 = axs /2.0# a(t)
  11. A = np.array([[time **3, time **4, time **5],[3* time **2,4* time **3,5* time **4],[6* time,12* time **2,20* time **3]])
  12. b = np.array([xe - self.a0 - self.a1 * time - self.a2 * time **2,
  13. vxe - self.a1 -2* self.a2 * time,
  14. axe -2* self.a2])# Ax=b 求解x
  15. x = np.linalg.solve(A, b)# 计算c3 c4 c5
  16. self.a3 = x[0]
  17. self.a4 = x[1]
  18. self.a5 = x[2]# 根据时间计算点x(t)defcalc_point(self, t):
  19. xt = self.a0 + self.a1 * t + self.a2 * t **2+ \
  20. self.a3 * t **3+ self.a4 * t **4+ self.a5 * t **5return xt
  21. # 计算v(t)defcalc_first_derivative(self, t):
  22. xt = self.a1 +2* self.a2 * t + \
  23. 3* self.a3 * t **2+4* self.a4 * t **3+5* self.a5 * t **4return xt
  24. # 计算a(t) defcalc_second_derivative(self, t):
  25. xt =2* self.a2 +6* self.a3 * t +12* self.a4 * t **2+20* self.a5 * t **3return xt
  26. # 计算jerk(t) defcalc_third_derivative(self, t):
  27. xt =6* self.a3 +24* self.a4 * t +60* self.a5 * t **2return xt
  28. defquintic_polynomials_planner(sx, sy, syaw, sv, sa, gx, gy, gyaw, gv, ga, max_accel, max_jerk, dt):"""
  29. quintic polynomial planner
  30. input
  31. s_x: start x position [m]
  32. s_y: start y position [m]
  33. s_yaw: start yaw angle [rad]
  34. sa: start accel [m/ss]
  35. gx: goal x position [m]
  36. gy: goal y position [m]
  37. gyaw: goal yaw angle [rad]
  38. ga: goal accel [m/ss]
  39. max_accel: maximum accel [m/ss]
  40. max_jerk: maximum jerk [m/sss]
  41. dt: time tick [s]
  42. return
  43. time: time result
  44. rx: x position result list
  45. ry: y position result list
  46. ryaw: yaw angle result list
  47. rv: velocity result list
  48. ra: accel result list
  49. """
  50. vxs = sv * math.cos(syaw)# 起点速度在x方向分量
  51. vys = sv * math.sin(syaw)# 起点速度在y方向分量
  52. vxg = gv * math.cos(gyaw)# 终点速度在x方向分量
  53. vyg = gv * math.sin(gyaw)# 终点速度在y方向分量
  54. axs = sa * math.cos(syaw)# 起点加速度在x方向分量
  55. ays = sa * math.sin(syaw)# 终点加速度在y方向分量
  56. axg = ga * math.cos(gyaw)# 起点加速度在x方向分量
  57. ayg = ga * math.sin(gyaw)# 终点加速度在y方向分量
  58. time, rx, ry, ryaw, rv, ra, rj =[],[],[],[],[],[],[]for T in np.arange(MIN_T, MAX_T, MIN_T):
  59. xqp = QuinticPolynomial(sx, vxs, axs, gx, vxg, axg, T)
  60. yqp = QuinticPolynomial(sy, vys, ays, gy, vyg, ayg, T)
  61. time, rx, ry, ryaw, rv, ra, rj =[],[],[],[],[],[],[]for t in np.arange(0.0, T + dt, dt):
  62. time.append(t)
  63. rx.append(xqp.calc_point(t))
  64. ry.append(yqp.calc_point(t))
  65. vx = xqp.calc_first_derivative(t)
  66. vy = yqp.calc_first_derivative(t)
  67. v = np.hypot(vx, vy)
  68. yaw = math.atan2(vy, vx)
  69. rv.append(v)
  70. ryaw.append(yaw)
  71. ax = xqp.calc_second_derivative(t)
  72. ay = yqp.calc_second_derivative(t)
  73. a = np.hypot(ax, ay)iflen(rv)>=2and rv[-1]- rv[-2]<0.0:
  74. a *=-1
  75. ra.append(a)
  76. jx = xqp.calc_third_derivative(t)
  77. jy = yqp.calc_third_derivative(t)
  78. j = np.hypot(jx, jy)iflen(ra)>=2and ra[-1]- ra[-2]<0.0:
  79. j *=-1
  80. rj.append(j)ifmax([abs(i)for i in ra])<= max_accel andmax([abs(i)for i in rj])<= max_jerk:print("find path!!")breakif show_animation:# pragma: no coverfor i, _ inenumerate(time):
  81. plt.cla()# for stopping simulation with the esc key.
  82. plt.gcf().canvas.mpl_connect('key_release_event',lambda event:[exit(0)if event.key =='escape'elseNone])
  83. plt.grid(True)
  84. plt.axis("equal")
  85. plot_arrow(sx, sy, syaw)
  86. plot_arrow(gx, gy, gyaw)
  87. plot_arrow(rx[i], ry[i], ryaw[i])
  88. plt.title("Time[s]:"+str(time[i])[0:4]+" v[m/s]:"+str(rv[i])[0:4]+" a[m/ss]:"+str(ra[i])[0:4]+" jerk[m/sss]:"+str(rj[i])[0:4],)
  89. plt.pause(0.001)return time, rx, ry, ryaw, rv, ra, rj
  90. defplot_arrow(x, y, yaw, length=1.0, width=0.5, fc="r", ec="k"):# pragma: no cover"""
  91. Plot arrow
  92. """ifnotisinstance(x,float):for(ix, iy, iyaw)inzip(x, y, yaw):
  93. plot_arrow(ix, iy, iyaw)else:
  94. plt.arrow(x, y, length * math.cos(yaw), length * math.sin(yaw),
  95. fc=fc, ec=ec, head_width=width, head_length=width)
  96. plt.plot(x, y)defmain():
  97. sx =10.0# start x position [m]
  98. sy =10.0# start y position [m]
  99. syaw = np.deg2rad(10.0)# start yaw angle [rad]
  100. sv =1.0# start speed [m/s]
  101. sa =0.1# start accel [m/ss]
  102. gx =30.0# goal x position [m]
  103. gy =-10.0# goal y position [m]
  104. gyaw = np.deg2rad(20.0)# goal yaw angle [rad]
  105. gv =1.0# goal speed [m/s]
  106. ga =0.1# goal accel [m/ss]
  107. max_accel =1.0# max accel [m/ss]
  108. max_jerk =0.5# max jerk [m/sss]
  109. dt =0.1# time tick [s]
  110. time, x, y, yaw, v, a, j = quintic_polynomials_planner(
  111. sx, sy, syaw, sv, sa, gx, gy, gyaw, gv, ga, max_accel, max_jerk, dt)if show_animation:# pragma: no cover
  112. plt.plot(x, y,"-r")
  113. plt.subplots()
  114. plt.plot(time,[np.rad2deg(i)for i in yaw],"-r")
  115. plt.xlabel("Time[s]")
  116. plt.ylabel("Yaw[deg]")
  117. plt.grid(True)
  118. plt.subplots()
  119. plt.plot(time, v,"-r")
  120. plt.xlabel("Time[s]")
  121. plt.ylabel("Speed[m/s]")
  122. plt.grid(True)
  123. plt.subplots()
  124. plt.plot(time, a,"-r")
  125. plt.xlabel("Time[s]")
  126. plt.ylabel("accel[m/ss]")
  127. plt.grid(True)
  128. plt.subplots()
  129. plt.plot(time, j,"-r")
  130. plt.xlabel("Time[s]")
  131. plt.ylabel("jerk[m/sss]")
  132. plt.grid(True)
  133. plt.show()if __name__ =='__main__':
  134. main()

在这里插入图片描述
在这里插入图片描述

上图模拟了车辆曲线的拟合过程的轨迹,箭头代表方向。

过程的速度在这里插入图片描述

感觉5次多项式和贝塞尔曲线还是挺像的,有时间写一篇五次多项式、贝塞尔曲线、样条曲线的对比。

还有一个问题就是为啥要用5次多项式,而不是4次,6次更高阶或者低阶呢?下回复习一下老王的讲解。
参考:


本文转载自: https://blog.csdn.net/weixin_43673156/article/details/129016974
版权归原作者 BineHello 所有, 如有侵权,请联系我们删除。

“自动驾驶规划 - 5次多项式拟合”的评论:

还没有评论