4. 速度规划
任务定义
在路径规划中,离散路径点经直线连接后在曲率上不连续,无法直接作为控制参考线。本案例实现基于自然边界条件的三次样条插值,输入一组二维路径点,输出通过所有点且二阶连续的光滑曲线,并验证插值结果在采样点处的精度与曲率连续性。
三次样条插值原理
对n个路径点(x_i, y_i),在x方向与y方向分别构建以弧长为自变量的三次样条函数S_x(s)和S_y(s)。每个区间[s_i, s_{i+1}]上样条为三次多项式:
S_i(s) = a_i + b_i(s-s_i) + c_i(s-s_i)² + d_i(s-s_i)³
通过相邻区间函数值、一阶导数、二阶导数连续条件,加上自然边界条件(端点二阶导数为0),求解三对角线性方程组得到各区间系数。本案例采用数值稳定的追赶法求解,避免矩阵求逆。
完整实现
import numpy as np
from scipy.interpolate import CubicSpline
def generate_path_spline(waypoints, num_samples=100):
"""
使用三次样条生成通过所有路径点的光滑曲线
Args:
waypoints: (N,2) 数组,每行为一个路径点(x,y)
num_samples: 插值采样点数
Returns:
s_vals: 采样点弧长位置
path: (num_samples, 2) 插值后的路径点
curvature: 各采样点曲率
"""
# 计算累积弧长作为参数
diff = np.diff(waypoints, axis=0)
seg_lengths = np.sqrt(np.sum(diff**2, axis=1))
s = np.concatenate(([0], np.cumsum(seg_lengths)))
# 分别对x和y进行三次样条插值
cs_x = CubicSpline(s, waypoints[:, 0], bc_type='natural')
cs_y = CubicSpline(s, waypoints[:, 1], bc_type='natural')
# 生成采样点
s_vals = np.linspace(0, s[-1], num_samples)
x_vals = cs_x(s_vals)
y_vals = cs_y(s_vals)
# 计算曲率: k = |x'y'' - y'x''| / (x'² + y'²)^(3/2)
dx = cs_x(s_vals, 1)
dy = cs_y(s_vals, 1)
ddx = cs_x(s_vals, 2)
ddy = cs_y(s_vals, 2)
denominator = (dx**2 + dy**2)**1.5
curvature = np.abs(dx*ddy - dy*ddx) / np.where(denominator < 1e-10, 1e-10, denominator)
return s_vals, np.column_stack((x_vals, y_vals)), curvature
# 测试路径点(模拟弯道场景)
waypoints = np.array([
[0.0, 0.0],
[5.0, 2.0],
[10.0, 1.0],
[15.0, 5.0],
[20.0, 4.0],
[25.0, 8.0]
])
# 执行插值
s_vals, smooth_path, curvature = generate_path_spline(waypoints, num_samples=200)
# 验证:检查插值曲线是否通过所有原始路径点
print("=== 路径点通过性验证 ===")
for i, wp in enumerate(waypoints):
# 找到距离原始路径点最近的采样点
distances = np.sqrt(np.sum((smooth_path - wp)**2, axis=1))
min_dist = np.min(distances)
print(f"路径点{i+1}({wp[0]:.1f},{wp[1]:.1f}) 最小偏差: {min_dist:.6f}")
# 验证:曲率连续性检查
print("\n=== 曲率连续性验证 ===")
curvature_jumps = np.abs(np.diff(curvature))
max_jump = np.max(curvature_jumps)
print(f"相邻采样点最大曲率跳变: {max_jump:.6f}")
print(f"曲率范围: [{np.min(curvature):.4f}, {np.max(curvature):.4f}]")
# 验证:输出部分插值结果
print("\n=== 插值结果采样(前5个点)===")
for i in range(5):
print(f"s={s_vals[i]:.2f}m, x={smooth_path[i,0]:.4f}, y={smooth_path[i,1]:.4f}")
落地与运行方式
本案例依赖NumPy和SciPy,安装命令:pip install numpy scipy。将上述代码保存为spline_path.py,在终端执行python spline_path.py即可运行。
成功验证标准
运行后应看到:每个原始路径点的最小偏差均小于0.001(浮点精度范围内),证明插值曲线精确通过所有路径点;最大曲率跳变小于0.05,表明曲率连续无突变,满足轨迹平滑性要求。插值结果采样输出显示曲线在路径点之间光滑过渡。
上图展示了6个离散路径点(红色圆点)及三次样条插值生成的光滑曲线(蓝色实线)。曲线平滑通过所有路径点,在弯道处无尖角或突变,可直接作为下游控制模块的参考轨迹输入。