在自动驾驶和智能交通领域,让车辆精准跟踪预定轨迹是个经典难题。去年我在开发园区无人配送车时,就遇到过车辆在弯道处总是偏离轨迹的问题。传统PID控制在这种非线性场景下表现不佳,直到尝试了基于CasADi的模型预测控制(MPC)方案,才真正实现了厘米级的跟踪精度。
这个项目将带您用Matlab实现一套完整的MPC控制器,核心是通过CasADi框架将轨迹跟踪问题转化为优化问题求解。相比传统控制方法,MPC最大的优势在于能够显式处理系统约束(如速度限制、加速度限制),同时基于预测时域内的系统行为进行滚动优化。下面这张表格对比了几种常见控制方法的特性:
| 控制方法 | 处理非线性能力 | 约束处理 | 计算复杂度 | 适用场景 |
|---|---|---|---|---|
| PID控制 | 弱 | 不支持 | 低 | 简单线性系统 |
| LQR控制 | 弱 | 部分支持 | 中 | 线性最优控制 |
| MPC控制 | 强 | 显式支持 | 高 | 复杂约束系统 |
MPC的核心思想可以用一个简单的类比理解:就像开车时不断观察前方道路并调整方向盘,而不是只盯着当前的车轮位置。具体到数学模型,我们需要:
建立质点车辆的运动学模型:
code复制x_{k+1} = x_k + v_k*cos(θ_k)*dt
y_{k+1} = y_k + v_k*sin(θ_k)*dt
θ_{k+1} = θ_k + (v_k/L)*tan(δ_k)*dt
其中(x,y)是位置,θ是航向角,v是速度,δ是前轮转角,L是轴距。
设计代价函数(以轨迹跟踪为例):
math复制J = Σ(||[x,y] - [x_{ref},y_{ref}]||² + λ||δ||²)
第一项惩罚跟踪误差,第二项防止转向过于激进。
CasADi是我选择的核心工具,原因有三:
注意:安装CasADi时建议使用官方预编译版本,避免从源码编译时遇到依赖问题。在Matlab中只需将解压后的文件夹添加到路径即可。
首先准备Matlab环境(建议R2020b以上版本):
matlab复制addpath('casadi-3.6.3-windows64-matlab2018b') % 添加CasADi路径
import casadi.* % 导入符号计算库
% 定义系统状态和控制量
x = SX.sym('x'); y = SX.sym('y'); theta = SX.sym('theta');
states = [x; y; theta]; n_states = length(states);
v = SX.sym('v'); delta = SX.sym('delta');
controls = [v; delta]; n_controls = length(controls);
定义车辆运动学模型和物理约束:
matlab复制% 运动学方程
rhs = [v*cos(theta); v*sin(theta); (v/L)*tan(delta)];
% 创建函数句柄
f = Function('f', {states,controls}, {rhs});
% 设置约束条件
v_max = 2.0; delta_max = pi/4; % 最大速度2m/s,最大转角45度
关键的优化问题构建部分:
matlab复制% 初始化优化变量
U = SX.sym('U', n_controls, N); % 控制序列
X = SX.sym('X', n_states, N+1); % 状态序列
% 构建代价函数
J = 0;
for k = 1:N
st = X(:,k); con = U(:,k);
J = J + (st(1)-xref(k))^2 + (st(2)-yref(k))^2; % 位置误差
J = J + 0.1*con(2)^2; % 转向惩罚项
end
% 设置求解器
opts = struct;
opts.ipopt.max_iter = 100;
cont = nlpsol('cont', 'ipopt', nlp_prob, opts);
经过多次实测,我发现这几个参数对性能影响最大:
实测技巧:先用全局优化(如遗传算法)粗调参数范围,再用局部搜索精细调整。
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 求解器报错 | 初始猜测不合理 | 用上一时刻解作为初始猜测 |
| 跟踪震荡 | 权重设置不当 | 增加控制量惩罚项权重 |
| 计算延迟 | 预测时域过长 | 减少N或使用热启动策略 |
| 偏离轨迹 | 模型误差大 | 校验运动学模型参数 |
在我的测试场景中,设定一个S型参考轨迹,MPC控制器在3m/s速度下实现了:
如果想进一步提升性能,可以考虑:
最后分享一个调试心得:在Matlab中实时可视化预测轨迹非常重要,我通常会绘制三组曲线:
matlab复制plot(ref_path(:,1), ref_path(:,2), 'b--'); % 参考轨迹
plot(x_pred, y_pred, 'r-'); % 预测轨迹
plot(x_hist, y_hist, 'g.'); % 实际轨迹
这样能直观发现预测模型与实际执行的差异,快速定位问题所在。