Commit Graph

3 Commits

Author SHA1 Message Date
arm_dev baf7601995 预检补上 arm_control 孤儿与 mock 的 joint_state_publisher
上一轮残留的那四条孤儿(real_trajectory_adapter / named_pose_server /
arm_status_node / joint_state_publisher)在预检里**一条都报不出来**:
老的六条模式只覆盖 ros2_control_node 和 stack.launch,而它们的特征恰恰是
"栈的主体已经没了、只剩它们",所以两条老模式全都匹配不到。

补两条:
  · `install/arm_control/lib/arm_control/` —— 一次覆盖该包全部节点
    (用 install/ 而不是 install_sim/:仿真同名节点不该被真机体检误报,
    "install_sim/" 不含子串 "install/",这条性质用测试钉住了);
  · `joint_state_publisher` —— mock 专用节点,真机上出现 = 上一轮 mock 栈的
    残留。它发的**静态** /joint_states 会盖掉真实关节角,是"控制器一切正常、
    TF 显示臂没动"这个假象的元凶,所以说明里把它写清楚。

人工动作也改成先指向新的 stop_real.sh(它真能带走这些孤儿),保留手动 pkill 兜底。
新增 3 项单测(含"不许误报 install_sim/"的负向用例)。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-28 12:25:20 +08:00
arm_dev bb6f792922 复位命令必须带 timeout:实测它自己会永久挂住,还留下占着 USB 的僵尸进程
上一版把触觉 wedged 的处置改成「首选 `sudo -n orisys-usb-reset`(免密,无人值守
可直接跑)」。真跑了一次,发现这句话是错的:

    sudo -n /usr/local/bin/orisys-usb-reset 1-3.4.1

跑了 **155s 都没返回**,进程停在 `S` 状态(卡在写
`/sys/bus/usb/drivers/usb/unbind`),`timeout 90` 都收不掉它 —— 现场留下了三个
残留进程。对无人值守来说这是最坏的结果:那一轮在这里永久卡死,而且这个进程还
占着 USB,后面重试触觉只会继续失败。

复位之后 `1-3.4.1` 直接从 sysfs **消失**了(复位前它还在总线上、只是没有
/dev/video*)—— 也就是设备比复位前掉得更彻底。所以这条命令**不是**"跑一下试试"
那种安全操作,必须当有副作用的操作对待。

改动:
· 两处给现场的命令一律写成 `timeout 15 sudo -n /usr/local/bin/orisys-usb-reset
  <devpath>`,并把「不加 timeout 会永久卡住 + 留僵尸进程」写进提示原文。
  这与 `orisys_tactile.py` 的自动自愈口径一致(那里本来就是 `timeout=15.0`,
  所以自动路径不受影响,只有手工执行的建议是错的)。
· 复位后设备仍不在总线上(或消失)→ 明确归到**物理**处置:拔插该相机 /
  给这个 Hub 断电重启。

测试:test_v4l_health 新增两条 —— 断言给出的复位命令里含 `timeout 15`,
以及提示里必须写出"会挂住"这件事(只给命令不说风险,人就会裸跑它)。
全仓库 1119 passed / 1 skipped。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-28 10:46:06 +08:00
arm_dev 352270d1cc 真机开工体检的编排:把「不报错但不对」的故障源排成现场能照着做的顺序
前一个提交给了四个单项判据(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>
2026-09-28 10:42:49 +08:00