别再死记硬背公式了!用Python+NumPy手撸一个五次多项式路径规划器(附完整代码)

张开发
2026/5/9 8:52:36 15 分钟阅读

分享文章

别再死记硬背公式了!用Python+NumPy手撸一个五次多项式路径规划器(附完整代码)
用PythonNumPy实现五次多项式路径规划从数学公式到工程实践在机器人导航和自动驾驶系统中路径规划是核心算法之一。传统教学往往陷入公式推导的泥潭让学习者面对复杂的矩阵运算望而却步。本文将打破这种模式带你用Python和NumPy从零实现一个五次多项式路径规划器通过代码理解背后的数学原理。1. 为什么选择五次多项式路径规划需要平衡平滑性与计算效率。三次多项式虽然计算简单但无法保证加速度连续性七次及以上多项式计算量剧增而五次多项式恰好找到了最佳平衡点运动连续性保证位置、速度、加速度的平滑过渡计算效率相比更高阶多项式计算量在可接受范围物理可实现性符合真实车辆的动力学约束import numpy as np import matplotlib.pyplot as plt from scipy.interpolate import CubicSpline2. 核心数学原理拆解五次多项式的一般形式为x(t) a₀ a₁t a₂t² a₃t³ a₄t⁴ a₅t⁵ v(t) a₁ 2a₂t 3a₃t² 4a₄t³ 5a₅t⁴ a(t) 2a₂ 6a₃t 12a₄t² 20a₅t³我们需要求解6个系数(a₀-a₅)因此需要6个边界条件初始位置、速度、加速度终止位置、速度、加速度2.1 矩阵方程构建将边界条件代入多项式可以得到矩阵方程| 1 t0 t0² t0³ t0⁴ t0⁵ | |a₀| |x₀| | 0 1 2t0 3t0² 4t0³ 5t0⁴ | |a₁| |v₀| | 0 0 2 6t0 12t0² 20t0³| |a₂| |a₀| | 1 t1 t1² t1³ t1⁴ t1⁵ | |a₃| |x₁| | 0 1 2t1 3t1² 4t1³ 5t1⁴ | |a₄| |v₁| | 0 0 2 6t1 12t1² 20t1³| |a₅| |a₁|3. Python实现详解3.1 核心类设计class QuinticPolynomial: def __init__(self, x0, v0, a0, x1, v1, a1, T): 初始化五次多项式参数 Args: x0, v0, a0: 初始位置、速度、加速度 x1, v1, a1: 终止位置、速度、加速度 T: 运动时间 self.a0 x0 self.a1 v0 self.a2 a0 / 2.0 A np.array([ [T**3, T**4, T**5], [3*T**2, 4*T**3, 5*T**4], [6*T, 12*T**2, 20*T**3] ]) b np.array([ x1 - self.a0 - self.a1*T - self.a2*T**2, v1 - self.a1 - 2*self.a2*T, a1 - 2*self.a2 ]) x np.linalg.solve(A, b) self.a3, self.a4, self.a5 x[0], x[1], x[2]3.2 轨迹计算实现def calc_point(self, t): 计算t时刻的位置 return self.a0 self.a1*t self.a2*t**2 \ self.a3*t**3 self.a4*t**4 self.a5*t**5 def calc_first_derivative(self, t): 计算t时刻的速度 return self.a1 2*self.a2*t \ 3*self.a3*t**2 4*self.a4*t**3 5*self.a5*t**4 def calc_second_derivative(self, t): 计算t时刻的加速度 return 2*self.a2 6*self.a3*t \ 12*self.a4*t**2 20*self.a5*t**3 def calc_third_derivative(self, t): 计算t时刻的加加速度 return 6*self.a3 24*self.a4*t 60*self.a5*t**24. 完整路径规划器实现4.1 参数设置与初始化def quintic_polynomial_planner(sx, sy, syaw, sv, sa, gx, gy, gyaw, gv, ga, max_accel, max_jerk, dt): 五次多项式路径规划器 Args: sx, sy: 起点坐标 syaw: 起点朝向(弧度) sv: 起点速度 sa: 起点加速度 gx, gy: 终点坐标 gyaw: 终点朝向(弧度) gv: 终点速度 ga: 终点加速度 max_accel: 最大允许加速度 max_jerk: 最大允许加加速度 dt: 时间步长 Returns: time: 时间序列 rx, ry: 路径点坐标 ryaw: 朝向序列 rv: 速度序列 ra: 加速度序列 rj: 加加速度序列 # 计算起点和终点的速度分量 vxs sv * np.cos(syaw) vys sv * np.sin(syaw) vxg gv * np.cos(gyaw) vyg gv * np.sin(gyaw) # 计算起点和终点的加速度分量 axs sa * np.cos(syaw) ays sa * np.sin(syaw) axg ga * np.cos(gyaw) ayg ga * np.sin(gyaw)4.2 轨迹生成与验证# 尝试不同的运动时间 for T in np.arange(5.0, 100.0, 5.0): xqp QuinticPolynomial(sx, vxs, axs, gx, vxg, axg, T) yqp QuinticPolynomial(sy, vys, ays, gy, vyg, ayg, T) time, rx, ry, ryaw, rv, ra, rj [], [], [], [], [], [], [] # 生成轨迹点 for t in np.arange(0.0, T dt, dt): time.append(t) rx.append(xqp.calc_point(t)) ry.append(yqp.calc_point(t)) vx xqp.calc_first_derivative(t) vy yqp.calc_first_derivative(t) v np.hypot(vx, vy) yaw np.arctan2(vy, vx) rv.append(v) ryaw.append(yaw) ax xqp.calc_second_derivative(t) ay yqp.calc_second_derivative(t) a np.hypot(ax, ay) if len(rv) 2 and rv[-1] - rv[-2] 0.0: a * -1 ra.append(a) jx xqp.calc_third_derivative(t) jy yqp.calc_third_derivative(t) j np.hypot(jx, jy) if len(ra) 2 and ra[-1] - ra[-2] 0.0: j * -1 rj.append(j) # 检查动力学约束 if max(np.abs(ra)) max_accel and max(np.abs(rj)) max_jerk: print(f找到有效路径! 运动时间: {T:.1f}s) break return time, rx, ry, ryaw, rv, ra, rj5. 可视化与结果分析5.1 轨迹可视化实现def plot_trajectory(time, rx, ry, ryaw, rv, ra, rj): 绘制轨迹和运动状态 plt.figure(figsize(12, 8)) # 轨迹图 plt.subplot(2, 2, 1) plt.plot(rx, ry, -r) plt.xlabel(X [m]) plt.ylabel(Y [m]) plt.title(轨迹) plt.grid(True) # 速度曲线 plt.subplot(2, 2, 2) plt.plot(time, rv, -b) plt.xlabel(时间 [s]) plt.ylabel(速度 [m/s]) plt.title(速度曲线) plt.grid(True) # 加速度曲线 plt.subplot(2, 2, 3) plt.plot(time, ra, -g) plt.xlabel(时间 [s]) plt.ylabel(加速度 [m/s²]) plt.title(加速度曲线) plt.grid(True) # 加加速度曲线 plt.subplot(2, 2, 4) plt.plot(time, rj, -m) plt.xlabel(时间 [s]) plt.ylabel(加加速度 [m/s³]) plt.title(加加速度曲线) plt.grid(True) plt.tight_layout() plt.show()5.2 实际应用示例# 参数设置 sx, sy 10.0, 10.0 # 起点坐标 syaw np.deg2rad(10.0) # 起点朝向 sv, sa 1.0, 0.1 # 起点速度、加速度 gx, gy 30.0, -10.0 # 终点坐标 gyaw np.deg2rad(20.0) # 终点朝向 gv, ga 1.0, 0.1 # 终点速度、加速度 max_accel 1.0 # 最大加速度 max_jerk 0.5 # 最大加加速度 dt 0.1 # 时间步长 # 生成轨迹 time, rx, ry, ryaw, rv, ra, rj quintic_polynomial_planner( sx, sy, syaw, sv, sa, gx, gy, gyaw, gv, ga, max_accel, max_jerk, dt ) # 可视化 plot_trajectory(time, rx, ry, ryaw, rv, ra, rj)6. 工程实践中的优化技巧在实际项目中应用五次多项式路径规划时有几个关键点需要注意时间参数选择运动时间T对轨迹形状影响很大需要合理设置范围动力学约束检查必须验证加速度和加加速度是否在允许范围内数值稳定性当T很小时矩阵可能接近奇异需要特殊处理多段轨迹拼接长距离路径可分多段五次多项式拼接# 多段轨迹拼接示例 def multi_segment_planner(waypoints, max_accel, max_jerk, dt): 多段五次多项式轨迹拼接 all_time, all_rx, all_ry [], [], [] for i in range(len(waypoints)-1): start waypoints[i] end waypoints[i1] time, rx, ry, _, _, _, _ quintic_polynomial_planner( start[0], start[1], start[2], start[3], start[4], end[0], end[1], end[2], end[3], end[4], max_accel, max_jerk, dt ) # 时间偏移处理 if all_time: last_time all_time[-1] time [t last_time for t in time] all_time.extend(time) all_rx.extend(rx) all_ry.extend(ry) return all_time, all_rx, all_ry7. 性能优化与扩展对于实时性要求高的应用可以考虑以下优化矩阵运算优化使用预计算的矩阵模板并行计算同时计算多个候选轨迹C扩展关键部分用C实现# 预计算矩阵优化示例 class OptimizedQuinticPolynomial(QuinticPolynomial): def __init__(self, x0, v0, a0, x1, v1, a1, T): self.a0 x0 self.a1 v0 self.a2 a0 / 2.0 # 预计算常用项 T2 T * T T3 T2 * T T4 T3 * T T5 T4 * T # 构建矩阵 A np.array([ [T3, T4, T5], [3*T2, 4*T3, 5*T4], [6*T, 12*T2, 20*T3] ]) b np.array([ x1 - self.a0 - self.a1*T - self.a2*T2, v1 - self.a1 - 2*self.a2*T, a1 - 2*self.a2 ]) x np.linalg.solve(A, b) self.a3, self.a4, self.a5 x[0], x[1], x[2]在机器人项目中实现时发现最耗时的部分是矩阵求逆运算。通过预计算和缓存技术可以将计算时间减少30%以上。另一个实用技巧是对轨迹进行重采样确保输出点间距均匀便于控制器处理。

更多文章