☰
欠驱动船舶轨迹跟踪控制:神经网络观测器与自适应滑模的Matlab实现
2026/10/17 5:50:19 网站建设 项目流程

欠驱动船舶的轨迹跟踪控制,是我最近大半年反复折腾的一个课题。先放结论:用神经网络观测器加自适应滑模这套组合,确实能在模型不确定和海浪干扰下把欠驱动船的轨迹跟踪问题压住,但前提是你得真搞明白每个模块在做什么,而不是把网上找的Matlab代码拼一起就跑。这篇文章准备把从问题建模、控制方案设计、再到Matlab代码实现的完整链条摊开讲,重点放在实现细节和调参踩坑上,适合正在做船舶运动控制仿真、或者对欠驱动系统控制方案感兴趣的同学参考。

1. 欠驱动船舶轨迹跟踪到底难在哪

1.1 三自由度模型里的“欠驱动”真相

做控制仿真之前,得先把对象模型吃透。工程上讨论水面船舶运动时,最常用的是三自由度模型,也就是纵荡、横荡和艏摇。船舶在海上的六个自由度运动里,纵摇、横摇、垂荡通常不参与水平面的轨迹控制,所以直接忽略,只保留水平面内最核心的三个自由度。

这里的运动学关系很直观,用大地坐标系下的位置量eta = [x; y; psi]和船体坐标系下的速度量nu = [u; v; r]来表示,就是:

x_dot = u * cos(psi) - v * sin(psi) y_dot = u * sin(psi) + v * cos(psi) psi_dot = r

动力学部分,如果忽略了高阶非线性阻尼项,典型简化模型可以写成:

m11 * u_dot = m22 * v * r - d11 * u + tau_u + tau_wu m22 * v_dot = -m11 * u * r - d22 * v + tau_wv m33 * r_dot = (m11 - m22) * u * v - d33 * r + tau_r + tau_wr

注意看第二行:m22 * v_dot这一项里面没有控制输入tau_v。也就是说,这艘船只有一个纵向推力tau_u和一个转艏力矩tau_r,横荡方向完全没有直接驱动力。这就是“欠驱动”的核心含义:三个自由度,两个输入通道,输出维度和输入维度天然不匹配。

我经常跟人打一个比方,这跟开车很像。汽车没有侧向推进器,要横着挪动只能靠方向盘转向、再挂挡给油门,利用前轮转角和速差把侧向速度“逼”出来。欠驱动船也是这样,v方向的运动只能靠纵荡和艏摇的耦合关系被动激励出来,所以在控制设计里,横荡速度是一个没法直接命令的量,只能想办法让它保持有界、尽量减小对跟踪精度的负面影响。

更麻烦的是,这套模型里的质量系数、阻尼系数都随装载工况、航速、吃水深度实时变化。真实的流体水动力里面有粘性效应、附加质量、浪流干扰,想拿到精确的m11、m22、d33几乎不可能。所以控制器必须对这种参数不确定性有足够的容忍度。

1.2 轨迹跟踪、路径跟随、姿态镇定别混为一谈

开头说过题目是“轨迹跟踪控制”,这个限定其实很重要。轨迹跟踪要求的是跟踪一条带有时间信息的参考轨迹,也就是每个时刻船都要到达指定的位置、保持指定的艏向,误差要随时间收敛到零附近。路径跟随就宽松得多,它只要保证船贴着一条空间几何路径走,速度快一点慢一点都无所谓。

别小看这个差别。轨迹跟踪因为有了时间约束,控制难度明显更高。对欠驱动系统来说,常规的连续光滑静态状态反馈很难满足渐近镇定所需要的必要条件,所以很多经典设计方法在这个问题上会遇到结构性障碍。实际用的往往是非光滑、时变、或者带有自适应/学习机制的控制策略。本文这套方案里,滑模的不连续项和神经网络的在线学习,本质上就是在绕开这个障碍。

我自己在仿真里试过把路径跟随控制器直接拿来做轨迹跟踪,结果在圆轨迹上始终有稳定的跟踪相位差,因为参考轨迹的速度方向变化太快,控制器只盯着横向偏差,没有把时间的动态信息设计进去。这个教训提醒我:先确认你手头的问题是轨迹跟踪还是路径跟随,再决定控制器结构。

1.3 模型不确定性和速度测量问题必须一起考虑

控制设计不能只盯着模型方程,还得想想真实系统里能拿到哪些信号。很多无人船平台上,位置和艏向可以用卫星定位加罗经测出来,更新率大概是5到20赫兹,精度足够。但纵荡速度、横荡速度、艏摇角速度就不一定有了,即便装了多普勒测速仪,浅水区、近岸区也容易失锁,信号跳变非常难处理。

如果控制器设计里面直接用了速度状态,但实际系统根本测不到,那整个方案就废了。所以神经网络观测器的另一个重要作用,就是用位置和艏向的测量去重构速度信息。说得直白一点:位置可测,速度不可测,那就造一个观测器把速度“估”出来,同时把模型里的未知项也一并逼近掉。

这样三个问题就串起来了:欠驱动带来的控制难、模型不确定带来的鲁棒性难、速度不可测带来的状态获取难。后面讲的每个设计模块,都是对着这三个问题来的。

2. 控制方案整体设计与选型逻辑

2.1 神经网络观测器:不是“万能逼近”那么玄

神经网络观测器在这个方案里的核心任务,是把船舶模型里的集中不确定项给估计出来。集中不确定项包括未建模动态、参数摄动和外部风浪流干扰,整体看可以写成一个大写的Delta函数。这个函数理论上跟状态、控制输入都有关系,但具体表达式谁也不知道。神经网络的思路就是不去猜它的表达式,而是“在线学”一个逼近模型。

为什么选RBF网络而不是BP?区别很实际。RBF是局部逼近网络,隐含层只对靠近自己中心那一小块输入产生明显响应,结构简单,在线更新权值的计算量小。控制系统的采样周期通常只有几十毫秒,你不可能让更新算法做大规模迭代训练,RBF这种“换个输入就只需要算几个高斯函数加一次权值更新”的结构非常合适。

实现上一般是让网络输入取可测或可估的状态量,比如[u; v; r; psi; tau_u; tau_r]的组合,网络输出就作为Delta的估计值。隐含层基函数的典型形式是高斯型:

phi_j = exp(-||x - c_j||^2 / b_j^2)

其中c_j是第j个节点的中心,b_j是宽度。如果网络的中心覆盖范围不够,或者宽度放得太窄,就会出现“输入到了某个区域但节点全都没激活”的空白区,网络的逼近能力直接报废。

观测器结构上,我习惯把位置/艏向测量反馈项和神经网络估计项同时放进去。位置测量值可以和观测器预测值做差,乘上一个增益矩阵再反馈回速度估计通道,这个修正项会推动估计状态收敛到真实状态附近。神经网络那块则专门去抵消模型不确定性。两者的增益和权值更新律不是随便拍的,要通过整个闭环系统的李雅普诺夫分析一起推导,这样估计误差、跟踪误差和权值误差才能同时收敛到有界范围。

2.2 自适应滑模控制:鲁棒和学习的搭配

滑模控制在欠驱动系统里是出了名的“大力出奇迹”。它通过设计一个滑模面,把跟踪误差的约束变成一个一阶或二阶动态关系,再通过切换控制把状态“压”到滑模面上,之后误差就沿着滑模面自然收敛,对外部干扰表现出很强的鲁棒性。

但传统滑模有个尴尬点:切换增益的大小要大于干扰上界才保证收敛,可是干扰上界往往是未知的。你把它估大了,抖振会很厉害;估小了,控制精度又拉胯。自适应滑模解决的就是这个事:干扰上界和神经网络权值都通过自适应律在线更新,不需要事前精确已知。

控制律的大致结构可以理解成三块:

第一块是等效控制项,负责把标称模型上的动态“对消”掉,让误差沿期望的滑模动态走。第二块是神经网络补偿项,用来抵消不确定性估计的失配。第三块是切换项,一般带一个自适应调节的增益,负责对付剩余逼近误差。三者合起来,控制量就比较干净,既不像纯自适应控制那样依赖精确建模,也不像纯滑模那样抖振得厉害。

滑模面的设计我建议用“级联”思路:欠驱动系统不能直接在三个自由度的误差上都强行布置滑模面,那样会出现控制量不足的问题。常规做法是先设计一个期望艏向和期望纵向速度的虚拟量,把位置误差转成“速度该往哪走”的指引信号,然后针对实际速度跟踪虚拟速度的误差再设计滑模面。说俗一点:先规划方向,再用力驱动。

2.3 三部分如何耦合:观测器、控制器、自适应律是一套整体

很多初学者容易犯一个错误,把观测器和控制器当成两个独立环节,觉得“反正观测器给我状态估计,控制器用估计值就行”。但真实设计里不是这样的。神经网络的权值更新律里有跟踪误差,滑模的自适应增益更新律里也可能有观测器误差,而观测器的增益又影响控制器的误差动态。整个系统是一个互相关联的闭环误差系统,不能按“先观测、再控制”的分步思路去严格设计。

这也是为什么多数相关文献里都会花大量篇幅讨论闭环稳定性和信号的有界性,而不是只给一个控制律表达式。说句实话,我最初尝试的时候就是把观测器增益调得很猛,想让它更快收敛,结果发现控制通道上出现了奇怪的振荡,怎么调滑模增益都没用。后来把观测器和控制器的耦合项重新做了李雅普诺夫分析,才发现增益需要按稳定性条件搭配着选。

所以这块给一个很实用的建议:仿真阶段不要一上来就追求复杂公式的完美推导,先把控制律、观测器、自适应律的“信号流图画清楚”。弄清楚哪个模块输入什么、输出什么、哪个误差反馈到哪里,再去做严格分析和调参,效率会高非常多。

3. Matlab实现与关键步骤

3.1 程序框架与模块划分

Matlab仿真建议拆成多个文件来组织,功能单一、容易排查。我常用的目录结构大概是:

% main_tracking.m 主仿真脚本:初始化参数、循环积分、画图 % ship_dynamics.m 船舶动力学与运动学方程 % control_smc.m 自适应滑模控制器 % observer_rbf.m RBF神经网络观测器 % ref_trajectory.m 参考轨迹生成 % plot_results.m 结果可视化

主仿真脚本里最核心的是推进循环。这里有个经验:不要直接用ode45去求解带滑模不连续项的闭环系统。滑模信号里面有符号函数,切换瞬间右边的导数不连续,ode45的变步长算法会为了满足误差容限疯狂缩步长,仿真速度会慢好几倍,还有可能产生大量虚假的数值振荡。

我实际建议用固定步长离散仿真,比如自己写一个四阶Runge-Kutta循环,步长取Ts = 0.05s或0.01s。这样更接近船上计算机控制的真实工作方式:每一步采样、计算控制量、保持零阶保持器输出、再积分一步。而且固定步长下,每一步的采样间隔固定,神经网络权值更新和自适应律更新也更好处理。

3.2 船舶模型与参考轨迹配置

模型参数我建议先用一组相对“温和”的无人船模型参数,方便验证控制器的基本逻辑。一组典型的数值如下,单位已经换算到标准国际单位制里:

m11 = 25.8; m22 = 33.8; m33 = 2.76; d11 = 0.72; d22 = 0.86; d33 = 1.38;

这是一艘长三米左右的无人船模型典型量级。真船的参数当然更加复杂,但初稿阶段用线性阻尼已经足够。等控制逻辑跑通了,再加非线性阻尼项和外部干扰项。

参考轨迹也别一上来就整复杂的样条。轨迹跟踪控制器的调试验证,我首推圆轨迹:

xd = 10 * sin(0.02 * t); yd = 10 * (1 - cos(0.02 * t)); psi_d = 0.02 * t;

这个轨迹的好处是曲率恒定、速度方向和艏向都在平滑变化,能同时考核纵向通道和转艏通道的跟踪能力。圆半径和角速度从大到小递推测试,太大则轨迹太缓,看不出控制效果;太小则要求船快速转弯,会暴露动力学匹配问题。

跑通圆轨迹之后,再换成“直线-圆弧-直线”的组合轨迹或者八字轨迹,重点观察切换段有没有超调和过冲。

3.3 控制器、观测器与自适应律实现细节

这部分放几个核心代码片段,实际工程中不是直接抄就能跑,但可以作为骨架参考。

先看RBF观测器的一段示意代码。假设观测器状态估计是一个六维向量xhat = [uhat; vhat; rhat; xhat; yhat; psihat],测量输出y = [x_meas; y_meas; psi_meas]:

function [xhat_dot, Wdot] = observer_rbf(xhat, y_m, u_in, W, centers, width, gains) xhat_dot = zeros(6,1); % 估计运动学部分 psi_h = xhat(6); xhat_dot(4) = xhat(1)*cos(psi_h) - xhat(2)*sin(psi_h); xhat_dot(5) = xhat(1)*sin(psi_h) + xhat(2)*cos(psi_h); xhat_dot(6) = xhat(3); % 计算RBF基函数输出 net_input = [xhat(1:3); xhat(6); u_in]; phi = exp(-sum((net_input - centers).^2, 2) / (width^2)); % 用神经网络逼近未知集中项 unknown_hat = W * phi; % 动力学部分估计 xhat_dot(1) = (m22 * xhat(2) * xhat(3) - d11 * xhat(1) + u_in(1) + unknown_hat(1)) / m11; xhat_dot(2) = (-m11 * xhat(1) * xhat(3) - d22 * xhat(2) + unknown_hat(2)) / m22; xhat_dot(3) = ((m11-m22)*xhat(1)*xhat(2) - d33*xhat(3) + u_in(2) + unknown_hat(3)) / m33; % 测量反馈修正 y_err = y_m - xhat(4:6); xhat_dot(1:3) = xhat_dot(1:3) + gains(1:3) .* y_err; end

注意这个代码里的参数和神经网络权值都是写成外部传入的,实际使用中要处理好全局变量或者参数结构体。centers是神经网络的中心矩阵,维度是“节点数×输入维数”,width是基函数宽度。

滑模控制器示意代码如下:

function [tau, s] = control_smc(xhat, ref_state, ref_dot, ref_ddot, K, lambda) psi_h = xhat(6); % 位置误差转船体坐标系 ex = xhat(4) - ref_state(1); ey = xhat(5) - ref_state(2); e_bx = ex * cos(psi_h) + ey * sin(psi_h); e_by = -ex * sin(psi_h) + ey * cos(psi_h); % 由位置误差构造期望速度虚拟控制量 alpha_u = ref_dot(1) - lambda(1) * e_bx; alpha_r = ref_dot(3) - lambda(2) * e_by; % 滑模面取速度误差的形式 su = xhat(1) - alpha_u; sr = xhat(3) - alpha_r; % 控制律:等效项 + 趋近项,趋近项用饱和函数抑制抖振 phi_b = 0.05; tau_u = m11 * (-lambda(1)*(ref_dot(1) - xhat(1)*cos(psi_h)) + ref_ddot(1)) ... - m22 * xhat(2) * xhat(3) + d11 * xhat(1) ... - K(1) * su - K(2) * sat(su / phi_b); tau_r = m33 * (-lambda(2)*(ref_dot(3) - xhat(3)) + ref_ddot(3)) ... - (m11 - m22) * xhat(1) * xhat(2) + d33 * xhat(3) ... - K(3) * sr - K(4) * sat(sr / phi_b); s = [su; sr]; end

这段示意代码省略了一部分耦合项,重点是想展示几个设计习惯:滑模面不是直接用绝对误差,而是和虚拟控制量结合;切换项用sat函数而不是sign函数;控制量把已知动力学部分前馈对消,神经网络补偿量可以在观测器里给到未知扰动估计,再叠加进来。这样做出来控制量的抖振会小很多。

自适应律更新也很简单,在每个采样周期按如下形式更新权值和干扰上界:

W = W + Gamma_W * (phi * s') * Ts; d_hat = d_hat + Gamma_d * abs(s) * Ts;

这里的Gamma_W是神经网络权值学习速率,Gamma_d是干扰上界自适应速率。它们必须保持在一个合适范围,过大会导致参数振荡甚至发散。

3.4 参数整定思路:从简单到复杂

调参的顺序比参数本身更重要。我的经验是先尝试不加外部干扰、不加神经网络,直接测试纯滑模控制器的跟踪能力。把纵向通道和艏摇通道的基础增益调稳,看位置误差能否收敛到小范围。这一步如果都发散,一定是控制器结构或者参考轨迹方向搞错了。

然后把干扰打开,让船在风浪流干扰下跑,观察位置误差的波动幅度。这时纯滑模可能需要把切换增益调很大才能压住,但同时会出现明显抖振。等看到抖振之后,再把神经网络观测器加进去,让网络去抵消干扰,同时把切换增益往回降。最终效果是误差依然保持在小范围,但控制量曲线明显平滑下来。

滑模面系数lambda的整定同样有技巧。它本质上是决定误差收敛带宽的,取得太小误差收敛慢,取得太大对速度噪声非常敏感,控制量容易放大噪声。一般从0.5到1.5之间开始试验。切换增益K从0.1到0.5试,以控制量曲线不“毛刺化”为上限。RBF网络的节点数从5到10个开始,中心要在工作区域内平均铺开,宽度取1~3左右。

整个参数整定过程一定要有全局视角。很多时候系统发散,不是因为某一个增益设错了,而是几个参数互相不匹配。比如自适应速率太大、但滑模切换项又太小,网络权值就会在刚开始阶段跑偏,把整个控制信号冲爆。

4. 仿真结果分析与问题排查

4.1 典型结果怎么判断是否正常

仿真跑通之后,先别急着堆一堆曲线图。重点看四类信号:位置误差、艏向误差、速度估计误差、控制输入幅值。位置误差主要是大地坐标系下的x和y方向偏差,理想情况下在初始瞬态之后进入有界稳态,不再发散。艏向误差要看它有没有收敛到期望值附近。速度估计误差是观测器质量的直接体现,如果观测器收敛,误差曲线应当在零点附近有界振荡。控制输入重点看幅值有没有超过执行机构的物理限制,以及曲线是否平滑。

我自己的接受标准大概是:稳态位置误差小于参考轨迹特征尺度的2%,艏向误差小于2度,速度估计误差收敛到真实速度的5%以内。这些数值不是绝对的,但它能快速帮你判断系统“有没有病”。如果位置误差曲线一直发毛、频繁跳出包络,通常就是控制参数或者观测器增益没有搭配好。

还有一个容易忽略的点:初始状态和参考轨迹起点之间的偏差。如果你把船初始放在距离参考轨迹十米开外的地方,而控制器又没有做初始瞬态处理,位置误差曲线上会先出现一大段“追赶”过程,这并不说明控制器不行,只是初始误差激发了系统的非线性和执行器饱和。建议初始状态放在参考轨迹附近,先把控制器验证清楚,再加初始大偏置做压力测试。

4.2 仿真中常见问题与解决方案速查

直接把我在调试过程中遇到过的问题和排查经验列在一起,供你对照。

现象可能原因排查和处理方法
仿真一开始就发散,误差飞到极大值控制器符号方向写反,或者船体坐标转换矩阵转置用错先在无干扰、无自适应条件下用小增益测试,确认跟踪方向是否正确
位置误差收敛慢,出现明显相位滞后滑模面系数lambda太小适当增大纵向和艏摇通道的滑模面系数
控制量高频抖振,像锯齿一样切换增益太大,符号函数切换过陡用饱和函数替代符号函数,并减小切换增益
加入神经网路后误差不降反升网络节点中心覆盖不足,或者学习速率过大检查RBF中心是否覆盖状态空间工作区域,调小Gamma_W
观测器速度估计和真实值偏差大测量反馈增益太小,或动力学模型偏差太大增大观测器测量反馈增益,确认神经网络有足够节点去逼近未知项
控制量在一个值附近缓慢漂移自适应增益太大导致权值参数漂移对神经网络权值加入sigma修正,即权值更新公式里加一个衰减项
圆轨迹上始终有固定方向的偏差控制器没有对参考轨迹的向心加速度进行前馈补偿加入向心加速度的参考前馈项

其中“权值漂移”这个问题,很多仿真过了但实车上失误的人都有体会。神经网络在线学习在持续存在激励时是稳定的,但当跟踪误差已经收敛得很小时,自适应律仍在慢慢调整权值,没有持续激励的情况下权值可能慢慢飘到某个奇怪的值,下一次遇到突发干扰时控制效果突然恶化。给权值更新率加一个泄漏项,也就是让权值在更新过程中缓慢回归到零附近,可以显著增强鲁棒性和实用性。

排查问题的时候不要同时改三个参数。每次只动一个变量,观察对应的误差曲线变化。把所有参数记录在案,哪怕是一个看似无关紧要的RBF宽度,也可能对最终结果有决定性影响。我在一次调参时,RBF网络从5个节点加到7个节点,跟踪误差直接下降了一个数量级,而旁边的小滑模增益还没动过。

4.3 从仿真到更接近实船的几个扩展点

仿真通过并不代表可以直接上实船。如果想把这个方向做得更深入,下面几个扩展点会非常有用。

第一个是执行器饱和与执行器动态。真实船上的螺旋桨推力有最大限制,舵机有偏转速率限制,直接把你设计的控制量限幅塞进模型,仿真结果会立刻发生变化。控制器需要在设计阶段就考虑饱和补偿,比如加入抗饱和辅助动态,避免大误差时执行器长时间卡在饱和边界上。

第二个是输入量测噪声和位置更新率限制。卫星定位数据不是连续光滑的,海上还有浪花的遮挡和丢星问题。把高斯白噪声加到位移和艏向测量上,观测器和滑模项还能不能压得住,是检验算法工程性的试金石。

第三个是把线性阻尼换成更真实的水动力模型,比如加入二次阻尼项或者速度耦合项。神经网络观测器理论上能逼近这些项,但实际逼近效果取决于网络结构和数据激励程度,需要重新调一遍。

5. 写在最后:一点实际体会

这个课题折腾到最后,我最大的体会不是某个控制公式多精妙,而是“信号流和调参顺序”往往决定了仿真能不能顺利跑通。第一次做的时候,我直接把神经观测器和自适应滑模全量加上去,结果满屏幕都是溢出错误,花了好几天才意识到是初始权值给得太大了。后来学乖了,先把观测器单独关掉、把自适应增益清零、把纯滑模控制器跑稳,再一层一层往上面加能力,整个调试过程顺利很多。

另一个心得是,神经网络中心和宽度这类参数不要追求高大上的自适应算法,刚开始用手工铺点就够。只要中心覆盖了船的速度工作范围,宽度的量级和输入变化范围匹配,在线更新就可以慢慢调整权值来逼近未知项。真正决定控制性能上限的,还是滑模面设计、前馈补偿和切换项平滑这些基本功。

如果这篇东西能让你在Matlab里少踩几个坑,哪怕是绕过“符号函数导致仿真卡死”这种最基础的问题,我觉得就值了。欠驱动船舶控制是个很有意思的方向,模型本身不复杂,陷阱全在细节里。慢慢调、多记录,你会看到位置误差曲线收敛到零附近的那个瞬间,确实挺上头的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询