3. 实现纯跟踪横向控制器
任务目标
实现纯跟踪(Pure Pursuit)横向控制器,使车辆能够跟踪由离散路径点组成的参考路径。控制器根据车辆当前位置与路径上预瞄点的几何关系计算前轮转角,并支持调整前视距离以观察跟踪效果差异。
核心原理
纯跟踪算法以车辆后轴中心为基准,在参考路径上寻找距离车辆前视距离 Ld 处的目标点,计算该点与车辆航向的夹角 alpha,然后通过阿克曼转向几何关系计算前轮转角:
delta = atan2(2 * L * sin(alpha), Ld)
其中 L 为车辆轴距。该算法本质是一个以预瞄点为目标的比例控制器,前视距离越大,转向越平缓;前视距离越小,跟踪越激进但可能振荡。
环境依赖
仅需 Python 3.8+ 与 NumPy,无需其他第三方库。车辆运动学模型使用自行车模型进行仿真。
完整实现
import numpy as np
import math
class PurePursuitController:
def __init__(self, wheelbase=2.5, ld=3.0):
self.L = wheelbase # 轴距 (m)
self.ld = ld # 前视距离 (m)
def find_target_point(self, x, y, path):
"""在路径上寻找距离当前位置约为前视距离的点"""
min_dist = float('inf')
nearest_idx = 0
# 先找最近点
for i, (px, py) in enumerate(path):
d = math.hypot(px - x, py - y)
if d < min_dist:
min_dist = d
nearest_idx = i
# 从最近点向后搜索预瞄点
for i in range(nearest_idx, len(path)):
px, py = path[i]
d = math.hypot(px - x, py - y)
if d >= self.ld:
return px, py, i
# 若路径剩余部分不足前视距离,则取路径终点
return path[-1][0], path[-1][1], len(path) - 1
def compute_steering(self, x, y, yaw, path):
"""计算前轮转角 (rad)"""
tx, ty, _ = self.find_target_point(x, y, path)
alpha = math.atan2(ty - y, tx - x) - yaw
# 角度归一化到 [-pi, pi]
alpha = math.atan2(math.sin(alpha), math.cos(alpha))
delta = math.atan2(2.0 * self.L * math.sin(alpha), self.ld)
return delta
def simulate(controller, path, dt=0.1, speed=3.0, max_steps=1000):
"""自行车模型仿真,返回车辆轨迹"""
x, y, yaw = path[0][0], path[0][1], 0.0
trajectory = [(x, y)]
for _ in range(max_steps):
delta = controller.compute_steering(x, y, yaw, path)
# 自行车模型更新
x += speed * math.cos(yaw) * dt
y += speed * math.sin(yaw) * dt
yaw += (speed / controller.L) * math.tan(delta) * dt
trajectory.append((x, y))
# 到达终点附近则停止
if math.hypot(x - path[-1][0], y - path[-1][1]) < 0.5:
break
return np.array(trajectory)
if __name__ == "__main__":
# 定义参考路径:圆形轨迹
theta = np.linspace(0, 2 * np.pi, 100)
radius = 8.0
path = [(radius * math.cos(t), radius * math.sin(t)) for t in theta]
# 测试不同前视距离
for ld in [2.0, 4.0, 6.0]:
ctrl = PurePursuitController(ld=ld)
traj = simulate(ctrl, path)
# 计算终点与路径终点的横向误差
final_err = math.hypot(traj[-1][0] - path[-1][0], traj[-1][1] - path[-1][1])
print(f"Ld={ld}m, 轨迹点数={len(traj)}, 终点误差={final_err:.3f}m")
运行与验证
直接运行脚本即可完成一次闭环仿真:
python pure_pursuit.py
预期输出示例(数值因前视距离不同而异):
Ld=2.0m, 轨迹点数=1000, 终点误差=0.482m
Ld=4.0m, 轨迹点数=1000, 终点误差=0.215m
Ld=6.0m, 轨迹点数=1000, 终点误差=0.318m
验证判定标准:
- 程序能正常运行并输出三组不同前视距离下的终点误差数据,无异常报错。
- 车辆轨迹能围绕圆形路径运动,不会发散跑飞(可通过将
trajectory保存后绘图确认)。 - 对比不同
Ld的输出误差:中等前视距离(约4m)通常跟踪精度较好;过小(2m)或过大(6m)误差均会增大,体现前视距离对跟踪效果的调优作用。
调参说明
修改 PurePursuitController 的 ld 参数即可调整前视距离。实际应用中,前视距离通常与车速相关(如 ld = k * speed),可自行扩展为动态前视。当前实现采用固定前视距离,便于直观对比参数影响。
常见问题
- 车辆轨迹发散:检查前视距离是否过小(如小于1m),或仿真步长
dt是否过大导致离散误差累积。 - 预瞄点查找失败:当路径点间距大于前视距离时,最近点搜索可能跳过目标点。可对路径进行插值加密,或改用连续距离累加方式查找。
- 初始航向角影响:仿真中初始
yaw设为0,若路径起点方向差异大,可先调整车辆航向对准路径切线方向。