轨迹跟踪是自动驾驶和机器人控制领域的核心问题之一。最近我在研究如何利用CasADi框架实现模型预测控制(MPC)来解决质点车辆模型的轨迹跟踪问题,并在Matlab环境下完成了完整实现。这个方案相比传统PID控制具有更好的前瞻性和约束处理能力,特别适合车辆在复杂环境下的路径跟踪场景。
CasADi作为一个开源的符号计算框架,为优化控制问题提供了高效的求解工具链。它支持自动微分和多种求解器接口,能够显著简化MPC问题的建模过程。而质点车辆模型虽然简化了车辆动力学,但保留了基本的运动学特性,是研究控制算法的理想起点。
轨迹跟踪的核心目标是让车辆按照预定路径行驶,同时满足各种物理约束。这需要考虑三个关键方面:
MPC相比传统控制方法有几个显著优势:
CasADi特别适合MPC实现的原因在于:
我们采用简化的质点车辆模型(kinematic bicycle model),其状态方程如下:
code复制dx/dt = v * cos(θ + β)
dy/dt = v * sin(θ + β)
dθ/dt = (v / L) * sin(β)
dv/dt = a
其中:
将轨迹跟踪问题表述为如下优化问题:
code复制min J = Σ(||x(k)-x_ref(k)||_Q + ||u(k)||_R) + ||x(N)-x_ref(N)||_P
s.t.
x(k+1) = f(x(k),u(k)) # 系统动力学
x_min ≤ x(k) ≤ x_max # 状态约束
u_min ≤ u(k) ≤ u_max # 控制输入约束
Δu_min ≤ Δu(k) ≤ Δu_max # 控制变化率约束
其中:
首先需要安装CasADi工具箱(Matlab版本):
matlab复制% 添加CasADi到Matlab路径
addpath('casadi-matlab路径')
import casadi.*
然后定义系统参数:
matlab复制% 车辆参数
L = 2.6; % 轴距(m)
Lr = 1.3; % 后轴到质心距离(m)
dt = 0.1; % 离散时间步长(s)
N = 20; % 预测时域
matlab复制% 定义符号变量
x = SX.sym('x'); y = SX.sym('y'); theta = SX.sym('theta');
v = SX.sym('v'); delta = SX.sym('delta'); a = SX.sym('a');
states = [x; y; theta; v]; n_states = length(states);
controls = [delta; a]; n_controls = length(controls);
% 定义系统动力学
beta = atan((Lr/L)*tan(delta));
rhs = [v*cos(theta+beta); v*sin(theta+beta); (v/L)*sin(beta); a];
f = Function('f', {states,controls}, {rhs}); % 连续时间模型
% 离散化模型(采用RK4方法)
k1 = f(states, controls);
k2 = f(states + dt/2*k1, controls);
k3 = f(states + dt/2*k2, controls);
k4 = f(states + dt*k3, controls);
states_next = states + dt/6*(k1 + 2*k2 + 2*k3 + k4);
F = Function('F', {states, controls}, {states_next});
matlab复制% 权重矩阵
Q = diag([10, 10, 5, 1]); % 状态权重
R = diag([1, 0.5]); % 控制输入权重
P = 10*Q; % 终端权重
% 约束条件
v_max = 5; delta_max = pi/4; a_max = 2;
v_min = 0; delta_min = -delta_max; a_min = -2;
matlab复制% 初始化优化变量
U = SX.sym('U', n_controls, N); % 控制序列
X = SX.sym('X', n_states, N+1); % 状态序列
P = SX.sym('P', n_states + N*(n_states)); % 参数(初始状态+参考轨迹)
% 构建目标函数和约束
obj = 0; g = [];
% 初始状态约束
st = X(:,1);
g = [g; st - P(1:n_states)];
% 构建目标函数和约束
for k = 1:N
st = X(:,k); con = U(:,k);
obj = obj + (st-P(n_states+(k-1)*n_states+1:n_states+k*n_states))'*Q*...
(st-P(n_states+(k-1)*n_states+1:n_states+k*n_states)) + con'*R*con;
st_next = X(:,k+1);
st_next_pred = F(st, con);
g = [g; st_next - st_next_pred]; % 系统动力学约束
end
% 终端代价
obj = obj + (X(:,N+1)-P(n_states+(N-1)*n_states+1:n_states+N*n_states))'*P*...
(X(:,N+1)-P(n_states+(N-1)*n_states+1:n_states+N*n_states));
% 控制输入约束
for k = 1:N
g = [g; U(1,k)]; % delta约束
g = [g; U(2,k)]; % a约束
end
% 创建NLP问题
nlp = struct('x', [X(:); U(:)], 'f', obj, 'g', g, 'p', P);
opts = struct('ipopt', struct('print_level', 0), 'print_time', 0);
solver = nlpsol('solver', 'ipopt', nlp, opts);
matlab复制% 生成圆形参考轨迹
t = 0:dt:(N*dt);
x_ref = 10*sin(0.2*t);
y_ref = 10*(1-cos(0.2*t));
theta_ref = 0.2*t;
v_ref = 2*ones(size(t));
ref_traj = [x_ref; y_ref; theta_ref; v_ref];
matlab复制% 初始状态
x0 = [0; 0; 0; 0];
u0 = zeros(n_controls, N);
X0 = repmat(x0, 1, N+1)';
% 仿真参数
sim_time = 20;
mpciter = 0;
xx = []; u_cl = []; t_mpc = [];
% 主循环
while(mpciter*dt < sim_time)
% 准备参数向量
args.p = [x0; ref_traj(:)];
% 初始猜测
args.x0 = [X0(:); u0(:)];
% 求解优化问题
tic
res = solver('x0', args.x0, 'p', args.p, 'lbg', lbg, 'ubg', ubg);
t_mpc = [t_mpc toc];
% 提取最优解
u = reshape(full(res.x(n_states*(N+1)+1:end)), n_controls, N);
xx1 = reshape(full(res.x(1:n_states*(N+1))), n_states, N+1);
% 存储结果
xx = [xx; x0'];
u_cl = [u_cl; u(:,1)'];
% 应用第一个控制量并模拟系统响应
x0 = full(F(x0, u(:,1)));
X0 = [x0 xx1(:,2:end)];
% 更新初始猜测
u0 = [u(:,2:end) u(:,end)];
% 更新迭代计数器
mpciter = mpciter + 1;
end
通过上述实现,我们能够得到车辆跟踪圆形轨迹的效果。正常情况下,车辆应在2-3秒内收敛到参考轨迹,并保持稳定的跟踪性能。关键指标包括:
经过多次实验,总结出以下调参经验:
预测时域N:
权重矩阵:
约束设置:
求解器不收敛:
跟踪性能差:
控制输入抖动:
基于这个基础实现,还可以考虑以下改进:
在实际测试中发现,当车速超过3m/s时,质点模型的跟踪性能会下降,这时就需要考虑更精确的动力学模型。另外,在急转弯场景下,适当增加预测时域N可以显著改善跟踪效果。