P5c-4 相机出图联调:桥接 d405/d435 到 ROS,并修掉两处静默的几何错误

相机链路(devices/sim/gazebo/config/cameras.yaml 是唯一真相)
  - sim_cameras.py        纯逻辑:话题映射 / 深度换算 / 内参 / 视场一致性比对
  - sim_camera_adapter.py 改光学系 frame_id、32FC1 米 → 16UC1 毫米、覆盖内参
  - gazebo_sim.launch.py  桥接 + 适配器 + 世界相机的静态 TF(位姿从 world 解析)

本轮修掉两个**静默**的几何错误(都能出图、都能查到 TF,但点位是错的)

  1. gz 发的 camera_info 是错的:恒为 fx=fy=277, cx=160, cy=120
     (等于它的默认 60° 视场 + 半分辨率主点),而渲染用的是配置的 87° 视场。
     照抄它做三维反投影,点会偏半米量级;单目预览完全正常。
     用已知地面平面做最小二乘反解,得 fy=337.2 / cy=239.5,与
     640/(2·tan(87°/2))=337.2、480/2=240 吻合(残差中位 0.2mm)。
     改为由 sim_cameras.intrinsics() 按 cameras.yaml 的视场重算并覆盖。
     代价:cameras.yaml 的 horizontal_fov 必须与 SDF 一致,启动时自动比对告警。

  2. assembly.world 里 D435 的 rpy 写成 (0, 50°, 180°),
     而 URDF 相机的视线是**本体 X 轴**、rpy 复合顺序又是 Rz·Ry·Rx,
     于是"先俯 50° 再偏航 180°"把视线翻到了背面:相机背对台面、只看地面。
     它不报错,而且几何自洽(点确实落在真实地面上),只查数值发现不了。
     改为 (0, 50°, 0),并加回归测试锁住。

新增验收工具 + 测试
  - scripts/check_sim_cameras.py  反投影深度、要求命中地面/台面才算通过。
    "有图像"不是验收标准;实测 d435 台面 11.9%/地面 75.3%、d405 台面 37.8%。
  - 97 项单测(新增 sim_cameras 22 项、sim_site 16 项)

顺带修掉一处"改了配置静默无效"
  - sim.world 此前硬编码在 robot_description._WORLD_REL,而 site.yaml 与
    manifest.yaml 都宣称改它就生效。现在真的读了:
    优先级 --world > site.yaml:sim.world > 内置默认(相对路径按仓库根解析)。
  - physics_enable / joint_prefix 仍未接线,但若其值与实际状态冲突,
    启动时会告警(sim_site.unwired_warnings),不再静默忽略。

文档
  - devices/sim/gazebo/README.md 重写:原文还写着"仿真不是 Gazebo"、
    相机插件用 libgazebo_ros_camera.so,与实现早已不符。现分三部分:
    哪个"仿真"是真的 / 现状与缺什么 / 五条静默失效的坑及怎么验。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
arm_dev
2026-09-23 15:19:16 +08:00
parent f67f59f383
commit 47ad9d9a8b
17 changed files with 2690 additions and 101 deletions
+25 -4
View File
@@ -229,15 +229,36 @@
(早期把它挂在 URDF 的 world link 上,结果转 SDF 时整台相机消失 ——
sdformat 丢弃无质量根 link 时连带丢了整棵子树,且不报错。)
位姿:pitch≈50° 俯视,yaw=180° 让光轴转向机械臂一侧。
位姿:pitch=50° 俯视。**yaw 必须是 0**,原因见下面的坑。
⚠⚠ 实测踩到的坑(第四个"静默失效"):这里的 rpy 曾经写成
`0.0 0.872665 3.14159`(pitch 50° + yaw 180°),注释写的是
"yaw=180° 让光轴转向机械臂一侧"。但 rpy 的复合顺序是 Rz·Ry·Rx,
在 50° 俯角**之后**再做 180° 的 Z 旋转,会把视线从 "+X 斜向下"
翻成 "-X 斜向下" —— 也就是**背对台面**,只看得见地面。
而它不报任何错:话题有、图像有、深度有、TF 也对,
唯一症状是"相机拍不到该拍的东西"。用地面平面反投影验收时,
点是落在真实地面上的(几何自洽),所以只查数值根本发现不了。
正确理解:URDF 相机是"X 朝前"约定,**视线 = 本体 X 轴**,
Ry(50°) 已经把本体 X 从 (1,0,0) 转到 (cos50,0,-sin50),
正好是"朝 +X 俯视 50°",yaw 再转就过头了。
视野必须完整覆盖台面 —— 粗定位失败要回退到这个视角,看不全工件就等于
没有兜底方案。验收方法:
没有兜底方案。验收方法(**必须看命中率,不能只看"有图像"**):
ros2 topic hz /d435/color/image_raw # 有数
rqt_image_view /d435/color/image_raw # 工件三个孔都在画面内
python3 scripts/check_sim_cameras.py # 反投影必须命中 z=0.40 台面
后者会自动检查两台相机是否真的看到了该看的平面。
2026-09-23 实测基线(改位姿后请重测并更新,别凭印象):
台面四角投影到画面 u∈[172,468]、v∈[144,286](画面 640x480)→ 完整在视野内
通止规标记 → 像素 (180, 209)
台面像素占画面 11.9%,地面 75.3%
机械臂自身会遮住台面靠中偏下的一小块 —— 物理上必然,可接受;
但 P5c-6 放上工件后要用上面那条命令复核"工件是否完整可见"。
========================================================================= -->
<model name="d435">
<static>true</static>
<pose>-0.45 0.0 1.35 0.0 0.872665 3.14159</pose>
<pose>-0.45 0.0 1.35 0.0 0.872665 0.0</pose>
<link name="link">
<visual name="body">
<geometry><box><size>0.09 0.025 0.025</size></box></geometry>