ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

无人船多障碍自主避碰:从算法选型到实船验证的工程实践

无人船多障碍自主避碰:从算法选型到实船验证的工程实践

先交代一下背景:这个项目是一条1:6缩尺无人船验证平台,主要拿来跑多障碍场景下的自主避碰(collision avoidance)技术验证。去年年底到今年上半年,我在这套平台上投入了大半年时间,把从算法选型、仿真验证到实船调参的整个链路完整走了一遍。这篇东西不打算复述论文,也不打算贴一堆公式吓人,只讲工程落地过程中那些论文里不会写的事:为什么选这套方案、哪些参数最敏感、实船测试到底踩了多少坑。如果你正在做无人船、无人艇或者类似的自主航行项目,尤其在做多障碍避碰,这篇应该能帮你省不少弯路。

1. 为什么水面多障碍避碰比想象中难:先弄清问题边界

1.1 水面环境没有"标准答案",每条路径都要同时满足安全和规则

无人船的避碰和无人车的避碰看起来都是"从A点到B点、避开障碍物",但水面环境的约束完全不同。陆地上有明确车道线、交通信号灯和人行横道,障碍物的运动规律也相对可预测;水面上什么都没有,一条河、一片湖、一个港池,处处可走,但又处处不能乱走。你不仅要避开静态障碍(浮标、桥墩、码头、浅滩),还要避开动态障碍(其他船只、漂浮物、游泳区域),甚至要预测这些动态目标未来十几秒内的运动趋势。

多障碍场景真正的难点在于障碍物数量上来之后,决策空间会爆炸。单障碍避碰,算法可以找到一条漂亮的绕行轨迹;三个障碍同时出现在航道前方,彼此还会形成"夹击"态势,这时候最优解往往不是一个明确的绕行方向,而是一组需要权衡的候选方案。再加上水面运动受风、浪、流的持续干扰,你算出来的轨迹可能下一秒就被水流推偏了。所以无人船避碰从来不是"能不能碰到"的问题,而是"在什么时间窗口内、以什么方式让开"的问题。

1.2 传感器视野受限、执行器响应慢,留给决策的时间窗口很短

无人车用激光雷达加视觉,基本可以做到厘米级的环境感知;无人船差得远。水面环境空旷,特征稀疏,视觉在逆光和雾气下经常失效;毫米波雷达在水面上有大量杂波;激光雷达虽然能测障碍,但距离通常只有几十米,对小型漂浮物还容易漏检。我在项目里用到的感知组合是RTK定位、激光雷达、视觉和AIS(船舶自动识别系统)融合,但每一种都有明显的短板。

更麻烦的是执行器的响应延迟。无人船靠螺旋桨和舵转向,船体本身具有大惯性和非线性水动力特性,指令下达之后要经过一段时间才能建立转向角速度。缩尺模型相对好一些,但同样存在"打了舵船头才开始转"的延迟。这个延迟直接压缩了避碰决策的反应窗口。假如船速2米/秒,感知系统有0.3秒延迟,决策计算加执行机构响应又占掉1秒,那么留给规划系统的真实距离窗口可能只剩几米。很多算法在仿真里跑得很好,一上实船就撞,根子就在这。

1.3 COLREGs规则约束:避碰不只要安全,还要"合规"

水面航行有一套国际通用的规则,即海上避碰规则(COLREGs)。它对对遇、追越、交叉会遇三种态势下的让路责任做了明确界定:对遇时双方各自向右转向;追越时前方船保持航向航速,后方船让路;交叉相遇时,有他船在本船右舷一侧的,本船通常需要让路或减速。无人船做避碰,不能像无人机那样随便挑一个方向绕开,必须在规则框架内行动。

这个约束很烦人,但必须遵守。举个例子:两个障碍物分别位于本船左前方和右前方,单纯从几何安全角度看,向左绕行或许距离更短;但如果右前方那艘船是交叉相遇态势下的来船,规则要求你向右或减速让行,简单"抄近路"就会把一个本来合规的避让动作变成违规行为。更麻烦的是,多障碍场景下不同障碍物对应的会遇态势可能互相矛盾——对一艘船要右转,对另一艘船右转反而迎头撞上去。这时候避碰算法就得分出优先级,在规则和安全之间找平衡点。这个问题我在仿真阶段完全没意识到,直到实船测试被一艘按规则航行的真船"教育"了才彻底重视起来。

2. 我最终采用的避碰框架:分层决策与速度障碍法的取舍

2.1 候选算法横向对比:没有银弹,只有最合适的组合

先把我实际调研过的几类方案摆在一起对比,方便你快速理解它们的差异。下面是基于这个项目的经验总结,每个方案都有它的适用边界,不存在一个万能算法。

算法核心思路优点缺点本项目中的表现
人工势场法(APF)目标点产生引力,障碍物产生斥力,沿合力方向运动原理简单、计算量极小容易陷入局部极小值,目标附近振荡单障碍还行,多障碍会卡死,弃用
动态窗口法(DWA)在速度空间采样,根据预测轨迹评价安全性与效率直观、可处理动态障碍采样粒度影响性能,前瞻距离敏感作为局部执行层保留
速度障碍法(VO)求解速度空间中的碰撞锥,选择锥外速度动态障碍建模清晰,实时性好对测量噪声敏感,规则约束弱作为主决策层,改进后采用
模型预测控制(MPC)以预测模型为基础,滚动优化控制序列能显式处理约束,效果好计算量大,对模型精度要求高作为高精方案验证,未上实船
深度强化学习(DRL)通过奖励函数学习避碰策略无需显式建模,泛化潜力大训练成本高,安全性难保证只做了仿真探索,未部署

这个表不是让你直接照着选,而是想说:不同算法解决的是不同层面的问题。APF适合静态地图上的局部调整,DWA适合近距离反应,VO适合对动态障碍做速度级避让,MPC适合精确控制,DRL适合长期策略学习。单独拿哪一个出来做多障碍避碰,都会在某些场景失效。

2.2 分层结构:全局规划管"方向"、局部避碰管"动作"、应急制动管"保命"

最后落地的框架分三层。第一层是全局航线规划,在水域地图上预先规划一条从起点到终点的参考航线,只考虑静态障碍和禁航区,这一步相对简单,因为水面环境变化慢,不需要高频更新。第二层是局部避碰层,以本船为中心,利用激光雷达和融合感知获取周边障碍物的实时状态,通过改进的速度障碍法生成避碰速度指令,同时用DWA做最终的可行性校验,确保生成的速度在船体动力学允许范围内。第三层是应急制动层,当探测到障碍物进入安全距离、且局部避碰无法及时脱困时,直接执行停车、倒车甚至原地等待,优先保证不发生碰撞。

这个分层结构的核心逻辑是把"决策频率"从低到高分开:全局层的计算周期是秒级,局部层是十赫兹级,应急层则是毫秒级独立看门狗。这样即使某层出问题,其他层也不会立刻崩溃。比如全局航线规划卡了一个周期,局部避碰仍然能自主规避;局部避碰因为某个传感器数据异常失效,应急层还能做最后的刹停动作。这个设计帮我扛住了后续一大堆实船测试的突发状况,如果没有应急层,至少有两次测试会直接撞上码头边缘。

2.3 为什么没有直接上深度强化学习

现在很多论文都在推深度强化学习(DRL)做无人船避碰,我也花过不少时间在仿真环境里跑DRL相关实验,但最终没有把它部署到实船上,原因有三点。

第一,安全可解释性不足。DRL策略是一个黑箱,船一旦进入从未见过的状态,你无法预测它会输出什么动作,也无法向监管方或者验收方解释"为什么在这个关键时刻选择了这个转向角度"。对于实验平台可以容忍,对于要实际航行的系统,这是硬伤。第二,训练场景和实船环境之间存在巨大gap。仿真里可以用完美传感器模型,水流恒定向,障碍物匀速直线;实船上有噪声、有延迟、有风浪流突变,策略很容易"过拟合"仿真。第三,实船数据获取成本太高。DRL要想覆盖足够多的边界情况,需要大量失败样本,而每次失败都可能意味着碰撞事故。目前我更倾向于把DRL用在策略建议、参数自动调节这类辅助环节,主线还是用可解释的规则加优化方法。

3. 从会遇态势判断到转向决策:COLREGs的真正落地难点

3.1 先把障碍物归成三类,决策才有针对性

多障碍避碰的第一步不是算轨迹,而是给障碍物分类。我把本船感知范围内的障碍物分成三类:静态障碍,包括浮标、桥墩、固定码头和浅滩,这类障碍物位置基本不变,处理起来最简单;动态航行船,包括其他机动船只,它们受COLREGs约束,行为相对有规律,可以通过AIS和运动预测建模;突发事件目标,包括漂流的木头、小划艇、游泳区域边缘等,这类目标速度慢、运动方向不稳定,但风险很高,必须用更大的安全距离去对待。

分类之后,每个障碍物会附加上不同的"属性标签",包括最小安全半径、最高风险等级、是否受COLREGs约束。在速度障碍法计算碰撞锥时,这些属性会直接影响膨胀半径和预测时间窗口的大小。比如对一艘横向行驶的货船,我给它设定的是30米的感知膨胀半径和20秒的预测窗口;对一个缓慢漂移的浮标,膨胀半径15米、预测窗口只给8秒。分类的意义在于,不会让一个无关紧要的浮标和一条动态船占据同样的决策权重。

3.2 会遇态势判断:用速度向量和相对方位算"责任边界"

会遇态势判断是COLREGs落地的第一个难关。工程上我不会去读复杂的航海图,直接用两个核心参数来做判断:相对方位角(他船相对本船方位与船艏向的夹角)和本船相对他船的速度向量。以本船为中心建立一个运动坐标系,根据这两个参数把会遇情形分成对遇、追越、左交叉、右交叉等类别,每一类对应一组默认避让动作。

我对接实船数据时发现了一个之前没太在意的细节:态势判断必须持续稳定,不能频繁跳变。如果某个目标正好处于两种态势的边界附近,比如相对方位在交叉和对遇之间摇摆,决策系统就可能一会儿输出向右转、一会儿输出保向,导致船走成"S形"。解决办法是给态势判断加一个"滞回区间",也就是状态切换必须连续满足多个周期,且角速度方向一致。这个做法跟信号处理里的消抖一个思路,代价是判断延迟增加几百毫秒,但换来的是决策稳定性,值。

3.3 速度障碍法(VO)实际落地:从碰撞锥到可航行速度域

速度障碍法的核心思想不复杂:把本船视为一个膨胀的圆,假设障碍物在未来一段时间内按当前速度运动,那么本船哪些速度向量会导致撞上它,在速度空间里就会构成一个"碰撞锥"。只要选择一个落在碰撞锥之外的速度向量,就能在预测时间内避开这个障碍。多障碍场景变成多个碰撞锥的叠加,我们的任务是在速度空间里找到一块同时避开所有碰撞锥的区域。

实际工程中有三个改进点。第一,把碰撞锥的预测时间设为可变化:对近处的动态障碍物用短预测窗口,反映其当前运动趋势;对远处障碍物用长窗口,过滤掉瞬时抖动。第二,引入"时间优先"机制——如果两个碰撞锥重合,优先处理TCPA(最短会遇时间)更小的那个障碍物,因为它是真正的紧急威胁。第三,速度选择不能只求避开碰撞锥,还要靠近目标方向并保持稳定转向,所以我在VO之后接了一个代价评价函数,把"偏离航线的代价""转向角速度的代价""与障碍物最小距离的代价"加权求和,选出最优速度。加了这个评价层之后,船的轨迹明显比纯VO输出的要平滑很多。

3.4 多障碍优先级仲裁:当规则和规则打架时怎么办

多障碍场景最棘手的问题是优先级冲突。典型情况:本船前方左侧是静态桥墩,前方右侧是一艘交叉相遇且负有让路义务的动态船。如果按COLREGs处理动态船,应该向右转向;但向右又会撞向桥墩。这时候算法必须在"让路责任"和"物理安全"之间做出取舍。

我的处理原则是安全优先、规则次之,但不完全抛弃规则。具体做法是把每个候选速度向量都做两层过滤:第一层排除所有会导致碰撞的向量,无论规则上多么正确,物理上可能撞船的动作一律不用;第二层在剩余的安全向量里,优先选择满足COLREGs语义的那个方向。如果规则要求的动作恰好撞向静态障碍,则退而求其次,选择一个既避开静态障碍、又能在后续适当时机回归规则动作的向量。这个"先安全后合规、尽量兼顾"的策略在仿真和实船测试中都跑得很顺,也比较好向监管方解释。

4. 多障碍场景的参数标定与仿真验证过程

4.1 仿真平台搭建:不能完全依赖场景库,要自己加变态场景

我在仿真阶段用了主流机器人仿真环境,自行搭建了一套水面场景。规划了一块长500米、宽200米的水域,在其中随机布置了8到16个不同类型的障碍物,包括固定浮标、运动船只、随机漂移物,还加了一段狭窄航道。之所以不用纯随机布置,是因为避碰算法必须在"有结构的场景"里才看得出问题:狭窄航道两侧有静态障碍,中间有一条运动船对向而来,这种场景才能逼出进退两难的局面。

仿真平台的输出不止是轨迹,我还要记录本船每一时刻的速度指令、障碍物预测位置、决策标记(是保向、转向还是减速)以及最小会遇距离。这样每一帧都能回放,定位问题时能看到"是感知丢了目标,还是决策没算出来,还是执行没跟上"。我的一个建议是:仿真环境里至少加两类极端场景,一类是障碍物突然出现(比如从转弯盲区冲出),另一类是动态障碍物突然改变航向。这两种情况最容易暴露算法在预测模型和响应时间上的弱点。

4.2 关键参数标定:膨胀半径、预测窗口、采样频率、权重系数

参数标定是避碰算法从"能跑"到"跑得好"的分水岭。我这里把最关键的几组参数列出来,并说明它们是怎么影响行为的。

参数作用标定结论标定方法
障碍物膨胀半径决定本船距离障碍物的安全距离船宽的2.5倍到3倍之间最合适实船测试从大到小试
预测时间窗口决定VO算法看多远的未来动态目标10到20秒,静态目标6到10秒根据船速和制动距离推算
局部规划频率每个避碰决策周期的时间间隔10赫兹即可,再高船体跟不上对比轨迹平滑度
转向角速度限幅最大允许的转向速率限制在船体能达到的最大角速度的70%实测动力模型
安全距离阈值触发应急制动的条件当前速度下需要的最小停船距离制动实验测量

膨胀半径这个参数很有意思,设得太小,船贴着障碍物擦过去,看起来效率高,但一旦有风浪扰动或者水流突变就直接撞;设得太大,狭窄航道又过不去,误报率飙升。我的最终策略是让膨胀半径与当前船速挂钩,速度越快膨胀越大,速度降到接近零时膨胀半径收缩到船宽加一个固定余量。这个"动态膨胀"既保安全又不牺牲通过性。

4.3 评价指标与仿真结果:选对指标,问题才暴露得出来

评价避碰算法不能只看"有没有撞上",我用四个指标:碰撞次数、最小会遇距离(DCPA)、最短会遇时间(TCPA)和路径偏离度。前两个反映安全性,第三个反映决策的时效性,第四个反映效率。在仿真阶段,随机场景跑了300组(同样场景分布、不同随机种子),最终碰撞次数为0,所有场景的最小会遇距离都大于3倍船宽,TCPA低于3秒的情况没有出现过。

但"仿真成绩好"恰恰是最危险的信号。我后来复盘发现,仿真里障碍物模型是纯数学的,没有传感器噪声,没有水面反射,也没有水动力延迟,所以算法很容易表现得"太完美"。真正有效的验证方式是"带噪声仿真":给障碍物位置加上1米左右的高斯噪声,给速度测量加10%的随机误差,重新跑同一批场景,碰撞率立刻从0升到平均每百次1.2次。这套带噪声测试后来成了我的标准配置,也让算法在实船测试前的可靠性提升了一大截。

5. 实船测试踩坑记录:传感器、动力延迟与安全兜底

5.1 传感器层面的坑:逆光、水花、雷达近距杂波

实船和仿真最大的不同,是你要面对一个"不干净"的传感器世界。第一次上实船时,视觉检测在逆光方向直接失效,水面变成一片白茫茫,浮标完全消失。后来加了偏振镜片,选在非逆光时段测试,但治标不治本,真正解决还是要靠多传感器融合:视觉丢掉的目标,激光雷达能补回来;激光雷达漏掉的近距离漂浮物,视觉又能及时报出来。

另一个坑是水花。船高速行驶时溅起的水花会打湿激光雷达镜头,造成大范围误报。我测试时出现过一次"前方出现一整面弧形障碍墙"的假象,差点触发应急制动。排查下来是水花正好在雷达扫描平面内形成了连续反射点。解决思路是给雷达加装挡水罩,同时在驱动层加一个最小有效距离的滤波逻辑,对距离突变的目标做时长校验,只有持续存在足够多扫描周期的目标才被认为有效。这个方法牺牲了一部分真实紧急情况的响应速度,但换来的误报率下降非常明显。

5.2 动态障碍预测偏差:运动模型太简单会害死人

我在预测动态障碍物时最初用的是恒定速度模型,也就是假设他船在未来一段时间保持当前速度和航向。这个模型在开阔水域对付正常航行船基本够用,但一旦遇到他船开始转弯,预测轨迹和实际轨迹会迅速分离。仿真里我很少遇到这种情况,实船上却经常出现"他船突然向右转,本船还以为它继续直行,直到预测位置和实际位置差出十几米才反应过来"。

痛定思痛之后,我引入了"机动检测"机制。不断用实际观测数据和预测轨迹做对比,如果连续若干周期内偏差超过设定阈值,就判定他船正在机动,立刻丢弃旧预测、重新初始化预测模型,同时将本船的安全距离阈值临时上调30%。这样做的代价是会让避碰动作变得更加保守,但实船测试中我宁可保守,也不能赌对面会按直线航行。

5.3 动力模型失配与修正振荡:船的响应真的慢半拍

在仿真里,我给速度指令加了一个一阶延迟模型,自以为已经考虑到了船体惯性。实船一跑才发现,真实的水动力特性比一阶延迟复杂得多:低速时舵效差,船头转得慢;高速时惯性大,转弯半径明显变大;再加上侧向风和水流的作用,实际航向和期望航向的偏差经常超过20度。局部避碰算法如果只看期望速度,不看当前船体状态,就会导致过度修正——左转没转过来就右转补偿,船在水面上走出一条明显振荡的蛇形轨迹。

解决方法是把"船体运动模型"嵌入到DWA的轨迹预测里。每次采样候选速度时,不只是做纯运动学外推,而是用一个简化水动力模型预测未来2秒内船的实际航向变化,再计算候选轨迹是否会撞到障碍。这个改动让避碰动作的"预判性"好很多,船的轨迹也平滑了不少。但我也明白,这个简化模型在浪大时依然不准,所以又加了一条规则:当船体横摇和航向偏差同时超过阈值时,自动降低允许的最大船速,给决策留出更多反应时间。

5.4 安全兜底不可少:应急制动和人工接管的最后防线

不管算法做得多完善,工程上总要有"最后一道防线"。我在系统里单独实现了一个应急制动模块,独立于局部避碰逻辑运行。它持续监控最近障碍物的距离和相对速度,如果计算出的剩余碰撞时间低于设定安全阈值,会直接发送制动指令,同时暂停所有避碰规划输出。这个模块逻辑极简,没有复杂的判断,就是为了确保在最极端情况下能停下来。

此外,系统保留了远程人工接管通道。实船测试期间,无论算法运行得多稳定,我都会让操作员保持在遥控器附近,测试区域也划定在开阔水域、留足缓冲距离。项目结束前的一次偶发通信断链,让我彻底意识到"本地看门狗"的重要性:当遥控链路断开时,船端的自主系统必须在几十毫秒内接管,否则船会按最后一次指令盲目航行。我把通信状态监控、本地自主接管和应急制动串成了一条完整的安全链,之后的测试才真正踏实。

结语:一点个人体会

如果你问我在这个项目里收获最大的是什么,我会说不是某个算法调得有多好,而是彻底理解了"算法只是避碰系统的一小部分。真正决定能不能安全航行的,是感知的可信度、决策的可解释性、执行的鲁棒性,以及系统整体的安全兜底。多障碍自主避碰没有一个放之四海而皆准的方案,任何论文里的算法到了实船上都会露出原型。最稳的路径永远是:先在带噪声的仿真环境里把边界试探清楚,再拿着保守的参数上实船逐步放宽,每放宽一个参数都要用跑过的场景复盘。这套方法论,比任何单一算法都更值得花时间去打磨。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进