海上故障只出现一次,先录全数据再修
假设一艘无人船靠港时反复偏航,回办公室重放日志却一切正常,这说明为何复现必须排在修复之前。
要点速览
- 在现场,复现缺陷往往比修复更难。先录数据,再修复。
- 回放能复现,问题就在软件;回放复现不了,就怀疑输入(硬件、网络)或技术栈本身不确定。
- GPS 丢失、动力故障这类失效,要在受控试验中主动触发,别等真实环境替你触发。
设想一艘无人船,整个上午都在近海按计划航线稳定行驶。到了下午进港时,它开始偏离航向,自行修正,然后又偏。你把日志带回办公室重跑一遍,一切正常。
处理这类缺陷,是从事自主系统的前线部署工程师(FDE)的本职工作之一。制造自主水面船艇的 Saronic 这样描述自己的 FDE:在真实环境中集成、部署并改进自主系统的人。
按照岗位描述,FDE 在部署过程中要同时处理软件、硬件和网络问题,而且 50% 以上的时间在国内外出差。
你也许一辈子都不会登船。但几乎每个 FDE 都遇到过只在客户现场出现的缺陷:挂不上调试器,网络很慢,也没人能把那一刻原样重放给你看。海上是这个问题最严酷的版本,因此也是学习它最清楚的地方。
在现场,难的是复现缺陷
海上的每一刻都只发生一次。海浪、风、周边船只和卫星信号,不会再以同样的方式凑到一起。如果什么都不录就在现场匆忙修复,你无法证明修复是对的;缺陷再出现时,你也认不出来。
在 Saronic,海上测试规划岗位用一套结构化流程跟踪缺陷,每个缺陷都记录复现步骤、严重程度和纠正措施。值得借鉴的原则是:在能复现缺陷之前,你没有任何可靠的东西可修。
复现需要数据。Saronic 称,其 Corsair 船艇的耐久试验产生了约 500 小时的多摄像头视频,总计约 17 TB。
该公司表示,会把这批数据用于模型开发、回放和回归测试。这次试验设计为连续运行,用来评估可靠性和耐久性,也就是暴露短时测试发现不了的缺陷。
链路太慢,逼你选择往回发什么
一项关于自主船舶的研究指出,它们在海上受限于低带宽卫星链路。没人会通过这样的链路传 17 TB 数据。于是任务一分为二:所有数据录在船上的机器里,岸上只收到足够让人知道“出事了”的信息。
下面是这个思路的简单示意。阈值、冷却时间和字段名都只是示例:
import collections, json, time
def send_over_satlink(msg):
"""桩函数:替换为带队列和大小限制的真实卫星客户端。"""
payload = json.dumps(msg).encode()
assert len(payload) < 512, "摘要必须足够小"
print("SATLINK", payload)
class FieldRecorder:
"""所有数据录在本地机器上,慢速链路上只发摘要。"""
def __init__(self, window_s=120, rate_hz=50, cooldown_s=60):
self.buf = collections.deque(maxlen=window_s * rate_hz)
self.cooldown_s = cooldown_s
self.last_snap = {} # reason -> 最近一次快照的时间
def record(self, s): # s:包含 t、heading_err_deg、gps_fix、link_ok、sw_version 的 dict
self.buf.append(s)
if abs(s["heading_err_deg"]) > 5:
self.maybe_snapshot("heading_error")
def maybe_snapshot(self, reason):
now = time.monotonic()
if now - self.last_snap.get(reason, float("-inf")) < self.cooldown_s:
return # 仍是同一段航向误差,不再生成新快照
self.last_snap[reason] = now
path = f"/data/snap_{int(time.time())}_{reason}.jsonl"
with open(path, "w") as f:
for s in self.buf:
f.write(json.dumps(s) + "\n")
# 卫星链路上只走几百字节,完整文件留在船上
send_over_satlink({"reason": reason, "file": path, "n": len(self.buf)})
关键在环形缓冲区:检测到异常时,你手里已经有之前两分钟的数据,也就是导致缺陷的那一段。冷却时间同样重要。没有它,一段持续几分钟的航向误差会生成成千上万个快照,既写满磁盘,又堵死卫星链路。
还要在同一条记录里写下三层的状态:软件版本、GPS 状态和链路状态。这样隔离缺陷时,证据就在手边。
示例:靠港时的航向误差
回到开头那艘船。这是一个用来练习方法的设想场景,并非 Saronic 公布过的事故。纸面上有三组假设:导航逻辑没处理好只在近岸出现的情况;某个传感器在港口环境下读数不同;连接中断导致系统切换了模式。
定位层的假设是有依据的。关于自主船舶的研究警告,当 GPS 失去信号、遭到干扰或欺骗时,船上无人值守,可能陷入危险境地。这正是记录中 gps_fix 字段如此重要的原因。
决定性的测试是回放。把录下的那份快照原样输入办公室机器上的导航栈。如果虚拟船像在海上一样偏离航向,缺陷就在逻辑里,你也有了一个可以对着修的测试用例。
如果回放结果完美无缺,就有两种可能。第一,你输入的数据和海上真实系统收到的不一样,这时要怀疑时序、硬件或网络。
第二,技术栈本身不确定:线程顺序、处理延迟或某个随机步骤,都可能让同样的输入产生不同的输出。
所以要多次回放,固定随机种子,使用模拟时钟。如果每次结果不同,先解决技术栈的确定性问题,再对硬件下任何结论。
结果按如下方式写进缺陷报告:
| 字段 | 航向误差案例的填写方式 |
|---|---|
| 现象 | 接近港口时,航向误差反复超过阈值 |
| 条件 | 时间、位置、GPS 状态、链路状态、软件版本 |
| 复现步骤 | 回放指定快照;记录运行次数及其中复现缺陷的次数 |
| 严重程度 | 是否影响运行安全 |
| 怀疑层 | 软件、硬件或网络,附回放得到的证据 |
| 纠正措施 | 修复方案,外加用这份快照构建的回归测试 |
很多人会跳过最后一行。触发缺陷的那份快照应当成为永久测试,下一次试验就不必再去海上追查老缺陷。
在真实环境之前主动触发失效
避免海上意外的最好办法,是在受控试验中自己制造失效。2013 年的一次海上试验中,GPS 被有意干扰,一套原型系统自动切换到了 eLoran。
那次测试针对的是导航系统而非自主船艇,但方法完全适用。
最近一次自主能力演示中,包括了对模拟机械故障的应急响应,同时岸上在远程监控这艘船。
这类测试只有在事先定好标准时才有价值。Saronic 围绕测试矩阵组织测试,每项需求都对应一个客观的通过/不通过标准。
“降级机制运行良好”只是一种印象。“GPS 丢失时切换到备用系统,偏差不超过允许值”才是可以检验的标准。
还有安全问题。在 Saronic,现场测试总监实时指挥试验并对其安全负责。想要主动触发失效,必须事先与这个人商定。任何人都不能擅自切断正在运行的系统。
常见错误
最常见的错误是只在自己熟悉的那一层调试。软件工程师埋头看代码,证据却指向天线或链路。这也是 FDE 岗位描述把软件、硬件和网络写在同一行的原因。
第二个错误是想把所有数据都通过慢速链路传回来,偏偏在最需要它的时候把它堵死。第三个是不保存快照就在现场修复,修复永远无法被证明正确。第四个是没有通过/不通过标准就开测,事后再争论结果算不算好。
缩短现场与代码之间的回路
Saronic 的测试规划人员每天与软件团队、船艇运营团队和供应商合作,推动每个问题尽快解决。好的缺陷报告能让这个回路转起来:办公室的人拿到快照和复现步骤,不用亲自去现场也能理解发生了什么。
职业方面,阅读 FDE 招聘信息时,留意“software, hardware, and networking”或“real-world environments”这类措辞:它们说明这个岗位需要现场调试。简历上别只写“处理过生产环境事故”。
讲一个具体缺陷的故事:你怎样录下数据,怎样复现,把它隔离到哪一层,又把它变成了什么回归测试。面试中,这样的故事远比一串工具清单更有说服力。
大海不会给你第二次机会。好工程师能把那唯一一次失效带回办公室,想重放多少次就重放多少次。
这篇文章对你有帮助吗?
感谢你的反馈!
6 个信源
- Senior Forward Deployed Engineer (Saronic Technologies)
- Autonomous Sea Trials Test Planner (Saronic Technologies) · 2026-06-04
- Saronic runs endurance trials on Corsair ASV for Navy program · 2026-02-04
- VR Teleoperation to support a GPS-free Positioning System in a Marine Environment · 2020-12
- Successful trial of automatic GPS backup · 2013-03-08
- 368-ton ex-US Navy vessel shows off advanced autonomy in high-stakes sea trials · 2026-10-19