保姆级教程:用Python从零实现自动驾驶的Pure Pursuit轨迹跟踪算法
从零实现自动驾驶Python版Pure Pursuit算法全解析第一次看到自动驾驶车辆沿着预定轨迹平稳行驶时我被这种看似有意识的路径跟踪能力深深吸引。作为初学者最令人兴奋的莫过于用几十行Python代码就能复现这种智能行为。本文将带你从零开始用最直观的方式实现Pure Pursuit算法——这个在工业界广泛应用的轨迹跟踪方法。1. 理解Pure Pursuit的核心思想想象你正在骑自行车追赶前方的朋友。你不会死死盯着朋友的脚跟而是会看向前方几米处根据那个预瞄点调整车把角度。Pure Pursuit算法正是模拟这种人类本能——它让车辆始终瞄准路径前方的一个虚拟点通过调整转向角使车辆沿着圆弧接近该点。算法核心只有三步在路径上选择一个预瞄点通常距离车辆后轴中心L米计算使车辆圆弧轨迹经过该点的前轮转角持续更新预瞄点形成闭环控制# 伪代码展示Pure Pursuit流程 while 车辆未到达终点: 当前位姿 获取车辆位置() 预瞄点 在路径上查找距离L的点() 转向角 计算阿克曼转向角(预瞄点) 执行转向控制(转向角)2. 搭建Python仿真环境我们使用matplotlib创建可视化环境避免复杂的游戏引擎。这个轻量级方案能清晰展示算法每个步骤。首先建立车辆和轨迹的表示import numpy as np import matplotlib.pyplot as plt class Vehicle: def __init__(self, x0, y0, yaw0, length2.5): self.x x # 后轴中心x坐标 self.y y # 后轴中心y坐标 self.yaw yaw # 航向角弧度 self.length length # 轴距 self.steering_angle 0 # 当前转向角 def update(self, steering, velocity1, dt0.1): # 基于自行车模型的位姿更新 self.x velocity * np.cos(self.yaw) * dt self.y velocity * np.sin(self.yaw) * dt self.yaw (velocity / self.length) * np.tan(steering) * dt self.steering_angle steering注意这里使用简化的自行车模型假设后轮无侧滑。实际车辆动力学更复杂但对算法理解足够。3. 实现阿克曼转向计算阿克曼几何确保车辆转向时所有轮胎绕同一瞬时中心旋转。虽然真实车辆有复杂的转向机构但我们用等效的自行车模型简化计算def pure_pursuit_control(vehicle, path, lookahead_dist): # 找到距离车辆最近的路径点 nearest_idx np.argmin([(vehicle.x - p[0])**2 (vehicle.y - p[1])**2 for p in path]) # 在路径上搜索预瞄点 for i in range(nearest_idx, len(path)): dist np.sqrt((path[i][0] - vehicle.x)**2 (path[i][1] - vehicle.y)**2) if dist lookahead_dist: target path[i] break else: target path[-1] # 如果找不到选择终点 # 计算转向角 alpha np.arctan2(target[1] - vehicle.y, target[0] - vehicle.x) - vehicle.yaw steering np.arctan2(2 * vehicle.length * np.sin(alpha), lookahead_dist) return steering, target参数调节技巧预瞄距离(L)相当于前瞻距离越大跟踪越平滑但延迟明显车速通常需要与预瞄距离动态适配路径密度离散路径点间距建议为0.1-0.5倍轴距4. 完整仿真案例让我们创建一个8字形路径并观察跟踪效果# 生成8字形参考路径 theta np.linspace(0, 2*np.pi, 100) path_x 10 * np.sin(theta) path_y 5 * np.sin(2*theta) path np.column_stack((path_x, path_y)) # 初始化车辆 car Vehicle(x-5, y0, yawnp.pi/2) lookahead 3.0 # 预瞄距离 # 仿真循环 plt.figure(figsize(10,5)) for _ in range(200): steering, target pure_pursuit_control(car, path, lookahead) car.update(steering) # 可视化 plt.cla() plt.plot(path[:,0], path[:,1], --, colorgray, label参考路径) plt.plot(car.x, car.y, bo, label车辆) plt.plot(target[0], target[1], ro, label预瞄点) plt.axis(equal) plt.legend() plt.pause(0.01)运行这段代码你会看到蓝色车辆点逐渐跟踪上灰色参考路径红色点表示当前跟踪的预瞄点。尝试调整lookahead参数观察跟踪行为变化预瞄距离跟踪特性适用场景1.0-2.0紧密跟踪低速精确路径3.0-5.0平滑跟踪中高速行驶5.0延迟明显高速直道5. 进阶优化与实践技巧基础实现虽然能工作但实际项目还需要考虑路径预处理原始路径可能有噪声或不平滑from scipy import signal # 使用Savitzky-Golay滤波器平滑路径 window_size, poly_order 11, 3 smoothed_x signal.savgol_filter(path[:,0], window_size, poly_order) smoothed_y signal.savgol_filter(path[:,1], window_size, poly_order)动态预瞄距离根据车速自适应调整def dynamic_lookahead(speed, min_dist2.0, max_dist8.0, gain0.3): return np.clip(gain * speed, min_dist, max_dist)跟踪误差处理当车辆偏离路径时的恢复策略if nearest_dist 2 * lookahead: # 执行恢复程序停车或重新规划路径 print(警告车辆严重偏离路径)在真实项目中测试时我发现预瞄距离与车速的比值保持在0.3-0.5秒即预瞄距离0.4×车速能获得较好的平衡。例如车速10m/s时预瞄距离设为4米左右。