ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

无人水面艇NMPC实时控制:从建模到Matlab实现全解析

无人水面艇NMPC实时控制:从建模到Matlab实现全解析 前言做无人水面艇USV控制的同行应该都有体会这玩意儿看着就是个“水上机器人”真上手之后却发现它比小车、无人机都难伺候。螺旋桨推进的非完整约束、浅水效应、风浪流扰动、低速下舵效不足……随便一个因素就能让经典PID在湖面试车时“翻车”。我自己在项目里踩了无数坑之后最终把方案收敛到了NMPC非线性模型预测控制——用一套统一的优化框架同时解决轨迹跟踪和动态避障省掉了大量“规则缝合”工作。这篇博文就把我实现的USV实时NMPC方案完整拆开从建模、优化求解到Matlab代码结构、参数整定、调试技巧一次讲透希望能给正在做无人船、自动驾驶小船或者水下机器人控制的朋友一些直接能用的经验。1. 为什么USV控制要选NMPC而不是PID或线性MPC先说结论USV的动力学天生就是非线性的而应用场景又偏偏要求“轨迹跟踪避障”同时处理这两点决定了NMPC是最合适的选择。但这不是说PID一无是处我做快速原型验证时也经常用PID兜底只是它扛不住大范围工况变化。1.1 PID和LQR在USV上为什么不够用先看PID。USV在水面上的运动可以近似成一个三自由度刚体纵荡surge、横荡sway和艏摇yaw。横荡方向没有直接的执行机构——多数USV只有舷外机或者双推进器这就是所谓的欠驱动特性。PID在欠驱动系统上做路径跟踪时通常把横向误差转化成偏航角指令再靠航向闭环去修正。这在低速、小角度误差时表现还行但一旦船速提起来或者遇到侧风横荡方向的“滑移”会持续积累误差项迟迟收敛不了船就画着蛇形往前走。LQR的问题在于它是线性控制器设计时必须在某个工作点比如某个固定航速、固定航向做线性化。用了几组LQR增益在不同速度段之间切换也算常见做法但USV跟踪的期望轨迹往往曲率变化很大如果航向角在大范围变化线性模型根本描述不了船的实际运动行为控制效果自然就崩了。另外无论PID还是LQR避障都不是控制器本身能表达的事只能在外层套一个路径重规划比如常见的人工势场法、A*、RRT再把新路径投给底层控制器。这种两段式结构在低速、静态障碍下能用但动态障碍一多重规划频率和底层跟踪能力一旦不匹配船就可能撞上去。1.2 线性MPC与NMPC的本质差异线性MPC跟NMPC的根本区别在于“被控模型是不是线性的”。线性MPC把USV模型在某个工作点线性化后预测模型变成一个线性时变LTV系统优化问题变成二次规划QP可以用OSQP、qpOASES这类求解器毫秒级解完。这在汽车、工业过程控制里非常成熟。但USV有个特殊性它经常要在低速和高速之间切换作业模式比如抵近作业时航速只有1节转场时跑到5节以上本身工作范围就跨了大量工作点一个线性模型很难全局有效。NMPC则直接采用非线性运动方程做预测不需要在每个工作点反复线性化代价是优化问题变成非线性规划NLP需要用内点法或序列二次规划来解单步计算量往往在几十到几百毫秒量级。这里要强调的是USV系统本身响应慢。一条排水量几十公斤的小型USV从指令到速度跟上来往往需要13秒采样周期取0.20.5秒完全合理。也就是说只要优化求解耗时控制在100毫秒左右实时性是够用的。相比之下四旋翼那种0.01秒采样周期的系统才真正需要追求极致的求解速度。因此USV非常适合跑NMPC这也是我认为它“能落地”的第一层底气。1.3 NMPC统一框架带来的工程收益NMPC最吸引我的地方不是它“更先进”而是它能在一个框架里同时把轨迹跟踪、避障、执行机构饱和、甚至能量优化全都写进一个代价函数和约束集合里。传统做法是路径规划层负责绕障轨迹跟踪层负责跟随两层之间还要设计接口协议否则跟踪层稍微迟钝一点规划层就认为“偏离路径”重新规划出的路径又给跟踪器制造新的难题。而NMPC天然是“预测未来”的控制器它在每次优化时不仅看当前状态还预测整个预测时域内的运动轨迹然后在这个窗口里同时满足跟踪误差最小和避障约束。避障不再依赖外部的重规划链条而是变成优化问题里的不等式约束这样控制器和避障之间根本不存在“接口失配”的问题。这套统一框架带来的另一个收益是代码结构清爽。你不需要维护一条复杂的“状态机规则表”来做工况切换只需要在约束和权重上做一些自适应调整。我在后面的代码解析部分会展示这个框架的具体实现方式。2. USV运动学与动力学建模NMPC的地基NMPC的预测质量完全取决于预测模型。模型太粗控制效果差模型太细求解慢到没法实时跑。对USV来说我最终选定的是三自由度水平面运动模型忽略垂荡、纵摇和横摇——前提是船体本身在风浪较小的水域作业或者这些方向的运动被船体设计抑制得足够好。2.1 三自由度运动方程与坐标变换先定义两个坐标系惯性坐标系地球固定E系和船体坐标系随船运动B系。USV在E系中的状态是$x$、$y$惯性系下的位置坐标$\psi$艏向角$u$船体坐标系下的纵荡速度向前$v$船体坐标系下的横荡速度向右$r$艏摇角速度那么运动学方程为 $$ \dot{x} u\cos\psi - v\sin\psi $$ $$ \dot{y} u\sin\psi v\cos\psi $$ $$ \dot{\psi} r $$这组方程很好理解E系下的速度就是把船体坐标系下的速度旋转一个艏向角。需要注意的是$v$在USV里不是0。很多初学者会把USV简化成二自由度独轮车模型认为船只能向前走横荡方向速度为零。实际航行中船在转向时会出现侧滑尤其在风浪流环境中忽略$v$会让预测轨迹跟实际轨迹差很远。动力学方程考虑质量、附加质量、线性阻尼、非线性阻尼以及风浪流的扰动项。以纵荡为例可以写成 $$ m_{11}\dot{u} - m_{22}vr d_{11}u d_{n11}|u|u \tau_u \tau_{wind,u} $$ 其中$m_{11}m - X_{\dot{u}}$$m_{22}m - Y_{\dot{v}}$这里$X_{\dot{u}}$、$Y_{\dot{v}}$是附加质量系数来源于船体加速时周围水体的惯性。$d_{11}$是线性阻尼系数$d_{n11}$是非线性阻尼系数对应阻力随速度非线性增长的特性。$\tau_u$是推进器产生的纵荡力$\tau_{wind,u}$是风在纵荡方向上的干扰力。横荡和艏摇方向同理 $$ m_{22}\dot{v} m_{11}ur d_{22}v d_{n22}|v|v \tau_{wind,v} $$ $$ m_{66}\dot{r} - (m_{11}-m_{22})uv d_{66}r d_{n66}|r|r \tau_r \tau_{wind,r} $$这里我要特意说明一下$\tau_u$和$\tau_r$并不是独立可任意赋值的广义力。对于双推进器USV来说实际控制输入是左右两侧推进器的推力$T_L$、$T_R$它们和广义力之间满足 $$ \tau_u T_L T_R $$ $$ \tau_r B_t(T_R - T_L) $$ 其中$B_t$是推进器到船体中心的横向力臂。也就是说NMPC的输出可以是$T_L$、$T_R$也可以先输出$\tau_u$、$\tau_r$再做个控制分配。两种做法我都试过后者在加执行机构饱和约束时更方便因为推进器推力有上下限而广义力没有物理直观上限。但也有人喜欢直接用$T_L$、$T_R$做优化变量少一层分配就少一层误差。我的建议是如果船只有两个以上的执行机构比如加了艏侧推器用控制分配层更合理如果只有双推进器直接优化$T_L$、$T_R$来得更简单、更可靠。2.2 模型参数辨识与不确定性处理模型里最让人头疼的就是那一堆系数。我的做法是分三步走理论估算根据船体几何尺寸用经验公式估算附加质量系数和阻尼系数。经典的估算方法之一是把船体近似成椭球体用附加质量公式算$X_{\dot{u}}$、$Y_{\dot{v}}$。自由衰减试验把船放在静水中给一个初始速度或角速度记录速度随时间衰减曲线拟合出线性阻尼系数。这个实验简单有效我的经验是多测几组不同初速度下的衰减曲线才能拟合好非线性阻尼项只测一组数据很容易得到过拟合的系数。系统辨识在线修正在航行中记录实际输入和速度响应用最小二乘或扩展卡尔曼滤波EKF在线更新部分参数。这个更高级一点但NMPC模型本身对参数误差有一定鲁棒性所以不一定非要上在线辨识。需要强调的是模型参数不准不是致命的。NMPC本身有反馈机制每次采样都会用当前状态作为预测起点即使模型有误差只要趋势对控制器就能通过滚动优化不断修正。真正要命的其实是模型结构错误比如忽略了$v$、忽略了耦合项$m_{22}ur$这种结构性误差在高速转向时会让预测轨迹严重失真你怎么调权重都救不回来。2.3 离散化与采样周期选择NMPC是离散时间控制的预测模型必须离散化。我比较推荐的方法是**四阶Runge-KuttaRK4**做数值离散化。在Matlab里如果用了CasADi可以直接用它的integrator函数来做离散内部也是类似的操作。对USV这种系统RK4的精度已经足够而且耗时不大。真正耗时的是对离散后模型求导的步骤——CasADi会自动用算法微分去求雅可比矩阵这是它比手写雅可比省时省力的核心原因。采样周期$T_s$的选择直接决定控制性能。我在这类小水面船上常用的取值是0.20.5秒折中原则是太快了优化求解时间跟不上实时性风险太慢了控制器对扰动的响应太迟钝。一个常用的经验法则是采样时间应当大约是系统主导时间常数的1/10到1/20。USV纵荡方向的时间常数通常约15秒取0.2秒刚好在合理区间。预测时域$N_p$则通常取2050步对应410秒的预测窗口。这个窗口长度要覆盖到避障时“看到障碍到采取机动”的反应距离。我的经验值是低速水面船采样周期0.20.5s预测时域2540步预测总时长510s可以兼顾控制效果和优化求解时间。3. 轨迹跟踪与避障的一体化约束设计模型建好了接下来就是把“跟踪”“避障”翻译成数学语言——代价函数和约束条件。3.1 代价函数不仅跟踪还要省力、平滑NMPC每一步优化求解的目标是让如下代价函数最小$$ J \sum_{k0}^{N_p-1} \left( |\mathbf{e}_{k1}|_Q^2 |\mathbf{u}k - \mathbf{u}{ref}|_R^2 |\Delta\mathbf{u}k|{S}^2 \right) $$其中$\mathbf{e}k [x_k - x{ref,k} y_k - y_{ref,k} \psi_k - \psi_{ref,k}]^T$是跟踪误差向量$Q$、$R$、$S$分别是误差权重矩阵、控制幅度权重矩阵和控制增量权重矩阵。记号$|\mathbf{e}|_Q^2$表示$\mathbf{e}^T Q \mathbf{e}$。三部分的含义分别是跟踪误差项让船贴近期望轨迹控制幅度项避免输出过大的推力指令省能量也减小执行机构磨损控制增量项让推力指令的变化不要太剧烈防止船“抖舵”其中控制增量项对于实际系统特别关键。我一开始没加这权重时船的推力指令高频抖动螺旋桨噪声很大而且实际推力响应跟不上指令变化。加上$S$之后指令平滑多了跟踪精度反而提升了——因为频繁抖动的指令在空中飞行器上是“振动”在船上是“无效功”。权重的选取我跟大家推荐一个顺序先保证跟踪权重$Q$的主导地位观察纯跟踪效果再逐步加入控制增量权重$S$直到指令平滑最后用控制幅度权重$R$做能耗权衡。最简单有效的调试方式是先把$Q$设为单位阵$R$和$S$设得很小跑一遍仿真再根据响应特性逐步增大$R$和$S$。3.2 避障约束的两种表达方式与取舍避障的核心是把障碍物“塞进”约束里。我先后试过两种方案。方案一二次型排斥约束如果障碍物是一个圆圆心$\mathbf{p}_o$半径$r_o$加上USV的安全半径$r_s$那么避障约束可以写成$$ (x_k - p_{o,x})^2 (y_k - p_{o,y})^2 \ge (r_o r_s)^2 $$这是一个非凸约束因为可行域是圆的外部区域。非凸给NLP求解器带来一定压力但现代求解器配合好的初始猜测一般也能解出来。这种方式的优点是几何表达简洁不足是容易陷入局部最优——比如船在狭窄通道中可能“被逼到墙角”求解器给出一组满足约束但轨迹很差的解。方案二线性化超平面约束推荐在每次优化时把避障约束在当前预测状态点附近做一阶泰勒展开变成一组线性不等式。这样虽然牺牲了一点精度但保持了凸性求解稳定性和速度都要好不少。工程实现上更常用的是另一种思路把障碍物的影响通过代价函数的软约束来实现。也就是在代价函数里加一个避障惩罚项而不是在约束里硬性排除。例如用高斯形式的势函数 $$ J_{obs} \sum_{k}\sum_{i} K_{obs} \cdot \exp\left(-\frac{|\mathbf{p}k - \mathbf{p}{obs,i}|^2}{2\sigma^2}\right) $$惩罚项越大船离障碍越远。这种方式避免了非凸约束的求解困难代价是可能出现很小的距离违背因为只是惩罚不是硬约束。我的实际建议是在仿真阶段先用硬约束方案一看避障逻辑对不对在实船测试阶段把硬约束改软约束并保留一个安全距离阈值。因为实船上的障碍物位置都是感知模块给的坐标本身就有噪声硬约束在这种噪声下容易过激反而容易导致急转弯。3.3 动态避障预测碰撞锥与速度障碍法USV碰到静态障碍物相对好处理但动态障碍其他船只、漂浮物必须考虑相对运动。工程中最实用的方法是借鉴机器人领域的**速度障碍法Velocity ObstacleVO**的思想结合NMPC的预测能力做改进。核心思路是在当前时刻已知障碍物的位置$\mathbf{p}{obs}$和速度$\mathbf{v}{obs}$在未来$T_{coll}$时间内计算USV与障碍物发生碰撞的相对速度条件形成一个“碰撞锥”。如果预测轨迹进入这个锥则启动避障约束。但在NMPC框架里与其预先算一个固定的碰撞锥不如在预测时域内逐步检查每个预测点与障碍的距离。也就是说在每个预测时刻$k$把障碍物的预测位置算出来假设它保持匀速运动然后检查$|\mathbf{p}k - \mathbf{p}{obs,k}|$是否小于安全距离。整个过程在预测时域内都是动态一致的相当于隐式实现了速度障碍的概念但又不需要显式求解碰撞锥的几何边界。这一点是NMPC做动态避障的最大优势预测本身就是一种考虑未来信息的避障能力。为了给控制器足够的反应时间我通常在代价函数和约束里额外引入一个“预警距离”$d_{warn}$。当USV进入预警范围后不管是否真的有碰撞风险先把这部分权重调高让控制器朝“离开障碍趋势”的偏航角走。这个策略有点像人类驾驶时的“防御性驾驶”——不是等到马上撞了再打方向盘而是提前进行方向调整。4. 实时NLP求解与Matlab工程实现NMPC整体框架理清楚了接下来就是最关键的工程细节怎么在Matlab里把非线性优化问题实时解出来。4.1 求解器选择CasADi IPOPT还是ACADOMatlab里做NMPC主流选择是CasADi。CasADi是一个符号计算和最优控制工具包它的核心能力是高效的算法微分AD——你只需要把模型方程写成符号表达式它就能自动算出雅可比矩阵和海森矩阵这对NLP求解器的速度至关重要。搭配的求解器我推荐IPOPT内点法求解NLP。IPOPT是开源里最成熟、最稳的NLP求解器能处理等式约束、不等式约束和目标函数的非线性。缺点是它不是一个“实时求解器”它的耗时调节只能靠修改收敛容差等参数但在USV应用里单步求解通常在50200毫秒内完成完全够用。如果你追求更极致的实时性可以考虑ACADO Toolkit或者MATMPC它们针对嵌入式NMPC做了大量优化采用基于序列二次规划SQP的实时迭代RTI方案。这种方案把NLP求解过程中的一次迭代分布到每个采样周期内大幅缩短单步计算时间但代价是每次优化并不“完全收敛”所以它对可行性和收敛性要求更高的算法打磨。我的经验是先拿CasADi搞通逻辑再谈嵌入式移植。先把事情做对再快。4.2 热启动解决NMPC实时性最容易被忽略的一环NMPC实时性提升最重要的技巧其实是热启动warm start。非线性优化求解器在迭代时需要初始猜测。如果每次从零开始迭代次数会很多耗时也长。但如果用上一次最优解作为本次迭代的初值因为系统状态连续变化两次最优解通常很接近迭代次数能大幅降低。这个技巧在工程上极其有效实测往往能让单步耗时降低一半以上。具体做法是把上一时刻解出的控制序列按“去掉第一个元素末尾补上最后一个元素”的方式进行移位% NMPC热启动 function u0 warm_start(u_prev, Ts) % 移除已执行的控制量末尾复制保持原值 u0 [u_prev(:, 2:end), u_prev(:, end)]; end同时状态轨迹序列也需类似处理把上一个预测周期内各节点的状态值作为本次迭代的初始猜测状态。这里有个细节如果预测时域比较长建议保留每个节点的状态值而不是只传一个初值这样求解器能在整个轨迹维度上有一个好的起点收敛曲线会平缓许多。4.3 代码结构一个可直接扩展的Matlab/Simulink框架我这里给出一个精简但可以直接运行的Matlab代码结构框架建议按以下M文件组织usv_nmpc/ ├── main.m % 主程序 ├── usv_model.m % 被控模型 ├── nmpc_setup.m % 定义NMPC问题 ├── nmpc_solve.m % 求解步骤封装 ├── reference_path.m % 参考轨迹 ├── obstacles.m % 障碍物信息 ├── plot_results.m % 绘图 └── utils/ ├── rk4_discrete.m % RK4离散化 ├── wrap_angle.m % 角度归一化 └── euler_to_mat.m % 旋转矩阵工具主循环的核心逻辑是% 主控制循环 xk [x0; y0; psi0; u0; v0; r0]; % 当前状态 u_k zeros(2, Np); % 控制输入初始化 for t 0:Ts:Tfinal % 1. 生成参考轨迹点 ref_traj reference_path(t, t Np*Ts); % 2. 获取障碍物信息感知层 obs get_obstacles(t); % 3. 求解NMPC [u_opt, x_pred] nmpc_solve(xk, ref_traj, obs, u_k); % 4. 执行第一个控制量 u_ctrl u_opt(:, 1); % 5. 模拟被控对象反馈到状态 xk rk4_discrete(xk, u_ctrl, Ts); % 6. 热启动 u_k warm_start(u_opt, Ts); end在nmpc_setup.m里用CasADi构建优化变量的核心代码大致长这样import casadi.* % 决策变量 X MX.sym(X, 6, Np1); % 状态序列 U MX.sym(U, 2, Np); % 控制序列 % 初始状态约束 g {}; g [g, {X(:,1) - xk}]; % 动态约束RK4离散 for k 1:Np x_next rk4_discrete(X(:,k), U(:,k), Ts); g [g, {X(:,k1) - x_next}]; end % 避障约束 for k 1:Np1 for obs_i 1:size(obs_pos, 1) dist_sq (X(1,k)-obs_pos(obs_i,1))^2 (X(2,k)-obs_pos(obs_i,2))^2; g [g, {dist_sq - (obs_r(obs_i) safe_r)^2}]; end end % 控制量限幅 lbx [repmat([-T_max; -T_max], 1, Np), -inf(6,1)]; ubx [repmat([ T_max; T_max], 1, Np), inf(6,1)]; % 目标函数 J 0; for k 1:Np e X(1:3,k1) - ref_traj(k); du U(:,k) - U(:,k-1); J J e * Q * e U(:,k) * R * U(:,k) du * S * du; end % 创建NLP求解器 prob struct(f, J, x, [U; X], g, vertcat(g{:})); solver nlpsol(solver, ipopt, prob);这段代码是骨架真实项目还需要加很多细节比如角度差值的归一化处理艏向角误差要wrap到$[-\pi,\pi]$区间否则会走大圈调回来、控制量增量的边界条件处理等。但在结构上它已经覆盖了核心要素。4.4 控制分配从广义力到实际推力如果你选择优化$\tau_u$、$\tau_r$而不是$T_L$、$T_R$那么在拿到最优广义力后需要做一个控制分配function TL_TR control_allocation(tau_u, tau_r, B_t) % 由广义力反解左右推进器推力 TL 0.5 * tau_u - tau_r / (2 * B_t); TR 0.5 * tau_u tau_r / (2 * B_t); % 推力限幅 TL max(min(TL, T_max), -T_max); TR max(min(TR, T_max), -T_max); TL_TR [TL; TR]; end这里有两点需要注意一是广义力不是任意可达的当$T_R$饱和时实际的$\tau_u$、$\tau_r$会受限这种约束在NMPC里最好直接建模到U的边界里也就是给$T_L$、$T_R$加限幅约束二是如果船的推进器只能正转不能反转很多螺旋桨船就是这样那么还要额外考虑$T_L \ge 0$、$T_R \ge 0$这个约束。这个约束对USV的控制能力影响很大很多船根本无法原地转向只能靠差速转弯在NMPC里不把这个问题表达清楚求解器会给出无法执行的指令。5. 常见问题与参数调试实录前面把框架搭完了这一节我想重点聊聊在实际调试中最容易遇到的那些坑。这些坑没有一个写在教科书里全是我自己一个参数一个参数试出来、烧过电机才有的心得。5.1 求解不收敛或迭代次数爆炸这是用NMPC最先遇到、也最常见的问题。现象是IPOPT报错“Restoration failed”或“Maximum iterations exceeded”然后控制器直接输出上次指令或者归零。我的排查顺序是这样的看热启动做没做。没有热启动的NMPC初始猜测离最优解太远内点法很容易在非凸问题里迷失方向。这大约能解决70%的收敛问题。看约束是不是过紧。比如避障距离约束$r_o r_s$取得偏大当前状态已经在约束范围外会导致初始点不可行。这种情况我建议把约束改成两步先用一个小一点的“硬极限”约束保证安全底线再在代价函数里加一个梯度更大的“期望距离”惩罚项。看权重尺度有没有严重失衡。跟踪误差权重$Q$动辄上千控制权重$R$却不到1目标函数的数值量级跨越过大容易引起海森矩阵条件数变差收敛慢。一个小技巧是在调试阶段把IPOPT的print_level设为5这样能清楚看到求解器每步迭代的可行性、最优性残差快速定位是约束不可行还是目标函数不平滑。5.2 跟踪误差的振荡与超调仿真跑通了但发现船在直线上走得还行一进弯道就振甚至越追越偏。这里有个非常隐蔽的坑参考轨迹以时间为参数而不是以路径长度为参数。如果参考速度曲线给得不合理比如弯道上参考速度还保持高速控制器为了追参考点就会猛打舵产生振荡。解决办法是把参考轨迹从纯时间参数改成路径参数$s(t)$跟踪的目标不是“某个时刻的坐标”而是“沿参考路径的弧长位置”这样控制器的自由度更大弯道表现会好很多。另一个经验是关于权重矩阵$S$控制增量权重。我遇到的振荡案例中有一半是$S$设太小引起的增大$S$之后轨迹立刻平滑了。但$S$也不能太大否则船“懒得动”跟踪滞后严重整个系统显得迟钝尤其在动态避障时反应会变慢。5.3 动态障碍物避障失败决策在“最后一刻”动态避障最常见的失败模式是控制器在距离障碍物较远时“无动于衷”等障碍物逼近了才开始急转弯然后因为USV本身的转弯半径大、舵效滞后导致避障失败。我从这几方面同时下手才解决增大预测时域从20步加到30步以上让控制器更早看到未来的碰撞风险。加入速度自适应约束当离障碍物距离小于某个阈值时限制最大纵向速度和艏摇角速度降低急转弯的难度。在代价函数里加入“避障风险势场”让船即使还没有进入硬约束区域也能感受到障碍物的“斥力”提前改变航向。这个势场权重不能太大否则船会绕很远的路反而导致跟踪误差大范围增大。5.4 实船与仿真差异大模型失配要背锅仿真跑得好好的实船一放上去就废了这是几乎所有控制项目都逃不过的一关。USV上最典型的原因是附加质量、阻尼参数不准。我在实船调试时吃过亏船模在仿真中转弯半径是8米实船实测却有13米差距大到离谱。调下来发现是忽略了船体周围水体的附加质量效应——在仿真里我按静水估算参数实船在浅水区航行时水体受底部边界影响附加质量明显增大阻尼也变化了。解决方法是做闭环辨识。在实船上设计简单的开环试验给定一组正弦推力指令记录船的实际速度响应和航向响应然后在Matlab里用lsqnonlin去拟合模型参数。这样得到的参数比任何经验公式都可靠。虽然不能做到完全精准但拟合完成后NMPC的预测轨迹跟实测轨迹之间的差距就能控制在可接受范围内。6. 从仿真到实船的落地建议这里整理一份我反复用到的落地检查清单按优先级从高到低排列执行机构饱和建模如果预测模型里控制量范围比实船执行机构的实际范围宽控制器会输出无法执行的指令这个优先级最高必须最先确认。感知数据的噪声滤波避障模块的障碍物位置一定要经过滤波和预测否则直接用带噪位置给NMPC的约束会导致约束边界在每次求解时来回跳指令抖动。故障保护NMPC求解失败时的兜底策略要明确定义比如“使用上一次控制量”“切换到PID保持当前位置”“紧急停车”而且最好根据船的安全需求分优先级。参数热插拔控制权重要允许在运行中按工况切换。比如抵近作业时降低跟踪权重、提高避障权重转场时反过来。日志记录把每次求解的状态、控制量、约束余量、求解耗时记录下来。没有日志的实船调试就是盲人摸象所有难复现的问题都靠日志解决的。实船调试的过程确实比仿真痛苦得多但这也是NMPC这类方法最有魅力的地方。哪怕模型参数和实际有偏差只要整个反馈回路是通的控制器就会自动寻找可行的最优折中。我在多次湖面试车后最大的感受是NMPC不是在“做对每一步”而是在“持续修正自己”。这也是为什么尽管它调试门槛高我还是愿意把它作为USV控制的首选方案。刚开始做这个项目的时候我觉得NMPC的数学门槛是最难的后来发现建模和调试才是最磨人的。前前后后调了两个月才把跟踪精度和避障可靠性调到能放心在湖面跑的程度。这篇博客里写的这些经验和代码结构希望对正在做USV或类似无人系统控制的朋友有实际帮助。如果你也在跑NMPC时遇到什么奇奇怪怪的坑欢迎一起交流这类系统的工程经验太碎片了大家互相补一补能少走很多弯路。
返回列表