bda2fa7129
配置(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>
70 lines
5.2 KiB
Markdown
70 lines
5.2 KiB
Markdown
# 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` 一开始就是对的。
|