47ad9d9a8b
相机链路(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>
devices/ —— 设备与外部文件总目录
这个目录存在的唯一目的:把「换个硬件」从改代码变成改配置。
设计原则(务必先读)
1. 选型与数值分离
| 关注点 | 放在哪 | 谁改 |
|---|---|---|
| 用哪个品牌的哪个驱动 | devices/registry.yaml |
集成工程师(很少改) |
| 设备号 / 速度 / 阈值 / 悬高 | config/site.yaml |
现场操作人员(经常改) |
devices/ 下不允许出现任何现场数值。 数值只有 config/site.yaml 一个来源。
这样可以避免现在这种「同一个值三处定义、改了不生效」的问题。
2. 目录约定
devices/
├── registry.yaml # 选型开关(唯一入口)
├── robots/ # 机械臂:RDK + 适配器
├── grippers/ # 夹爪
├── sensors/
│ └── orisys/ # ★ 视触觉核心,长期迭代,单独占一个大文件夹
├── cameras/ # 相机
└── sim/ # 仿真平台(当前 Gazebo)
每个品牌一个子目录,子目录内固定结构:
<类别>/<品牌>/
├── manifest.yaml # 我是谁 / 支持什么能力 / 需要哪些配置 / 外部文件放哪
├── driver/ # 适配器(把厂商 API 翻译成框架接口)
└── <厂商物料>/ # 如 rdk/、sdk/,原样放置,不要改名
3. 一个新品牌要接进来,只需要四步
- 丢物料:把厂商的 RDK / SDK / 驱动包放进
<类别>/<品牌>/下对应文件夹 (格式和命名要求写在该类别的README.md里,必须按它要求放)。 - 填 manifest:复制同类别的
manifest.yaml改四个字段(id / label / driver.package / config_schema)。 - 写适配器:在
driver/下实现框架的接口契约(见src/arm_interfaces/)。 这一步的工作量取决于厂商 —— 如果厂商本来就提供符合契约的 ROS 2 驱动,这一步几乎为零。 - 改一行选型:把
registry.yaml里对应类别的值改成新品牌 id。
诚实说明:第 3 步无法完全避免。Flexiv 的 RDK 是 C++/Python 库而不是 ROS 2 驱动, 所以它外面永远需要一层薄适配器。框架能做的是把这层适配器写到最薄(只做 API 翻译, 不含任何业务逻辑),而不是让你零代码接入。
4. 启动时的校验
框架启动会依次读 registry.yaml → 各 manifest.yaml → config/site.yaml,
校验三件事:
- 选中的品牌目录存在,且
manifest.yaml可解析; - manifest 里
assets声明的必需物料文件都在; config_schema里标记required: true的配置键,在site.yaml里都有值。
任何一项不满足立即报错并明确指出该去哪个文件补什么,不允许静默降级。
这是替代现在「run_handeye.sh 传了 5 个节点没声明的参数、调参静默失效」那类问题的机制。