Files
ros_contorl/scripts/run_real_preflight.sh
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

81 lines
3.3 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# 真机开工前的**一次性体检**(一条命令说清"能不能开工、不能的话人要去做什么")。
#
# bash ~/ros2/scripts/run_real_preflight.sh --arm 89
# bash ~/ros2/scripts/run_real_preflight.sh --arm 89 --json # 给脚本消费
# bash ~/ros2/scripts/run_real_preflight.sh --arm 89 --watch-usb 10
#
# 查什么(顺序就是现场该处理的顺序:根因在前,症状在后):
# 1. 现场配置:这一轮在读哪份 site.yaml、认哪台臂/哪台相机/哪个串口
# 2. 遗留进程:上一轮没退干净的栈会让这一轮的现象指向别处
# 3. 网络:机器人是否在网(含"两台臂 ARP 撞同一个 MAC"这个坑)
# 4. 机械臂 RDK:能不能使能(Manual 模式是**硬阻断**,只能人工在示教器上切)
# 5. USB:RealSense 协商速率 + Hub 是否在内核里卡死
# 6. 触觉 V4L2:设备在不在,是"没插"还是"卡死"
# 7. 几何:手眼矩阵是否自洽 + 悬停高度会不会把工具捅进工件
#
# 退出码:0 = 全绿(GO);1 = 有需要处理的项(NO-GO,看输出里"要人工做的事")。
#
# 为什么要有这个而不是让人挨个跑:这些故障**同时出现时现象会互相串**
#(Hub 卡死会让相机消失,相机消失又会让 S00 自检报"缺相机",
# 而真正拦住机械臂的其实是示教器模式)。分开查会让人先怀疑软件。
#
# 注意:这里**不加** `set -u` —— conda/RoboStack 的钩子会引用未绑定的变量。
set -eo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
WATCH_USB=0
JSON=false
# --sn/--arm 必须先解析:load_site_config.sh 靠 ROBOT_SN 决定选哪台臂
# shellcheck disable=SC1091
source "${ROOT}/scripts/lib/parse_arm_args.sh"
parse_arm_args "$@"
set -- "${PARSE_ARM_REST[@]}"
while [[ $# -gt 0 ]]; do
case "$1" in
--watch-usb) WATCH_USB="${2:?--watch-usb 需要秒数}"; shift 2 ;;
--json) JSON=true; shift ;;
-h|--help) sed -n '2,20p' "$0"; exit 0 ;;
*) echo "Unknown: $1" >&2; exit 1 ;;
esac
done
# shellcheck disable=SC1091
source "${ROOT}/scripts/env.sh" >/dev/null 2>&1 || true
# shellcheck disable=SC1091
source "${ROOT}/scripts/lib/load_site_config.sh"
# site.yaml 不存在时不要直接失败:网络与 RDK 自检在配置前就该能用,
# 而"配置没写"本身也是体检要报出来的一项。
if [[ "${SITE_LOAD_STATUS}" == "2" ]]; then
echo "ERROR: site.yaml 有问题,先按上面的提示修好再体检。" >&2
exit 2
fi
SN="${SITE_ROBOT_SN:-${ROBOT_SN:-}}"
if [[ -z "${SN}" ]]; then
echo "ERROR: 没选到机械臂。给命令加 --arm <臂号>,或在 site.yaml 里填 robot.sn。" >&2
exit 2
fi
echo "=== 真机开工体检 arm=${SITE_ROBOT_ARM:-?} ${SITE_ROBOT_LABEL:-} (${SN}) ==="
echo
ARGS=(--sn "${SN}" --site "${SITE_CONFIG:-${ROOT}/config/site.yaml}")
[[ -n "${SITE_NET_IFACE:-}" ]] && ARGS+=(--iface "${SITE_NET_IFACE}")
[[ "${JSON}" == true ]] && ARGS+=(--json)
RC=0
if [[ "${WATCH_USB}" != "0" ]]; then
# 先单独盯一会儿 USB:Hub 半死时会"设备在 / 不在"反复跳,
# 单次采样只会看到一个瞬间,看不出它在抖。
echo "--- USB 链路盯 ${WATCH_USB}s(看掉线/重连)---"
python3 "${ROOT}/scripts/lib/usb_health.py" --watch "${WATCH_USB}" || RC=$?
echo
fi
python3 "${ROOT}/scripts/lib/real_preflight.py" "${ARGS[@]}" || RC=$?
exit "${RC}"