1. 项目概述
车道线识别和循迹控制确实是自动驾驶技术中最基础也最关键的环节之一。作为一名在自动驾驶领域工作多年的工程师,我发现很多刚入行的朋友对这个看似简单的功能存在不少误解。实际上,从图像识别到控制执行,每个环节都藏着不少"坑"。
PreScan作为专业的自动驾驶仿真平台,为我们提供了一个接近真实的测试环境。结合MPC(模型预测控制)和LQR(线性二次调节器)这两种经典控制算法,可以构建出相当可靠的车道保持系统。不过在实际操作中,如何调参、如何处理识别误差、如何应对不同路况,这些才是真正考验工程师经验的地方。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境搭建与PreScan配置
2.1 PreScan基础环境准备
首先需要安装PreScan和MATLAB(建议R2020b及以上版本)。安装完成后,我建议先创建一个简单的直线道路场景进行测试:
- 在PreScan中新建工程
- 从"Road"库中拖拽"Straight Road"到场景
- 设置道路长度为200米,宽度为3.5米(标准车道宽度)
- 添加车辆模型,建议使用PreScan自带的"Car_1"模型
注意:PreScan的物理引擎对硬件有一定要求,建议使用独立显卡的电脑运行。如果遇到卡顿,可以尝试降低图形质量设置。
2.2 传感器配置
车道线识别主要依赖摄像头传感器:
- 在车辆上添加"Camera"传感器
- 设置摄像头参数:
- 分辨率:1280×720
- 视场角:60度
- 安装高度:1.2米(模拟前装摄像头)
- 俯仰角:-10度(使摄像头略微向下)
- 添加雷达传感器(可选,用于障碍物检测)
matlab复制% 在MATLAB中初始化传感器参数
cameraParams = monoCameraParameters(...
'IntrinsicMatrix',[1250 0 640; 0 1250 360; 0 0 1],...
'ImageSize',[720 1280],...
'WorldUnits','meters');
3. 车道线识别算法实现
3.1 图像预处理
从PreScan获取的原始图像需要经过以下处理步骤:
- 灰度转换:将RGB图像转为灰度图
- 高斯滤波:消除噪声,核大小建议5×5
- 边缘检测:使用Canny算法,阈值设置很关键(我通常用50和150)
- 透视变换:将图像转为鸟瞰视图
matlab复制% 图像预处理示例代码
grayImg = rgb2gray(cameraImg);
blurImg = imgaussfilt(grayImg, 2);
edgeImg = edge(blurImg, 'Canny', [0.1 0.3]);
% 定义透视变换矩阵
perspectiveTform = estimateGeometricTransform(...
[x1,y1; x2,y2; x3,y3; x4,y4],... % 源点
[u1,v1; u2,v2; u3,v3; u4,v4],... % 目标点
'projective');
birdView = imwarp(edgeImg, perspectiveTform);
3.2 车道线检测
我常用的是滑动窗口法结合多项式拟合:
- 对鸟瞰图进行直方图分析,找到车道线起始位置
- 设置9个滑动窗口(高度方向)
- 在每个窗口内识别车道线像素
- 使用二阶多项式拟合车道线
matlab复制% 车道线拟合示例
[leftx, lefty, rightx, righty] = find_lane_pixels(birdView);
left_fit = polyfit(lefty, leftx, 2);
right_fit = polyfit(righty, rightx, 2);
% 计算车辆位置偏移量
lane_center = (left_fit(1)*y^2 + left_fit(2)*y + left_fit(3) + ...
right_fit(1)*y^2 + right_fit(2)*y + right_fit(3)) / 2;
vehicle_offset = (image_width/2 - lane_center) * xm_per_pix;
实操心得:多项式拟合对噪声很敏感。我通常会加入一个低通滤波器,平滑连续帧之间的拟合结果,避免车道线抖动。
4. 循迹控制算法实现
4.1 车辆动力学模型
无论是MPC还是LQR,都需要建立车辆动力学模型。常用的自行车模型:
code复制ẋ = v * cos(θ + β)
ẏ = v * sin(θ + β)
θ̇ = (v / l_r) * sin(β)
β = arctan((l_r / (l_f + l_r)) * tan(δ_f))
其中:
- (x,y):车辆位置
- θ:航向角
- v:车速
- δ_f:前轮转角
- l_f/l_r:前后轴到重心的距离
4.2 LQR控制器设计
LQR需要定义状态向量x和输入u:
code复制x = [横向误差; 航向误差; 横向误差变化率; 航向误差变化率]
u = 前轮转角
代价函数:
code复制J = ∫(x'Qx + u'Ru)dt
matlab复制% LQR控制器设计示例
A = [0 1 0 0;
0 0 C_alpha_f/m 0;
0 0 0 1;
0 0 (a*C_alpha_f - b*C_alpha_r)/I_z 0];
B = [0; C_alpha_f/m; 0; a*C_alpha_f/I_z];
Q = diag([10 1 1 0.1]); % 状态权重
R = 1; % 控制输入权重
[K, S, e] = lqr(A, B, Q, R);
4.3 MPC控制器设计
MPC相比LQR能更好地处理约束条件:
- 定义预测时域(N=10)和控制时域(Nc=5)
- 构建优化问题:
code复制min Σ(x'Qx + u'Ru) s.t. x_k+1 = Ax_k + Bu_k u_min ≤ u ≤ u_max Δu_min ≤ Δu ≤ Δu_max - 使用quadprog求解
matlab复制% MPC控制器设计示例
H = blkdiag(kron(eye(Nc), R), kron(eye(N), Q));
f = zeros(Nc*m + N*n, 1);
Aeq = [kron(eye(N), -B) eye(N*n) - [zeros(n, N*n); kron(eye(N-1), A) zeros((N-1)*n, n)]];
beq = [A; zeros((N-1)*n, 1)] * x0;
[z, fval] = quadprog(H, f, [], [], Aeq, beq, lb, ub);
u = z(1:m);
避坑指南:MPC的计算量较大,在实际应用中需要考虑实时性。我通常会将预测时域控制在10步以内,采样时间50ms左右。
5. 仿真测试与参数调优
5.1 测试场景设计
建议分阶段测试:
- 直线道路(验证基本功能)
- 恒定曲率弯道(验证转向控制)
- S型弯道(验证控制器响应速度)
- 带噪声的车道线(验证鲁棒性)
5.2 控制器参数调优
LQR调参经验:
- 先调Q矩阵中对横向误差的权重
- 再调航向误差权重
- 最后微调变化率权重
- R值通常从1开始,根据转向幅度调整
MPC调参经验:
- 预测时域:5-10步(对应1-2秒)
- 控制时域:预测时域的1/2到2/3
- 权重矩阵:参考LQR的设置
- 约束条件:
- 最大转向角:±30度
- 最大转向速率:±15度/秒
5.3 性能评估指标
我常用的评估指标:
- 横向误差RMS值(<0.1m优秀)
- 最大横向误差(<0.3m可接受)
- 转向角变化率(反映控制平滑性)
- 计算时间(单步<50ms)
6. 常见问题与解决方案
6.1 车道线识别问题
问题1:车道线检测不稳定
- 检查透视变换矩阵是否准确
- 尝试调整Canny阈值
- 加入帧间滤波
问题2:弯道识别效果差
- 增加多项式阶数(尝试三阶)
- 调整滑动窗口数量
- 检查鸟瞰图范围是否足够
6.2 控制问题
问题1:车辆振荡
- 减小LQR的Q矩阵中误差变化率权重
- 增加MPC的转向速率约束
- 检查车辆模型参数是否准确
问题2:过弯时偏离车道
- 增加预测时域
- 调整车辆模型中的轮胎侧偏刚度
- 检查速度是否过高
6.3 实时性问题
问题:控制周期不达标
- 减少MPC的预测步数
- 使用更高效的QP求解器
- 考虑代码优化(如预计算H矩阵)
7. 进阶优化方向
在实际项目中,我还尝试过以下优化方法:
- 基于曲率的前馈控制:在MPC/LQR基础上加入前馈项,提前补偿弯道转向
- 参数自适应:根据车速自动调整控制器参数
- 多传感器融合:结合GPS和IMU数据提高鲁棒性
- 机器学习方法:使用CNN直接端到端输出控制指令(需要大量数据)
经过多次项目实践,我发现MPC在性能上确实优于LQR,特别是在复杂路况下。但LQR的实现简单、计算量小,对于简单的车道保持已经足够。选择哪种方案,还是要根据具体的应用场景和硬件条件来决定。
