真机开工体检的编排:把「不报错但不对」的故障源排成现场能照着做的顺序

前一个提交给了四个单项判据(USB / V4L / RDK / 手眼)。这一批把它们的**判据入口**
补齐并编排成一条命令,产出「结论 + 要人工做的事」:

scripts/lib/real_preflight.py
  run_all() 按**现场该处理的顺序**排出结论,不是按代码顺序:
    现场配置 → 遗留进程 → 网络 → 机械臂 RDK → 腕部相机 → USB/触觉/几何
  顺序是有理由的:遗留的 ros2_control 占着 RDK,会让后面每一项的现象都指向别处,
  所以先查它;机械臂能不能动是唯一的人工硬阻断,排在相机之前。

  新增 check_cameras —— **本臂配置的那只腕部相机在不在 USB 上**。
  这是本次实测暴露的判据缺口:2026-09-28 现场 D405 整个从 lsusb 消失
  (只剩顶置 D435),而旧体检**全绿** —— check_usb 只看协商速率,遍历的是
  「发现到的」设备,对「这只根本不在了」无话可说。缺 D405 之后踩的是完全不同
  的一类错误(点云为空 / 找不到工件),排查方向会被带偏很远。
  按 site.yaml 的配置意图核对:robots[<sn>].camera.name → cameras.<name>.model,
  比**型号**而不是序列号 —— 实测这台 D435 的 sysfs serial 是空串,按序列号判会
  永远判「不在」;序列号只在型号对上时做一次「是不是本臂那只」的提醒(WARN)。

  修掉三处会误导现场的输出:
  · _run() 改成三返回值(分离 stdout/stderr,RDK 的 C++ 日志会混进 stdout)
    之后,_ps_output/网络两处还在按两返回值解包 —— 体检**第一步就崩**,
    什么结论都给不出来。现在有 test_run_all_completes_without_crashing 钉住。
  · 人工动作里「去查网线」出现过两条(check_network 与 rdk_status 各写一句
    意思相同、字面不同的话),去重是按整串文字做的,于是人读到两条、还得判断
    「这是一个问题还是两个」。措辞抽到 manual_actions.py,两边字面一致。
  · 触觉 wedged 的处置与 v4l_health 同步(免密的 reset 是首选,重插是兜底)。

scripts/lib/manual_actions.py(新)
  人工动作措辞的**唯一**来源。判据分在两个文件、还跑在两个不同的 Python 上
  (3.11 / 3.10,见 rdk_status 的模块说明),互相 import 不了,所以抽成只依赖
  标准库的公共模块。

scripts/run_real_preflight.sh(新)
  一条命令的入口:只读、不动臂,不需要机械臂能连上。

实测(2026-09-28,arm 89):体检跑通并给出 NO-GO + 7 条互不重复的人工动作,
新判据抓到「D405 不在 USB 上」(旧版全绿)。同时确认了本机可用的部分:
夹爪 PGEA 初始化完成 / 全开 20.00mm、右指触觉 SDK 300 帧 @29.9Hz、
手眼矩阵自洽、enp4s0 千兆全双工。

测试:test_real_preflight 28 项通过(含跨模块的措辞去重回归、
编排端到端冒烟、腕部相机四种情形)。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
arm_dev
2026-09-28 10:42:49 +08:00
parent 0fadd26ca2
commit 352270d1cc
5 changed files with 1311 additions and 4 deletions
+38
View File
@@ -0,0 +1,38 @@
#!/usr/bin/env python3
"""人工动作的**唯一措辞**来源 —— 让同一件事在体检报告里只出现一次。
为什么单独一个文件
------------------
体检报告最后会汇总"要人工做的事",而去重是**按整串文字**做的
(见 ``real_preflight.Report.manual_actions``)。同一件事如果两处各写一句
意思相同、字面不同的话,去重就形同虚设 —— 现场看到的是:
1. 机器人不在网里:确认网线接控制柜 User Port、PC 与臂同网段,
先跑 bash scripts/check_robot_network.sh(当前目标 192.168.2.101)
...
3. 确认网线接的是控制柜用户口、PC 与机器人同网段
(先跑 bash scripts/check_robot_network.sh)。
两条说的是同一件事,人却要读两遍、还会怀疑"是不是两个不同的问题"。
真正的根因(`check_network` 判据 + `rdk_status` 的状态分类)分在两个文件里、
还跑在两个不同的 Python 上(3.11 / 3.10,见 rdk_status 的模块说明),
互相 import 不了,所以把措辞抽到这里:只依赖标准库,谁都能 import。
改这里的文字等于改现场看到的操作步骤,动之前先想清楚。
"""
from __future__ import annotations
# 机器人不在网里(ping 不通)。措辞里**不带具体 IP** —— IP 已经在上面的
# 判据明细里打过了;带上 IP 就会让 check_network 和 rdk_status 的句子不一样,
# 去重立刻失效。
NET_UNREACHABLE_ACTION = (
"确认网线接的是控制柜用户口、PC 与机器人同网段"
"(先跑 bash scripts/check_robot_network.sh)。"
)
# 通了网也连不上 RDK 时的三种常见原因(与厂商报错 a) b) d) 对齐)。
RDK_REMOTE_MODE_ACTION = "确认示教器上已开启 Remote/Ethernet(RDK)。"
RDK_STACK_HOLDING_ACTION = (
"如果 ros2_control 已经在跑,RDK 可能被它占着 —— 先停掉栈再试。"
)