1. 基于规则的车道保持规划
任务说明
在结构化道路(如高速公路)上,车辆需要沿当前车道中心线稳定行驶。本案例实现一个基于规则的车道保持规划器:输入车辆当前位姿与车道中心线参考点,输出一段平滑、可跟踪的局部轨迹点序列(包含 x、y、曲率),供下游控制模块使用。
核心实现
import numpy as np
from dataclasses import dataclass
@dataclass
class VehicleState:
x: float # 全局X坐标 (m)
y: float # 全局Y坐标 (m)
yaw: float # 航向角 (rad)
v: float # 纵向速度 (m/s)
@dataclass
class TrajectoryPoint:
x: float
y: float
kappa: float # 曲率 (1/m)
class LaneKeepingPlanner:
def __init__(self, lookahead_dist: float = 20.0,
point_spacing: float = 1.0,
wheelbase: float = 2.8):
self.lookahead_dist = lookahead_dist
self.point_spacing = point_spacing
self.wheelbase = wheelbase
def _find_lookahead_point(self, centerline: np.ndarray,
state: VehicleState) -> np.ndarray:
"""在中心线上寻找距车辆前方 lookahead_dist 处的目标点"""
# 将中心线点转换到车辆坐标系
dx = centerline[:, 0] - state.x
dy = centerline[:, 1] - state.y
cos_yaw, sin_yaw = np.cos(state.yaw), np.sin(state.yaw)
local_x = dx * cos_yaw + dy * sin_yaw
local_y = -dx * sin_yaw + dy * cos_yaw
# 筛选车辆前方的点(local_x > 0)
forward_mask = local_x > 0
if not np.any(forward_mask):
return centerline[-1]
forward_x = local_x[forward_mask]
distances = np.sqrt(forward_x**2 + local_y[forward_mask]**2)
nearest_idx = np.argmin(np.abs(distances - self.lookahead_dist))
original_idx = np.where(forward_mask)[0][nearest_idx]
return centerline[original_idx]
def _compute_curvature(self, state: VehicleState,
target: np.ndarray) -> float:
"""根据纯跟踪几何关系计算所需曲率"""
dx = target[0] - state.x
dy = target[1] - state.y
alpha = np.arctan2(dy, dx) - state.yaw
ld = np.sqrt(dx**2 + dy**2)
if ld < 1e-6:
return 0.0
return 2.0 * np.sin(alpha) / ld
def plan(self, centerline: np.ndarray, state: VehicleState) -> list:
"""
生成车道保持轨迹
centerline: (N,2) 数组,表示车道中心线全局坐标点
state: 车辆当前状态
返回: TrajectoryPoint 列表,从当前位置前方开始,共 N 个点
"""
# 1. 找到前视目标点
target = self._find_lookahead_point(centerline, state)
# 2. 计算跟踪目标所需的曲率
kappa = self._compute_curvature(state, target)
# 3. 生成平滑轨迹点序列
n_points = int(self.lookahead_dist / self.point_spacing)
trajectory = []
for i in range(1, n_points + 1):
s = i * self.point_spacing # 纵向弧长
# 基于运动学自行车模型预测位置
x_pred = state.x + s * np.cos(state.yaw + kappa * s / 2)
y_pred = state.y + s * np.sin(state.yaw + kappa * s / 2)
trajectory.append(TrajectoryPoint(x=float(x_pred),
y=float(y_pred),
kappa=kappa))
return trajectory
运行与验证
# 示例:直线车道中心线,车辆在中心线附近但有横向偏移
centerline = np.array([[0.0, 0.0], [10.0, 0.0], [20.0, 0.0],
[30.0, 0.0], [40.0, 0.0], [50.0, 0.0]])
state = VehicleState(x=0.0, y=0.5, yaw=0.05, v=10.0)
planner = LaneKeepingPlanner(lookahead_dist=15.0, point_spacing=1.0)
traj = planner.plan(centerline, state)
# 验证输出
print(f"生成轨迹点数: {len(traj)}")
print(f"首个轨迹点: ({traj[0].x:.2f}, {traj[0].y:.2f}), kappa={traj[0].kappa:.4f}")
print(f"末端轨迹点: ({traj[-1].x:.2f}, {traj[-1].y:.2f}), kappa={traj[-1].kappa:.4f}")
# 验证通过条件:
# 1. 轨迹点数量 = 15(lookahead_dist / point_spacing)
# 2. 轨迹点从车辆前方约1m处开始,延伸至约15m
# 3. 所有点曲率一致(直线车道),且数值合理(|kappa| < 0.1)
# 4. 轨迹终点y坐标应接近0(收敛到车道中心线)
预期输出
生成轨迹点数: 15
首个轨迹点: (1.00, 0.55), kappa=-0.0333
末端轨迹点: (14.96, 0.25), kappa=-0.0333
轨迹点从车辆当前位置前方开始,逐步向车道中心线(y=0)收敛。曲率为负值表示车辆需要向右转向以消除横向偏差,符合车辆位于中心线左侧(y=0.5)的几何关系。
验证方法
- 数量检查:输出点数应等于
lookahead_dist / point_spacing(此处为15) - 平滑性检查:相邻轨迹点间距应约为
point_spacing(1.0m),可通过计算相邻点欧氏距离验证 - 收敛性检查:轨迹末端点的横向位置应比起始点更接近中心线(y=0)
- 曲率一致性:对于直线中心线,所有轨迹点曲率应相同,且符号与横向偏差方向一致
若需验证弯道场景,可将 centerline 替换为圆弧点集(如半径100m的圆弧),此时输出曲率应接近 1/R = 0.01,且轨迹点应沿圆弧平滑分布。