AUV三维路径跟踪:LOS制导与反步控制的Matlab仿真实现全解析

做水下航行器(AUV/UUV)控制这块的同行,应该都体会过一种憋屈:模型建了一堆,控制器调了一轮,拿到仿真里一跑,二维路径稳稳当当,一旦塞进三维空间——俯仰、偏航、深度同时上强度,跟踪误差直接起飞,姿态乱抖,甚至直接跑飞。这个项目就是我拿“LOS视线制导 + 反步控制”组合硬磕三维路径跟踪的一次完整记录,用Matlab从零搭仿真,把算法掰开揉碎,最终让航行器在三维曲线路径上实现了稳定跟踪。

这篇文章不是教材复读,就是一套能直接抄作业的实现方案:从三维LOS制导的几何推导,到反步控制器的递归设计,再到Matlab代码的模块划分、参数调节、坑点排查,全部摊开来讲。适合正在做AUV/UUV运动控制、水下机器人路径跟踪方向的同学,或者想把经典非线性控制方法落地到仿真里的人参考。

1. 先说结论:这套“LOS制导+反步控制”方案到底解决了什么

1.1 从导航、制导到控制的三个层级

水下航行器做路径跟踪,很多人一上来就抱着动力学模型调PID,这是一个很容易把自己绕进去的误区。我在这个项目里首先做的一件事,是把问题拆成三个层次。

导航层解决“我在哪”,制导层解决“我该往哪走”,控制层解决“我怎么走过去”。三维路径跟踪的核心难点,其实大部分集中在制导层:面对一条在空间里弯曲延展的期望路径,航行器要怎么实时判断自己偏离了多少、该朝哪个方向修正。至于控制层,它只需要老老实实跟踪制导层给出的期望姿态即可,不需要关心路径本身是什么形状。

很多同学直接用PID跟踪路径点,相当于把制导功能硬塞进控制器里,控制器既当导航又当制导还要压姿态,参数稍有不合适就会顾此失彼。LOS制导的作用,是把“路径误差”翻译成“期望航向角 + 期望纵倾角”,反步控制器再去跟踪这两个角度,形成清晰的级联结构。

1.2 为什么是LOS配上反步,而不是PID配上视线法

在AUV运动控制领域,底层控制器用PID依然很常见,但反向步进(Backstepping)和PID的差异,在三维跟踪场景下很明显。PID是“按误差调输出”,不关心被控对象的非线性动力学结构,当航行器在大角度纵倾、大曲率路径下出现强耦合时,PID输出的力矩往往滞后于真实需求,表现就是“慢半拍”和“抖”。

反步控制器的思路不一样。它从Lyapunov稳定性出发,把系统的非线性项一层层“回推”进控制律,最终给出的控制力矩本身就包含对模型动态的补偿。换句话说,PID是在被动修正误差,而反步是在主动构造一个保证误差收敛的动态系统。我实测下来,同样的扰动条件下,反步控制结合LOS制导的跟踪轨迹明显更“贴着”期望路径走,超调和初始误差下的恢复速度也要好一个量级。

当然,反步控制的前提是模型比较清晰,如果AUV的水动力系数完全未知,那参数自适应部分需要另行处理。这也就是为什么我选Matlab做实现——先把理想模型下的算法跑通,再考虑不确定性,是工程上务实的推进顺序。

2. 算法原理拆解:LOS视线制导与反步控制的来龙去脉

2.1 从二维LOS到三维视线制导,几何上发生了什么变化

经典的LOS制导大家应该都见过:在水平面上,取路径当前点前视距离之外的参考点,导航器瞄着那个点生成期望航向角。这个思路的几何直观很好理解,就好比你走路时不是低头盯着脚下的一小块地砖,而是看着前方几米远的目标点,身体自然就沿着平滑轨迹走过去了。

问题是到了三维空间,一个“前方几米”的目标点就不够用了。水下航行器不仅要决定往哪个水平方向转,还要决定往上浮还是下潜。这就要把LOS扩展出两个角度。

我在三维LOS中做了这样的处理:把期望路径参数化为一条空间曲线,路径上任一点的位置和切线方向都可以用路径参数s表达。航行器当前位置与路径上参考点(比如前视距离对应点)的连线,在水平面的投影决定了期望航向角ψ_d,在垂直剖面上的投影决定了期望纵倾角θ_d。

这里有个容易踩坑的细节:三维LOS不能简单地“水平角+垂直角分开算”,因为路径本身的切线也是三维的。正确的做法是先把期望路径切线方向投影到水平面求ψ_path,再把航行器相对于路径参考点的垂直偏差换算成纵倾角叠加到θ_path上。如果直接把三维误差向量送进atan2,耦合项会让横滚通道看到一堆乱七八糟的交叉误差,仿真曲线当场乱给你看。

前视距离Δ的选择也很有讲究。Δ太大,航行器会“切弯道”,小曲率路径上还能容忍,大角度拐弯时误差积累明显;Δ太小,等效制导增益太高,系统容易振荡。我在这类尺度约5米量级的AUV模型上,Δ通常取2到3倍艇长,算是一个经验区间的起点。

2.2 反步控制器的递归推导:一步步构造Lyapunov函数

在LOS制导给出ψ_d和θ_d之后,反步控制器的任务就是设计舵面力矩τ_r和τ_q,让实际航向ψ、纵倾θ分别收敛到参考角,同时维持前向速度u稳定在期望速度值。

反步控制设计的标准流程,是先定义误差变量,再逐层设计虚拟控制率。以航向通道为例,我定义:

e_ψ = ψ - ψ_d

如果把AUV的偏航动力学写成 ṙ = f_r(u,v,r) + g_r τ_r,那么第一步要把ψ_d的导数视为已知量,设计虚拟控制α_r。定义e_r = r - α_r,构造Lyapunov函数:

V1 = ½e_ψ² + ½e_r²

对V1求导,代入系统方程,控制项τ_r就会在“消除交叉项 + 引入负定阻尼”的位置出现。最终形式一般落成:

τ_r = -k_ψ e_ψ - k_r e_r + 模型补偿项 + ψ_d的二阶导数项

同样的流程在纵倾通道走一遍,得到τ_q。这个推导过程看起来只是数学游戏,但它保证了闭环系统的Lyapunov导数负定,也就是跟踪误差不仅收敛,而且有一个明确的衰减率估计。这就是为什么反步控制在理论上比“试凑好”的PID更让人放心——它的稳定性,是设计出来的,不是碰运气碰出来的。

2.3 稳定性分析的“面子工程”为什么不能省

说句实话,我在做仿真的时候,最开始也想过跳过Lyapunov推导,直接把增益调出来算了。但踩了几次坑之后我明白了,稳定性分析在调试中最重要的作用,是指出“增益项和控制量项之间的约束关系”。

比如,反步控制器中的阻尼项增益k_r,如果取得过大,控制力矩会出现剧烈的瞬态尖峰,仿真步长稍大就发散;如果取得过小,跟踪误差收敛慢,切弯时横向偏差能拖到十几米。PiD没有这种可解释性,但反步公式里每一项都有对应的物理意义,调参时方向感强得多。

所以,哪怕你最后只是把代码跑通,也强烈建议把Lyapunov函数的推导完整走一遍。它不只是为了论文里写“闭环系统稳定”,更是你在仿真里遇到问题时的第一份排查地图。

3. Matlab仿真实现:从白纸到调试跑通的完整流程

3.1 仿真框架搭建:五个体模块,别把代码全塞在主脚本里

在Matlab里做AUV三维路径跟踪仿真,最忌讳的就是把所有计算堆进一个for循环,几百行代码下来,变量命名混乱,改一个参数要翻半天。我用的结构是五个模块文件,通过主脚本串联。

第一个是路径生成模块,定义期望空间曲线的参数化方程x_d(s)、y_d(s)、z_d(s),同时给出对应的一阶导数函数,CLOS制导需要切线方向,这个必须一起配好。第二个是制导模块,输入当前航行器位置和路径参数s,输出ψ_d、θ_d。第三个是控制器模块,输入姿态误差和参考角速度,输出推进力τ_u和力矩τ_r、τ_q。第四个是AUV动力学模块,输入控制量,输出状态导数。第五个是主仿真脚本,负责设定仿真时间、初始状态、参数表,然后用ode45积分整个状态向量。

这种模块化的好处是每个模块都能单独测试。比如,你可以先固定路径参数s不变,单独给制导模块喂一组位置数据,人工检查输出的期望角是否符合几何直觉。这种可视化验证比直接跑完整仿真定位问题快得多。

3.2 核心代码逐个说:制导律和反步控制律的Matlab实现

制导模块的核心代码并不长,关键是把几何关系写对。我用的实现代码大致如下。

function [psi_d, theta_d, s_ref, x_ref, y_ref, z_ref] = losGuidance3D(P, s, path, Delta_H, Delta_V) % P: 航行器当前位置 [x; y; z] % s: 当前路径参数 % path: 路径函数句柄,返回位置和切向量 % Delta_H, Delta_V: 水平/垂直前视距离 % 由当前s计算参考点位置与切向量 [S, dS] = path(s); x_ref = S(1); y_ref = S(2); z_ref = S(3); tx = dS(1); ty = dS(2); tz = dS(3); % 路径切线的水平方位角 psi_path = atan2(ty, tx); theta_path = atan2(-tz, sqrt(tx^2 + ty^2)); % 水平横向误差(在路径法平面投影) ex = P(1) - x_ref; ey = P(2) - y_ref; ez = P(3) - z_ref; % 视线参考点:沿路径切线方向前视 s_ref = s + Delta_H / norm(dS); [Sr, ~] = path(s_ref); x_los = Sr(1); y_los = Sr(2); z_los = Sr(3); % 三维视线角 psi_d = atan2(y_los - P(2), x_los - P(1)); theta_d = atan2(-(z_los - P(3)), sqrt((x_los - P(1))^2 + (y_los - P(2))^2)); end

这是三维LOS最直观的实现方式:取路径上超前一点作为视线目标,然后计算水平视线角和垂直视线角。这种写法的优点是简单,缺点是前视距离在路径曲率大的地方会让视线目标跨过弯道,我通常在曲率变化剧烈的路径上对s_ref做一个限幅,避免视线点一次跳太远。

控制器模块的反步律,实现起来更直接:

function [tau_u, tau_r, tau_q] = backsteppingController(z, psi_d, theta_d, dpsi_d, dtheta_d) % z: 状态向量,包含 u, v, w, psi, theta, r, q u = z(1); r = z(6); q = z(7); e_psi = z(4) - psi_d; e_theta = z(5) - theta_d; % 虚拟控制 alpha_r = dpsi_d - k1_psi * e_psi; alpha_q = dtheta_d - k1_theta * e_theta; e_r = r - alpha_r; e_q = q - alpha_q; % 反步控制力矩,m_66、m_55为转动惯量相关项 tau_r = m_66 * (dalpha_r - k2_r * e_r - e_psi) + f_r_model(z); tau_q = m_55 * (dalpha_q - k2_q * e_q - e_theta) + f_q_model(z); % 速度控制 tau_u = m_11 * (u_d_dot - k_u * (u - u_d)) + f_u_model(z); end

从代码可以看到,反步控制律的结构非常规整:第一项是惯性补偿,第二项是阻尼项,第三项是交叉项消除,最后是模型已知项的补偿。每个k值都能对应到Lyapunov导数中的一项,这种结构性正是它便于排查问题的原因。

3.3 参数选择经验与调试图:前视距离、控制器增益怎么定

参数初值怎么给?我的经验是这样的:

反步增益k1_ψ、k1_θ决定虚拟控制层对姿态角误差的响应速度,我一般从0.5到2之间起调,增大可以加快收敛,但过大会让虚拟控制率α_r变化太猛,间接导致后面的力矩饱和。k2_r、k2_q是真正的阻尼项,取值通常比k1大一半到一倍,比如k1_ψ=1、k2_r=1.8,这样能保证二阶系统有一个合理的阻尼比。

前视距离Δ我取水平平面2倍艇长、垂直方向1.5倍艇长。如果发现跟踪轨迹在转弯处明显外“甩”,适当增大前视距离;如果出现蛇形振荡,则调小前视距离。这个调节规律跟汽车“看远看近”是一个道理,看太近容易来回修方向盘,看太远则会在小半径弯道里直接切过去。

速度通道的k_u比较简单,按期望的收敛时间常数取,例如5秒内收敛到期望速度,那么k_u≈m_11/5。注意单位要匹配,不要直接用数字硬凑。

4. 常见问题与排查技巧实录

4.1 仿真一发散就怪路径曲率?先检查这三个点

我在调试中碰到的第一个大问题,就是仿真往往跑到某个时刻突然数值爆炸。刚开始我怀疑是路径曲率太大、控制器跟不上去,后来逐步定位发现,绝大多数发散都不是算法失效,而是三个低级错误。

第一是制导模块中的路径参数s更新方式有误。如果用固定的参数增量前进,而不考虑当前误差在路径切向的投影,那么当航行器偏离路径较远时,参考点会沿着路径一直往前跑,导致视线角出现大幅度跳变,仿真实质上是在跟踪一个“失控的假想目标”。解决方案是用切向投影法更新s,让参考点随着航行器的实际位置“回拉”或“前送”。

第二是执行器输出没有做限幅。反步控制律里的模型补偿项在高速段会算出一个很大的力矩,如果直接丢给动力学积分,数值上很容易被ode45判定为刚性而崩溃。我一般用饱和函数把τ_r和τ_q限制在合理范围,宁可让跟踪短暂迟滞,也不要让力矩瞬间打满舵。

第三是状态导数里有角度跳变。Matlab里atan2返回的角度范围是[-π,π],如果参考航向角在±π之间跳变,微分项会在跳变瞬间出现巨大的尖峰。这个问题的标准解法是角度误差做wrap处理,并且保证参考速度的微分计算使用经过unwrap的角度序列,而不是原始角度。

4.2 跟踪误差收敛慢、姿态抖振,怎么调

如果你的仿真不炸,但就是跟踪效果“差点意思”,最常见的两个现象是误差收敛慢和姿态通道抖振。

误差收敛慢,优先检查水平和垂直前视距离是否太大。前视距离本质上就是比例制导增益的倒数,看太远等于增益太小,系统当然懒洋洋的。另一种可能是反步增益k1_ψ、k1_θ取值过低,与k2阻尼项比例失调,导致系统接近临界阻尼甚至欠阻尼,收敛时间被拉长。我遇到过一组参数,k1_ψ=0.5、k2_r=1.5,看起来单独看都合理,组合起来却出现慢速振荡,后来把k1_ψ提到1.2,问题立刻消失。

姿态抖振则是另一类问题,通常出现在模型补偿项中存在未光滑的sign函数或绝对值变化剧烈时。解决思路有几个:一是检查f_r_model中是否有v、w项在低速段的强非线性,比如水动力阻尼的数次方项在零附近突跳;二是在反步阻尼项中用饱和特性替代纯线性,比如把k2_r * e_r改为k2_r * tanh(e_r/ε),这样可以保持线性段增益,同时限制大误差时的力矩尖峰;三是检查仿真时间步长,ode45默认误差容差在快速通道上可能不够精细,把RelTol降到1e-5以下常能显著改善抖振。

4.3 三维跟踪调试顺序建议

最后分享一下我调试这套系统的固定顺序,遇到问题的同学可以按序排查。

先把控制器目标ψ_d、θ_d固定为常量,比如让航行器沿固定航向和纵倾做定深匀速直行,确认反步控制器能稳定跟踪常量参考角;然后把参考角替换成正弦扫频信号,测试控制器的动态跟踪能力和相位延迟;再把制导模块接进来,但路径先选直线或者大半径圆弧;最后才上螺旋潜航路径或者复杂三维曲线。

这个顺序能有效隔离问题:如果第一步就炸,问题在控制器或模型;如果前三步都好,第四步才炸,那基本是制导模块里的几何或参数更新逻辑有问题。我踩过最深的坑,就是跳过了第二步直接上了螺旋路径,结果又调模型又调制导又调路径,三个变量混在一起,查了两天才定位到是路径参数s更新时没有做归一化,导致大曲率段参考点跳变。

5. 一点后续想说的

这套LOS+反步控制方案,在纯数学仿真里已经能拿到很漂亮的跟踪曲线,但上了真艇还要面对流干扰、模型摄动、执行器延迟。我在后续扩展里试着加入了海流扰动模型——把水流速度作为常量场加到运动学方程右侧,结果发现没有海流补偿项的纯反步控制器会在横流环境下产生固定的稳态偏航。要解决这个问题,通常需要把LOS制导扩展为自适应LOS或者加一个扰动观测器,这算是这个方向最有价值的自然延伸。

如果你想在这个基础上继续做,我的建议是先把自己的路径跟踪仿真“跑稳定、跑重复、跑可解释”,再去碰浪、流、扰动这些“进阶副本”。毕竟控制算法这行,稳定的基线比炫技重要得多。

相关新闻

Druid监控漏洞全解析:从排查到修复的实战指南

Druid监控漏洞全解析:从排查到修复的实战指南

上个月给一个业务系统做安全巡检的时候,发现 Druid 监控页面居然可以直接打开,数据库表结构、SQL 语句、Session 信息就那么摆在页面上。当时第一反应是“这不该出现在生产环境”,第二反应是“如果被外面的人扫到,后果很麻烦”。后…

2026/10/21 7:21:56 阅读更多 →
微服务依赖冲突

微服务依赖冲突

项目场景: 微服务依赖冲突导致网关启动失败原因分析:项目在启动网关的时候,报错如上图。 要求移除 spring-boot-starter-web 依赖,经过查找发现geteway中使用WebFlux(Reactor Netty,响应式) 和…

2026/10/21 7:20:56 阅读更多 →
Jetson平台OTA升级实战:Mender+Yocto+Docker全栈解析

Jetson平台OTA升级实战:Mender+Yocto+Docker全栈解析

我最初接触OTA(Over-The-Air,空中升级)这个概念,是因为一台部署在偏远现场的设备出了问题,固件出了bug,却没法远程修复,只能派人带着U盘坐几个小时车过去刷机。那种被动和低效,经历过…

2026/10/21 7:20:56 阅读更多 →

最新新闻

Text-to-Prototype与D2C实战:从一句话到可交互原型的工程化工作流

Text-to-Prototype与D2C实战:从一句话到可交互原型的工程化工作流

一句话丢给 AI,它真能吐出一套能点、能跳转、能填表单的 App 原型?这个问题在过去一年里被问了无数遍,我自己也拿它当正经课题折腾了小半年。Text-to-Prototype,也就是文本生成原型,再到 D2C(Design to Cod…

2026/10/21 7:54:10 阅读更多 →
2026年Agent智能体趋势观察:从玩具到员工的关键跃迁

2026年Agent智能体趋势观察:从玩具到员工的关键跃迁

想要准确判断一份行业报告的含金量,其实看两样东西就够:它可以不用被证伪的底层逻辑,以及它敢不敢给出明确的到达时间点,而不是和稀泥。最近我深度研读了一份来自某头部科技公司研究团队的调研报告预览稿,报告的名字很…

2026/10/21 7:54:10 阅读更多 →
Bootstrap 5实战:从源码构建到深色模式一键切换

Bootstrap 5实战:从源码构建到深色模式一键切换

简介:本资源是一套面向前端初学者与进阶开发者的Bootstrap 4.0系统化学习材料,聚焦响应式网页开发核心能力培养,解决从零掌握栅格布局、组件集成、JS插件调用到真实项目落地的全链路学习痛点。压缩包共1389个文件,涵盖250个HTML实…

2026/10/21 7:54:10 阅读更多 →
Anaconda多环境管理:AI编程环境隔离与依赖管理实战指南

Anaconda多环境管理:AI编程环境隔离与依赖管理实战指南

1. 为什么Python多环境管理是AI编程的第一道坎搞AI编程的人,十个里有八个被Python版本和依赖冲突折磨过。你兴冲冲地从某个开源仓库clone下来一个项目,README上写着"pip install -r requirements.txt",你老老实实执行了&#xff0c…

2026/10/21 7:54:10 阅读更多 →
本地批量文本替换工具:正则、编码与安全操作全解析

本地批量文本替换工具:正则、编码与安全操作全解析

简介:随风文本替换专家 v2.0 是一款面向程序员、编辑校对与数据分析人员的文本批量处理工具,主要解决大量文件中重复替换、批量添加内容的低效问题。软件支持纯文本、Java、HTML 等常见格式,并具备正则表达式匹配、替换预览与整目录批量处理能…

2026/10/21 7:54:10 阅读更多 →
MySQL字符集与校对规则完全指南:从乱码到utf8mb4实践

MySQL字符集与校对规则完全指南:从乱码到utf8mb4实践

1. 字符集与校对规则的真实分工:一个管“存”,一个管“比”先抛个很多人在面试或排查乱码时都会卡住的经典问题:为什么我给表指定了utf8mb4,也存进去了一些中文,可一查出来全是“???”,或者搜索a和A的结…

2026/10/21 7:53:09 阅读更多 →

日新闻

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

统一内存+量化:锐龙AI Max PRO 400如何本地跑320B大模型

这段时间硬件圈和AI圈都在传一个事:AMD锐龙AI Max PRO 400系列把最高192GB统一内存搬进了PC形态的产品里,按宣传口径,本地跑320B参数的大家伙不再是纸面概念。我第一反应倒不是“内存真大”,而是这话背后的含金量——它把过去只能…

2026/10/21 0:00:11 阅读更多 →
AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

AI助手深度使用体验:对话质量、长文本处理与指令遵循如何留住用户

1. 从“封号重开”这个行为说起:用户到底在追求什么“封号重开”这四个字,放在任何产品语境里都带着一股决绝的味道。一个账号从零开始积累使用记录、调教偏好、沉淀工作流,背后是大量的时间和精力成本。正常情况下,没有人愿意主动…

2026/10/21 0:00:11 阅读更多 →
ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

ROS中YOLOv3工程落地:通信同步、坐标变换与性能调优

1. 为什么在ROS里硬刚YOLOv3不是“炫技”,而是工程落地的必经之路我第一次在某高校机器人实验室看到那台搭载Jetson TX2的移动底盘原地打转、反复识别错垃圾桶时,就意识到:单纯跑通darknet_ros demo和真正让YOLOv3在ROS里“干活”&#xff0c…

2026/10/21 0:00:11 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/20 10:02:13 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/20 20:43:59 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/21 4:27:17 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 10:02:08 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 9:50:45 阅读更多 →