Files
ros_contorl/scripts/README.md
T
arm_dev bda2fa7129 通止规装配:配置段进 site.yaml + 中文手册 + 成败判定「不看 $?」
配置(site.yaml → gauge_assembly:,38 键全部带中文注释)
------------------------------------------------------
- 键名/单位/类型/交叉矛盾由 gauge_config.py 校验:拼错键名报错并给最相近的候选,
  单位后缀(_deg/_mm/_m/_s/_pct/_delta)逐条对表,`contact_safe_delta ≤
  contact_tangential_delta` 这类矛盾启动就拦(R1.2:没接线的键不许静默存在)。
- 借机清掉 4 个**没接线**的键(require_preview / track_*_s / hover_m:前两个是
  stage1 那层的、后两个是 servo 那层的,放在这里等于第二份真相),
  并把 contact_speed_m_s / coarse_timeout_s / 夹爪力速 真的接上。
- site.example.yaml 由 site.yaml 生成(gen_site_example.py --check 通过)。

成败判定:`ros2 launch` 的退出码**恒为 0**
------------------------------------------
实测(Humble):子进程 exit 3,`ros2 launch` 仍返回 0。用 `$?` 判成败的脚本会把
"装配失败"记成"成功"——没人会去查一个说成功的脚本。改成:

- 节点把结论**落盘**(--result-file,默认 /tmp/gauge_assembly_result.json,原子写、
  先落盘再发话题),任何"没跑到收尾"的退出也会补一份 ok=false;
- 脚本读结论文件判成败:0=成功、1=失败、**文件不存在也算失败**并说清;
- 新增 test_gauge_result_gate.py:把脚本里那段判成败的 Python 抽出来,
  对成功/失败/干跑/缺文件/坏 JSON 五种输入断言退出码 —— 判据本身也有测试。

顺带修掉两个"看着像玄学"的现象
------------------------------
- **流程打完了终端不回提示符**:launch 里的静态 TF 发布者是常驻的,主节点退出
  带不走它 —— 挂 OnProcessExit → Shutdown。
- **"已装 1/2 孔"**:结果里 hole_index 是 0 基当前孔号,不是"装完几个",
  新增 holes_done 给人和脚本看。

文档(全部中文,含"怎么调参/还没做")
------------------------------------
- 新增 docs/GAUGE_ASSEMBLY.md:状态机全图、每步判据表、E1 掉件处理(**按实现**:
  掉件后该孔作废、换下一个孔;最后一个孔掉件则序号被夹住=重试本孔)、
  话题契约、调参顺序、验收命令、踩过的坑。
- FRAMEWORK_RULES 新增 R5.8(同一份数学只许一份 + 守卫测试)、R5.9(自检的
  期望类型与调用处同源)、R5.10(缺依赖 skip,别留常年红)、R6.9(硬退出前打
  traceback)、R6.10(ros2 launch 退出码恒 0)+ R5.7 补真机/仿真"生效方式不同"
  (真机软链即改即生效,仿真拷贝必须重编)+ 5 条症状反例、.cursor/rules 同步。
- WORKSPACE / INTERFACES / SITE_CONFIG / HANDBOOK / 两份 README 索引与决策表补齐。

验证(本机真跑)
----------------
  pytest(仿真环境)  436 passed, 14 skipped(缺 onnx 跳过)
  干跑 --sim --dry-run  → 脚本退出码 0,结论 ok=true  已装 2/2 孔
  不干跑 --sim          → 脚本退出码 1,S00 拦住,未发任何运动指令

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 10:30:11 +08:00

70 lines
5.2 KiB
Markdown
Raw 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.
# scripts — 唯一操作入口
实现细节在 [docs/WORKSPACE.md](../docs/WORKSPACE.md) 和 [docs/](../docs/)。
**每天:** `run_real.sh` · `run_camera_d405.sh` · `run_visual_servo_rt.sh` · `go_home.sh`
**三阶段串联:** `run_all.sh --arm 89 [--hole k2] [--skip-stage1]`(`run_pipeline.sh` 是它的旧名别名)
**手眼:** `run_handeye.sh`(`teach` / `merge` / `calibrate` / `show`)
**夹爪:** `run_gripper.sh --arm 89|91` · `run_dual_gripper.sh`
**入孔:** `run_hole_detect.sh --arm … [--preview]`
**触觉:** `run_tactile.sh [--cli]`
**通止规装配:** `run_gauge_assembly.sh --arm 89 [--dry-run] [--holes N] [--backend …]`
- 一台状态机走完 S00–S11(自检 → 回 home/预绕 → 粗定位 → 跟踪 → 稳定拍照 →
悬停 → 柔顺接触 → 棘轮拧入 → 拧出 → 换孔 → 复位)。
- `--dry-run` **不发任何运动指令**,只验编排与自检 —— 改完配置先这么跑。
- 前置服务(臂 / 腕部相机 / 夹爪 / 触觉)要自己先起;缺哪项由 **S00 自检逐项报出**
并停住(不代你启动,也不"带病往下跑")。
- 掉件(E1):流程停在 home 等人,把规塞回爪里后发一次
`ros2 topic pub --once /gauge/reload_ok std_msgs/msg/Bool "{data: true}"`。
- 判据、调参顺序、还没做的部分:[docs/GAUGE_ASSEMBLY.md](../docs/GAUGE_ASSEMBLY.md)
**权重:** `weights.sh`(`list` / `labels` / `convert` / `doctor` / `show`)
- 转换:`weights.sh convert <文件> --name <模型名>` —— PT→ONNX→TensorRT,自动改名归位 + 固化标签
- 标签:`weights.sh labels <模型名>` 看,`--set "工件,通止规"` 改
- 体检:`weights.sh doctor --check-engines`(能查出 engine 与 TensorRT 版本不匹配这类静默失效)
- 规则写在 [models/README.md](../models/README.md)。`export_yolo_trt.sh` 现在是它的兼容转发壳。
**配置:** `show_site_config.sh` · `lib/export_site_env.py`
**仿真:** `run_sim_gz.sh`(Gazebo 物理仿真,唯一能做接触/力控验证的入口)
停:`stop_sim_gz.sh`(**别敲 `pkill -f gz`** —— 会杀掉调用它的 shell,见脚本文件头)
- 环境是独立 conda 环境 `ros_gz_sim`(`install_sim_env.sh` 装、`sim_env.sh` 激活),与真机环境隔离
- 相机验收:`python3 scripts/check_sim_cameras.py` —— **别用 `ros2 topic hz` 或肉眼看图验收相机**,
仿真相机的错误几乎全是静默的(深度单位、frame_id、内参、位姿方向),都能出图却是错的。
这条命令把深度反投影到 world,要求命中已知平面(地面/台面)才算通过。
- 场景验收:`python3 scripts/check_sim_scene.py` —— 同样别靠肉眼。它管四件事:
物体的摆放(悬空/穿模/出界/互相嵌入)、场景里的像素门槛与**真机生效值**是否漂移、
孔检测的成像几何(亮环/孔间距换算成像素后够不够门槛)、以及粗定位用的手外相机
能不能**完整**看见工件。第二条尤其重要:门槛抄了两份,不一致时仿真会"通过"而真机不认。
- 注意 `run_sim.sh` 不是 Gazebo,它走 mock 驱动(假数据 + RViz),永远不会产生接触力
**环境:** `env.sh` · `build_all.sh`
**RDK:** `test_rdk_python.sh` · `rdk_switch_tool.sh` · `rdk_drag_bridge.py`
**改注释/写文档后自检:** `python3 scripts/check_text_only.py`
- 用途:证明这次改动**只动了文字**(注释、docstring、提示信息),没碰逻辑。
它把改动前后的源码解析成语法树,删掉 docstring、抹平字符串常量后比对;
"翻译 f-string 时漏掉一个 `{}` 插值""顺手改了个变量名"这类问题会被抓出来。
- `python3 scripts/check_text_only.py` 查所有改过的 `.py`;也可以直接跟文件名。
基准是 `git HEAD`,所以要在**提交之前**跑。老手滑手滑的代价比跑一条命令高得多。
- 规矩写在 [docs/FRAMEWORK_RULES.md](../docs/FRAMEWORK_RULES.md) 的 R6.5。
一句话:**注释/docstring/提示信息用中文;标识符、话题名、字段名保留英文**
(但 `src/flexiv_*/` 是厂商上游代码,不许翻译,见 R4.4)。
**搁置未用:** `fetch_isaac_flexiv.sh`(拉 Flexiv 的 Isaac Sim / RDK 源码到 `thirdparty/`;Isaac 路线目前搁置,Gazebo 是选定平台)
`lib/parse_arm_args.sh` 解析 `--arm 89|91`。
`lib/load_site_config.sh` 把 `config/site.yaml` 变成 `SITE_*`。
## 排查脚本卡住时的常识
几个脚本开头会等外部条件(控制器 ACTIVE、相机出图、触觉就绪)。**正确的判活顺序是
先 `ros2 service list` / `ros2 topic list` 看目标在不在,再去 call / echo**:
```bash
# 对:服务不存在时立刻返回
timeout 3 ros2 service list | grep -q '^/controller_manager/list_controllers$' || exit 1
timeout 3 ros2 service call /controller_manager/list_controllers ...
# 错:服务不存在时每次 call 都要耗满超时才返回,
# 30 次循环 = 白等两三分钟(实测 63s),看起来就像脚本卡死了
for _i in $(seq 1 30); do timeout 5 ros2 service call ... ; done
```
`run_all.sh` / `run_stage2_locate.sh` / `run_stage3_search.sh` 已按正确顺序改过;
`run_handeye.sh` 一开始就是对的。