1. Lattice规划算法核心思想解析
Lattice(晶格)规划算法是自动驾驶运动规划领域的经典方法,其核心思想是通过在Frenet坐标系下构建规则化的采样空间,将连续的高维规划问题转化为离散的轨迹点搜索问题。这种结构化采样方式相比随机采样(如RRT算法)具有计算效率高、轨迹平滑性好、可预测性强等显著优势。
Frenet坐标系以道路中心线为参考基准,将车辆运动分解为纵向(s方向)和横向(d方向)两个维度。这种表示方法天然适配道路结构化环境,使得轨迹规划可以独立考虑路径跟踪(横向控制)和速度规划(纵向控制)。在实际工程实现中,我们通常会在s方向按固定间隔(如0.5米)设置采样点,在每个采样点的d方向生成若干候选偏移量,形成规则的网格状采样结构。
关键理解:Lattice采样不是简单的二维平面离散化,而是在考虑了车辆运动学约束的时空联合空间中进行采样。每个采样点实际上是一个(s,d,t)三元组,包含纵向位置、横向偏移和时间信息。
2. 轨迹生成与采样策略
2.1 横向轨迹生成方法
横向轨迹决定了车辆的换道或避障行为,常用的生成方式包括:
- 多项式插值:使用五次多项式连接初始状态(d0, d0', d0'')和目标状态(d1, d1', d1''),确保轨迹在起点和终点处的位移、速度、加速度连续
matlab复制% 五次多项式系数计算示例
A = [1, t, t^2, t^3, t^4, t^5;
0, 1, 2*t, 3*t^2, 4*t^3, 5*t^4;
0, 0, 2, 6*t, 12*t^2, 20*t^3];
b = [d1; d1'; d1''];
coeff = A \ b; % 求解多项式系数
- 样条曲线:特别适合复杂道路几何形状,能够保证曲率连续
- 圆弧过渡:计算简单但连续性较差,多用于低速场景
2.2 纵向速度规划策略
纵向速度剖面需要考虑舒适性、效率和安全约束,典型模式包括:
- 跟车模式:保持与前车的安全时距(通常2-3秒)
- 定速巡航:维持设定速度行驶
- 停车让行:规划减速度舒适的制动曲线
- 紧急制动:最大减速度下的安全停止
速度曲线生成常采用匀加速/匀减速模型,配合jerk(加加速度)限制:
code复制v(t) = v0 + a*t + 0.5*j*t^2
s(t) = v0*t + 0.5*a*t^2 + (1/6)*j*t^3
2.3 时空联合采样技巧
实际工程中需要平衡采样密度和计算效率:
- 横向采样:通常在±1个车道宽度范围内采样5-7个点
- 时间分层:规划周期内分3-5个时间层,每层时间间隔0.5-1秒
- 动态调整:根据场景复杂度自适应调整采样密度(如弯道增加横向采样)
3. 轨迹评估指标体系设计
3.1 舒适性指标
- 横向加速度:一般限制在0.3g以内
- 纵向加加速度(jerk):建议小于0.6 m/s³
- 曲率变化率:影响转向平顺性
3.2 安全性指标
- 与障碍物的最小距离
- 制动距离裕度
- 可干预时间(Time To Collision, TTC)
3.3 效率指标
- 行程时间
- 平均速度
- 偏离参考路径的积分误差
3.4 综合代价函数
典型的多目标加权形式:
code复制cost = w1*comfort_cost + w2*safety_cost + w3*efficiency_cost
权重配置需要根据驾驶策略调整(如激进型vs保守型)。实际工程中常采用分层加权策略,先确保安全性,再优化其他指标。
4. 碰撞检测实现细节
4.1 车辆包围盒建模
通常采用矩形或圆形近似:
- 矩形包围盒:需要考虑车辆航向角
matlab复制function [x_corners, y_corners] = getBoundingBox(x, y, yaw, length, width)
cos_yaw = cos(yaw);
sin_yaw = sin(yaw);
dx = length/2;
dy = width/2;
x_corners = x + [-dx, dx, dx, -dx]*cos_yaw - [-dy, -dy, dy, dy]*sin_yaw;
y_corners = y + [-dx, dx, dx, -dx]*sin_yaw + [-dy, -dy, dy, dy]*cos_yaw;
end
- 圆形包络:计算简单但保守,适合快速筛选
4.2 连续碰撞检测
为避免离散检测的漏检问题,可采用:
- 扫描体积法:检查轨迹段扫过的体积与障碍物交集
- 轨迹包络线:构建轨迹的保守边界
- 运动膨胀:根据速度动态扩大障碍物尺寸
4.3 加速检测技巧
- 空间划分:使用KD-tree或网格划分加速邻居查找
- 层次检测:先粗检测后精检测
- 并行计算:GPU加速碰撞检测
5. Matlab实现关键代码解析
5.1 轨迹采样核心代码
matlab复制function trajectories = sampleLatticeTrajectories(initial_state, target_states, T)
num_trajs = size(target_states, 1);
trajectories = cell(1, num_trajs);
for i = 1:num_trajs
% 横向轨迹生成
lat_coeff = solveQuinticCoeff(initial_state.lat, target_states(i).lat, T);
% 纵向轨迹生成
lon_coeff = solveQuarticCoeff(initial_state.lon, target_states(i).lon, T);
% 时空轨迹合成
t = linspace(0, T, 50);
s = polyval(lon_coeff, t);
d = polyval(lat_coeff, t);
trajectories{i} = struct('t', t, 's', s, 'd', d);
end
end
5.2 代价评估实现
matlab复制function costs = evaluateTrajectories(trajectories, ref_path, obstacles)
num_trajs = length(trajectories);
costs = zeros(1, num_trajs);
for i = 1:num_trajs
traj = trajectories{i};
% 舒适性代价
jerk = max(abs(diff(traj.acc, 2)));
% 路径偏离代价
dev_cost = mean(abs(traj.d - ref_path.d(traj.s)));
% 碰撞代价
collision = checkCollision(traj, obstacles);
% 综合代价
costs(i) = 0.3*jerk + 0.2*dev_cost + 0.5*collision;
end
end
6. 工程实践中的挑战与解决方案
6.1 实时性优化
- 采样空间剪枝:提前剔除明显不合理的轨迹
- 轨迹缓存:复用上一周期的可行轨迹作为初始解
- 硬件加速:使用SIMD指令或GPU并行计算
6.2 特殊场景处理
- 拥堵场景:引入博弈论考虑他车反应
- 紧急避障:设计fallback安全轨迹
- 复杂路口:结合语义信息调整采样策略
6.3 参数调优经验
- 舒适性参数:通过实车测试调整jerk阈值
- 安全距离:考虑传感器误差和系统延迟
- 权重配置:采用自适应权重策略
7. 实际调试中的典型问题
- 轨迹抖动问题:
- 检查多项式阶数是否足够
- 验证边界条件设置是否正确
- 增加jerk惩罚项权重
- 漏检碰撞:
- 确认时间分辨率足够高(建议≤0.1s)
- 检查障碍物膨胀半径
- 验证坐标系转换准确性
- 规划延迟:
- 分析耗时瓶颈(通常是碰撞检测)
- 采用多分辨率采样策略
- 考虑轨迹预测提前量
在实车部署中,我们发现最关键的调试环节是代价函数的权重配置。建议先在仿真环境中构建典型测试场景(跟车、换道、避障等),通过大量测试找到各代价项的合理权重范围,再通过实车测试进行微调。一个实用的技巧是记录人类驾驶数据作为参考,对比算法生成的轨迹与人类驾驶轨迹在各代价项上的差异。