P5c-6 场景物料落地 + Gazebo 中文手册:工件/通止规模型、场景校验、两处静默失效修复

一、场景物料(新增)
  devices/sim/gazebo/models/workpiece/   带三个孔的铝板。碰撞体是"带方孔的平板",
    视觉额外加两个 φ14/φ7 亮环 —— 因为真机的 HoughCircles 就是靠这两个亮环找孔,
    只按碰撞体建视觉会让"孔检测"在仿真里永远失败,而那看起来像算法问题。
  devices/sim/gazebo/models/gauge/       通止规:通端/套环/握柄/止端四段,各段异色
    便于肉眼判断方向。接触刚度刻意比台面软 —— 位置控制器会"刚性压进去",
    用默认刚度会被弹飞(注释里写了原因,不是随手抄的参数)。
  devices/sim/gazebo/models/gauge_stand/ 规座(static)。规直接站在台面上会立刻倒,
    加个方孔底座把它立住。
  三个模型都是 model.sdf + model.config,原点在**底面中心**,单位米。

二、场景配置与校验(新增)
  config/scene.yaml     物体不再写死在 world 里,改为 scene.yaml + 启动时动态 spawn。
    理由:world 是"环境"(地面/台面/相机/系统插件),场景是"这一批活做什么"。
    动 world 的风险面太大 —— 它只要丢一个系统声明,所有模型都 spawn 不进去(见旧坑 2)。
    含 operating(相机到工件的距离等作业条件)与 gates_px(像素门槛)。
  sim_scene.py          摆放校验:从 SDF **逐碰撞体**解析 AABB(不抄尺寸,避免漂移),
    检查原点在底面 / 不穿台面 / 不出界 / 物体之间不嵌入。
    重叠判定必须逐碰撞体三维判,不能拿总包围盒相交 ——
    正常装配里本来就有嵌套(规立在规座方孔里),粗判会误报,
    而误报的后果是人把检查整个关掉,之后真重叠也抓不到。
    另有成像几何:把亮环/孔间距按相机距离换算成像素,与门槛比对。
  scripts/check_sim_scene.py  验收工具(退出码可用):摆放 + 门槛漂移 + 成像几何 +
    悬停高度 vs 工作空间 + 手外相机是否**完整**看得见工件 + Gazebo 实际位姿。

三、修掉两处静默失效(都是"看起来一切正常")
  1) parse_spawned_poses 一直是**死代码**:它按 "x: N / y: N / z: N" 解析,
     而 Fortress 实际输出是方括号两行(XYZ / RPY)。对不上 → 永远返回空 →
     调用方按设计"降级成跳过位姿核对" → 位姿检查**从来没跑过**,
     而日志只说"跳过",看起来像正常降级。
     现在两种格式都支持,并用真实抓下来的输出样本做回归测试。
     教训:宽容降级会把"没检查"伪装成"检查通过"。
  2) stop_sim_gz.sh 的模式表里漏了 robot_state_publisher(而注释里写着它有覆盖):
     脚本报"已停止",它却还在发上一份 /robot_description 与 TF,
     下一次启动就会"改了描述却不生效"。
     顺带修掉同源的两个问题:awk 用 -v 传模式导致它匹配到自己、每次复查都多报
     一个空命令行的幽灵 PID;以及"杀的时候"和"复查的时候"两份扫描实现会各自漂移。
     现在共用同一个 scan_pids(),模式改用环境变量传递,并在杀完之后**再扫一遍**:
     有残留就报出来并非零退出 —— 下次再有漏项,不再静默。
     实测:--list 列出全套 9 个进程;停止后 rc=0 且 pgrep 干净。

四、相机:D405 分辨率对齐真机
  仿真的 D405 此前渲染 640x480,而真机跑 848x480(fx 337 而非 447)。后果是
  58mm 的两孔间距成像只剩 85px,低于 hole_distance_min=90 ——
  孔检测在仿真里根本不可能通过,而现象看起来像"算法不行"。
  已把 xacro 与 cameras.yaml 一起改成 848x480,并把启动时的比对从"只比视场"
  扩成"视场 + 图幅"(sim_cameras.check_camera_consistency),
  不一致时说明它对像素门槛的影响。

五、文档
  devices/sim/gazebo/README.md 重写为中文手册:使用方法 / 建模要求 / 导入格式 /
    配置方式(含"改哪里才真的生效"的接线表)/ 11 条实测坑(每条都有"怎么发现")。
  manifest.yaml 的进度、assets、description、坑清单与本轮状态对齐。
  scripts/README.md 补两个验收工具与停止脚本;根 README 补仿真入口与手册链接。
  cameras.yaml 里一处过期的函数名(check_fov_consistency)修正。

六、测试
  新增 test_sim_scene.py(79 条,此前 sim_scene.py 完全没有单测 —— 这正是
    位姿解析死掉却无人发现的原因)与 test_check_sim_scene.py(21 条),
  含三条回归:world_boxes 的偏移碰撞体不能被对称化放大(假重叠)、
  center_bore 不能被 _bore 后缀吃掉、Fortress 位姿输出格式。
  全量:src/arm_sim_gazebo + arm_interfaces + arm_application 共 515 通过。

同时附上 config/site.example.yaml 的重新生成(此前 site.yaml 的注释改动没同步,
它的 parity 测试是红的)。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
arm_dev
2026-09-23 17:13:00 +08:00
parent 01315773e7
commit d32e6ae53f
23 changed files with 4489 additions and 181 deletions
+9 -4
View File
@@ -111,11 +111,15 @@ paths:
# bash ~/ros2/scripts/export_yolo_trt.sh /home/USER/ros2/models/yolo/detect_best_0.onnx 640
# 4) yolo.imgsz 必须等于 ONNX 输入边长(当前 640)
# 5) 改权重/imgsz 后重启:bash ~/ros2/scripts/run_visual_servo_rt.sh [--control]
# 6) 换完确认标签没丢:bash ~/ros2/scripts/weights.sh doctor --check-engines
# 当前:detect_best_0.onnx(2026-09-04 从 ~/下载 移入,640 输入)
yolo_weights: "/home/USER/ros2/models/yolo/detect_best_0.onnx"
# 备选模型:直接换成 models/yolo/ 下的其他 .onnx / .pt 绝对路径即可。
# 换完建议确认标签没丢:bash ~/ros2/scripts/weights.sh doctor --check-engines
# 入孔 YOLO(backend=yolo 时把孔当框)。two_stage 用上面的工件权重。
# 换模型:把 models/yolo/ 下别的 .onnx / .pt 绝对路径填进来即可。
# 未在用的模型已移出仓库(体积大且干扰 `weights.sh list`),要恢复见 models/README.md。
# 入孔 YOLO(backend=yolo 时把孔当框)。two_stage 用下面的工件权重。
# 原先指向 hole_insert/best.pt —— 那个文件不存在(悬空引用)。这里改成实际存在的
# detect_best_1.onnx,这样 backend: yolo 至少是能跑的。查悬空引用:
# bash ~/ros2/scripts/weights.sh doctor
hole_weights: "/home/USER/ros2/models/hole_insert/detect_best_1.onnx"
# 下面是缺省(未匹配到 robots[] 时)。真机以 robots[].paths 为准:89 / 91 各一份。
handeye_file: "/home/USER/ros2/handeye/results/89_eye_in_hand.yaml"
@@ -339,6 +343,7 @@ gripper:
# bash ~/ros2/scripts/run_hole_detect.sh --arm 89 --preview
hole_detect:
backend: "two_stage" # two_stage | yolo | hough
# backend=yolo 时用。原为 hole_insert/best.pt(文件不存在),已改为实际存在的模型。
weights: "/home/USER/ros2/models/hole_insert/detect_best_1.onnx"
# 二阶段工件检测权重(YOLO 先框出工件,再 Hough 找 k1/k2 螺纹孔)
workpiece_weights: "/home/USER/ros2/models/hole_insert/detect_best_1.onnx"
@@ -491,7 +496,7 @@ sim:
# 决定,且 config/controllers.yaml 里硬编码了 sim_joint1..7。
# 写了个不同的值会告警。要真改,三处必须一起改。
#
# 另外注意:`run_sim.sh` 走的是 mock 驱动(假数据 + RViz),**不是**物理仿真;
# 另外注意:`run_sim.sh` 走的仍是 mock 驱动(假数据 + RViz),不是物理仿真;
# 物理仿真入口是 `scripts/run_sim_gz.sh`(Gazebo)。两者互不影响。
platform: "gazebo"
world: "devices/sim/gazebo/worlds/assembly.world"