让机器人安全失败:点云中断、TF 超时和控制器崩溃怎么测

机器人巡检仿真------从方法到可验收实现 · 07/10

定位:以真实电厂机器狗巡检项目为贯穿案例,提炼可迁移的机器人巡检仿真开发方法。

适合读者:机器人、自动化、计算机、电子信息等专业学生,以及准备进入 ROS 2、机器人软件、仿真、导航或测试方向的求职者。

上一篇:Gazebo 已经知道机器人在哪,为什么还要做定位融合?

下一篇:一个 90° 旋转如何搞坏整套导航:Gazebo 轮轴 Bug 完整复盘

机器人正朝巡检点前进,控制器突然退出了。导航程序不再发消息,机器人就一定会停下来吗?

这取决于后面的命令链如何处理旧指令。如果下游仍保存着最后一条非零速度,而系统又没有独立的超时保护,"没人再发命令"就可能变成"继续执行旧命令"。点云中断、关键坐标变换失联,也会让机器人在信息不足的情况下继续运动。

上一篇,我们讨论了定位结果如何可信。这一篇继续追问:当系统失去可信输入时,谁来阻止它继续行动?

本文给出故障实验的测量设计,并结合电厂机器狗的历史记录说明哪些结论有证据、哪些还需补齐。

一、先把"停车权"放到明确的位置

如果控制器、安全节点和测试工具都向同一个最终速度话题发布,零指令与非零指令就可能交错到达。不能指望安全节点"多发几次零"就一定压住其他发布者。

案例中把速度链串起来。机器狗保留四足外观,运动由隐藏的差速底盘代理;最终命令交给 Gazebo 差速驱动插件,并非四足步态控制器:

text 复制代码
controller_server
→ /cmd_vel_nav
→ collision_monitor
→ /cmd_vel_raw
→ safety_monitor
→ /cmd_vel
→ Gazebo 差速驱动

collision_monitor 根据启用的观测源和保护区域检查障碍物;safety_monitor 再检查命令是否过期、点云与关键 TF 是否持续到达,以及配置中的速度等约束。底盘接收的是经过这些环节处理的最终指令。

这个设计成立的前提,是控制器和其他命令源不能绕过安全门,直接给底盘发送速度。可以用下面的命令核对最终话题的发布者,再沿桥接与重映射检查实际接线:

bash 复制代码
ros2 topic info /cmd_vel --verbose

即使这样,监控节点自身退出时仍需要下游看门狗兜底。本文的 ROS 软件保护链也不能代替真实设备的驱动器保护或硬件急停。Nav2 官方同样明确,Collision Monitor 不提供硬实时安全认证。

二、命令过期、故障报警和停稳是三件事

先区分几个容易混用的概念:

  • 看门狗:持续检查某个被监控对象是否按预期更新。
  • 超时:超过预先设定的时间,没有等到符合条件的更新。
  • 命令过期清零:旧速度不能再被转发,输出改为零;不一定同时宣布任务故障。
  • 失效安全:系统检测到某类异常后,进入事先定义的受限行为,例如保持零速度。

当前案例启动配置中的部分参数如下。它们是配置值,不是本次实测停车时间:

检查项 配置值 作用
命令过期清零 0.5 s /cmd_vel_raw 长时间不更新时,停止转发旧命令
控制器命令超时 3.0 s 在附加条件满足时判定 CMD_VEL_TIMEOUT
点云更新超时 1.0 s 判定 POINTCLOUD_TIMEOUT
被监控 TF 更新超时 0.5 s 判定 TF_TIMEOUT
/clock 报文中断 0.3 s 进入 CLOCK_STALLED 安全保持

因此,不能把"控制器超时为 3 秒"解释为"机器人要等 3 秒才收到停车指令"。如果安全门输入先停止更新,0.5 秒的命令过期保护就可能先清零;如果碰撞监控仍在发零,底盘也可能更早收到零指令。究竟是谁先起作用,要看记录。

回到此案例:我们切断的是点云,不是命令。对应门限是表中的"点云更新超时",不能拿同为 0.5 秒的命令过期或 TF 门限解释它。多个保护可以同时存在,测试仍要辨认实际生效的环节。

监控循环的默认频率是 20 Hz,周期约 50 毫秒。这只能描述名义检查节奏;调度、通信、桥接与执行器响应都会影响实际延迟。参数越界被发现、最终话题输出零、机器人实际停稳,必须分别测量。

三、仿真暂停时,看门狗不能跟着"睡着"

假设超时判断和定时器都依赖仿真时间。当 /clock 不再推进,机器人世界停住了,检查"已经多久没有消息"的程序也可能不再运行。

案例为此使用两种时间:

用途 使用的时间
定时检查与消息接收间隔 稳定推进的单调时间
运动时间差、传感器数据与运动的对齐 仿真时间

监控定时器采用 STEADY_TIME,点云、TF 和命令回调记录 time.monotonic()。即便仿真时间停止,检查循环仍有机会发现报文中断并持续输出零速度。

前者负责在 ROS 中调度检查,后者是 Python 计算接收间隔的接口;它们都不依赖仿真时钟推进。这里不需要把两种 API 的绝对读数相减,也不能据此直接比较不同主机的时间值。

当 /clock 与传感器一起停发时,代码优先进入 CLOCK_STALLED,暂不把所有传感器都报成独立故障。这样可以把"整个仿真暂停或时钟链路中断"与"仅某个传感器失联"区分开。

不过,当前 /clock 看门狗检查的是报文接收间隔。如果报文持续到达,里面的时间值却一直不变,仅靠接收时间就不能识别这一异常。完整检查还应验证时间值是否推进、是否回退。这是现有保护的边界,不能因为诊断码叫"时钟停滞",就认为所有时间故障都已覆盖。

同样,代码中的加速度检查基于命令速度及仿真时间差,它不等于测得了机器人本体的物理加速度。

四、机器人为什么会把自己当成障碍物

开始之前前,还要先排除"点云本来就在触发停车"的情况。否则,暂停桥接后机器人仍不动,无法分辨是新的失联保护动作,还是原有误触发一直没有解除。

LiDAR 可能扫到机身、腿部或传感器支架。如果这些点进入碰撞保护区域,碰撞监控可能正确执行停止规则,却让机器人一直无法启动。

案例保留原始点云,另开一条供碰撞监控使用的过滤链:

text 复制代码
/sim/lidar/points
├─ 原始点云继续保留,供其他模块使用
└─ self_filter → /collision_monitor/points
               → collision_monitor

过滤器先把点坐标变换到 base_link,再根据配置的机体平面区域和高度范围删除自身回波。判定使用机体坐标,输出消息仍保留原始点云的坐标系与字段。

但扩大删除区域也会制造感知盲区。调参时应同时检查:自身点是否消失,紧邻机体的墙、设备和临时障碍物是否仍被保留,以及 TF 不可用时过滤器如何退化。当前实现有缓存外参及无缓存时直通原始点云的分支,不能仅凭"过滤器在运行"判断其结果正确。

还要检查 QoS。案例点云链使用 BEST_EFFORT;订阅端如果要求发布端无法满足的可靠性,就可能收不到数据。ROS 2 的 QoS 兼容规则决定端点能否通信,话题名相同不代表消息一定可达。

另一个容易忽略的问题是观测源是否真的启用 。仓库中的普通与融合导航配置,对碰撞监控点云源的启用值并不相同。查实际启动参数与有效配置,比看到配置文件里写着 FootprintStop 更有意义。

五、故障注入要一次只切断一条链

要验证点云中断,就只暂停承担点云桥接的进程,同时确认 /clock 与关键 TF 仍在更新。若把整个桥接进程树一起停掉,看到的可能是时钟故障,无法证明点云超时逻辑生效。

三类用例的实验条件可以这样设计:

故障 注入方式 同时确认
点云中断 对独立点云桥接进程发 SIGSTOP 时钟、TF 和测试采集器仍正常
关键 TF 中断 对对应 TF 桥接进程发 SIGSTOP 点云与时钟继续更新
控制器崩溃 终止独立控制器进程 自动重启关闭,其他节点仍存活

SIGSTOP 是暂停进程,SIGCONT 可以让其继续执行;终止控制器则用于模拟无法再正常发送收尾命令的退出。通过正常生命周期关闭节点,可能先发出停车指令,不能等价替代崩溃实验。

测试程序应自己启动并持有目标进程的准确 PID,记录进程身份与退出状态。按名称模糊匹配并终止进程,容易误伤其他运行。每轮还应使用独立的 ROS 通信域与 Gazebo 分区,避免外来的时钟或 TF 把失联故障掩盖掉。

注入前必须先确认机器人确实在运动,而且链路健康。机器人本来就没动时,"故障后速度为零"几乎没有证明力。

六、历史用例记录了什么,又没证明什么

先把案例中的已有记录连起来看。报告记载:对点云桥接进程执行了 SIGSTOP,观察到 POINTCLOUD_TIMEOUT、进入恢复状态以及最终 /cmd_vel 为零;执行 SIGCONT 后,点云重新发布,报告记录了恢复。

这条记录描述了"切断输入---保护动作---输入恢复"的过程。但注入前的准确初速、报警与零指令谁先出现、机器人何时真正停稳,都缺少足够的统一时间记录。因此,前面的"先确认运动和基线健康"是重做实验时必须落实的要求,不能倒过来当成这份旧记录已完整保存的事实。

其他两类用例可以与它并排比较。归档审计将这些测试关联到历史冻结版本 0a235a3:

用例 报告记录的故障码 报告记录的行为
TC-05:暂停点云桥接 POINTCLOUD_TIMEOUT 最终速度命令归零,恢复点云后退出故障流程
TC-08:暂停 TF 桥接 TF_TIMEOUT 最终速度命令归零,恢复后出现导航成功记录
TC-07:终止控制器 CMD_VEL_TIMEOUT 控制器未重启,最终速度命令归零,其他节点继续运行

这些记录支持"对应历史用例观察到了超时处理和命令清零",还不足以给出停车延迟的平均值、最坏值或稳定性保证。点云报告中的"首次停止约 0.6 秒"缺少足够时间基准说明,本文不把它当成检测延迟。

此外,当前仓库的 run_fault_tests.py 对这三类进程级注入保留了 PENDING 分支,原因是独立进程启动和 PID 跟踪尚未接好。历史报告存在,不代表现在执行该脚本就能复现一轮通过;本次也没有执行这些注入。

碰撞监控的记录同样需要谨慎解释:它记录过上游命令非零、下游命令被改为零,但还暴露了里程计与世界位置明显不一致。它可以作为命令拦截的证据,不能扩展成"已验证所有障碍物距离与无碰撞停车"。

七、怎样把"发了零"变成可验收的停车证据

如果重做此案例,需要分别捕捉四类事件:

text 复制代码
t_inject:故障确实发生
t_detect:监控发现异常
t_zero:最终命令进入持续零速
t_stop:机器人实际速度低于门限并保持

只有拿到可比较的内部检测时间,t_detect - t_inject 才能用于描述检测延迟;t_zero 与 t_stop 则分别关注命令响应与实际运动。四类事件不预设先后:命令过期保护可能先清零,故障码稍后才出现。

用一个采集器统一记录"观察时刻"

一种可实施的设计,是把注入控制与数据采集放在同一主机、同一测试进程中,用自身单调时钟记录:

记录项 采集方式
t_request / t_inject_confirmed 发信号前记录请求时间;查询准确 PID 的暂停或退出状态后,另记确认时间
t_fault_observed 订阅 /safety/status,第一次收到目标故障码时记录
零命令窗口 订阅最终 /cmd_vel,记录线、角速度均低于约定门限的窗口起点与确认时刻
停稳窗口 使用独立运动观测,记录实际线、角速度满足门限的窗口起点与确认时刻

这样可以比较 t_fault_observed - t_request 等采集器观察延迟。但第一次看到报警不等于节点内部检测时刻,发出信号也不等于故障立刻生效;请求与确认应一起保留。只有另行对齐内部事件时间,才能进一步拆分检测、通信与调度开销。

实际速度从哪里来

仿真中可以单独桥接机器人的世界位姿,用相邻位置差除以仿真采样时间差得到平面速度,并结合姿态变化检查转动;也可以接入独立测速来源。不要用期望速度代替真实运动,原地旋转也不能判为停稳。

采集器同时保存原消息时间戳与自身接收时间。位置差分窗口、坐标系、速度门限、保持时长及最大允许消息间隔都要写入记录。窗口内断流应标为未知,不能凭"没收到非零消息"认定持续为零。若把窗口确认时刻记作 t_stop,报告的响应时间就包含保持时长,应与窗口起点分别列出。

再从世界轨迹统计停车距离,记录初速与重复次数。接收时间统一,只解决观察记录的共同基准,并未消除桥接延迟。仿真暂停时世界本来就不推进,"位置没变"也不能证明物理制动能力。以上是补测方案,本次没有新增实测结果。

观察对象也要选对。当前速度诊断中的 final_lin 来自内部滤波变量,并非最终发布的 /cmd_vel 实测值。故障分支可以直接发布零 Twist,而该内部变量尚未变零。因此,测试应实际订阅最终话题,同时独立检查真实运动,不能只抄一个名字带 final 的字段。

八、恢复也是安全逻辑的一部分

故障后保持零速度,还要决定谁有权恢复运动。候选条件包括:输入重新连续有效、关键 TF 可用、控制器确实恢复、旧目标已处理、新命令属于当前任务。

案例有 FAULTED 与 RECOVERING 状态,在这些处理分支中持续发布零。当前启动入口打开了自动恢复,而导航 YAML 中另有参考配置;运行策略应以节点实际参数为准。

实际执行的报告记录了恢复,但回到 NORMAL 仍不等于恢复条件已经完整验证。当前实现还需针对以下问题补测:

  • 控制器是否真的恢复? 恢复函数未完整复核命令活性,传感器恢复不能代替控制器恢复。
  • 每条关键 TF 是否都健康? 多个被监控关系共用更新时间,一条更新可能掩盖另一条失联。
  • 活性是否来自控制器自身? 巡检状态也会刷新其活性时间,崩溃判定还有末次线速度等附加条件。

这些边界用例应分别验证,不能由一次停车成功推导出所有恢复场景可靠。

迁移到其他项目时,可以先带走这六个检查点:

  1. 最终命令来源明确,各种控制模式都经过安全仲裁。
  2. 旧命令有过期策略,安全节点自身失效有下游保护。
  3. 接收活性、数据时间戳和关键 TF 关系分别检查。
  4. 自过滤删除自身点,同时验证近处真实障碍物仍可见。
  5. 故障实验只切断目标链,并核对检测、零速、停稳与距离。
  6. 故障解除与恢复授权分开验证,避免旧指令或旧任务重新生效。

结语

机器人能够完成巡检,说明正常流程有了结果;当感知、坐标或控制失效时,系统如何收住动作,则决定了异常流程能否被解释和验证。

这套案例提供了明确的命令链、独立计时的活性检测和历史故障记录,也留下了进程注入自动化、逐项健康检查与物理停稳测量的补齐方向。可信的安全结论,需要从"代码里有保护"继续走到"故障确实发生、保护确实动作、机器人行为符合门限"。

相关推荐
小道士写程序2 小时前
Git 大文件问题解决办法
git
黑泽明Coding2 小时前
如何重置git分支,清空分支所有提交历史
git
小堃学编程3 小时前
Git远程开发操作指南
git
持敬chijing3 小时前
白盒测试与代码审计-JS 数据逆向
javascript·网络·安全·web安全·网络安全·网络攻击模型·安全威胁分析
啥都鼓捣的小yao3 小时前
机器人领域的基础模型:应用、挑战与未来
人工智能·机器人
于眠牧北4 小时前
雷电模拟器9/14搭配charles抓取自带浏览器接口9/14
经验分享·笔记·git
硅谷秋水12 小时前
面向机器人的上下文学习:方法与应用
深度学习·机器学习·语言模型·机器人
FairGuard手游加固13 小时前
手游加固怎么做?SO、IL2CPP、AssetBundle 与运行时保护详解
安全·游戏·unity