chore: 框架科学优化前的完整基线

在开始'设备契约层 + 目录重构 + 通止规装配'改造之前,先钉住当前可运行状态,
使后续任何删除/重构都可回退。

本基线包含:
- 现有 ROS 2 工作区全部源码(arm_application / arm_control / arm_bringup 等)
- 官方 flexiv_ros2 栈(含 flexiv_hardware / flexiv_controllers 等符号链接)
- 设备契约层 src/arm_interfaces(新增,46 项单测通过)
- devices/ 设备选型与品牌清单(新增)
- scripts/gen_site_example.py 与由它生成的 config/site.example.yaml

按 .gitignore 排除:build/ / install/ / log/ / config/site.yaml / 模型权重二进制。
This commit is contained in:
arm_dev
2026-09-23 10:53:06 +08:00
commit 6edb8d39ab
635 changed files with 1165230 additions and 0 deletions
+51
View File
@@ -0,0 +1,51 @@
# devices/cameras/ —— 相机
## 厂商物料放置要求
| 项 | 要求 |
|----|------|
| 格式 | 厂商 SDK / 驱动包原始格式。RealSense 用 `pyrealsense2` 或官方 ROS 2 包 |
| 命名 | 保持原样,不要改名 |
| 序列号 | **不要写在这里**。序列号在 `config/site.yaml` 的 `cameras.<名字>.serial` |
| 生效 | 放好物料 → 改 `registry.yaml` 选型 → 改 `site.yaml` 的 serial / 分辨率 / 曝光 → 重启对应相机脚本 |
## 目录结构
```
cameras/
├── README.md
├── realsense/ # Intel RealSense(当前在用)
│ ├── manifest.yaml
│ └── driver/
└── <新品牌>/
```
## 相机角色与命名(重要)
框架里每台相机必须有一个**角色**,因为不同角色参与完全不同的流程:
| 角色 | 当前相机 | 参与流程 | 是否参与手眼标定 |
|------|----------|----------|------------------|
| `wrist_eye_in_hand` | D405(左腕 / 右腕各一台) | 视觉跟踪 k0、拍照推理 k1/k2 | 是(眼在手上) |
| `overhead_eye_to_hand` | D435(双臂中间) | 粗定位兜底(S03) | 是(眼在手外) |
**注意**:D435 当前**还没有做手眼标定**,所以 S03 粗定位链路暂时不可用。
但这不影响 S04 跟踪链路,两条链路用的是同一套权重、同一个跟踪目标 k0。
## 已知的坑(迁移时必须保留的处理)
1. **USB 独占**:RealSense 同时只能被一个进程打开。启动前必须 `pkill` 掉旧进程,
现有脚本里那句 `sleep 2` 是必要的,不要删。
2. **USB2 vs USB3 会自动降分辨率**:现有脚本检测到 USB2 会降到 `640x480@15` 并告警,
这个降级逻辑要保留,否则会在弱链路上直接起不来。
3. **`run_camera_d435.sh` 曾把分辨率/曝光/emitter 硬编码**,与 `site.yaml` 的
`cameras.d435` 字段脱节。迁移后必须全部从 `site.yaml` 读,不允许硬编码。
## 当前状态(迁移参考)
| 现有位置 | 内容 | 迁移去向 |
|----------|------|----------|
| `src/arm_application/arm_application/realsense_color_pub.py` | 采集 + 发布彩图/对齐深度/红外 | `driver/` |
| `src/arm_application/arm_application/realsense_view.py` | 独立预览进程(与采集分离) | `driver/` 或 tools/ |
| `src/arm_application/arm_application/realsense_sdk_view.py` | Qt 四宫格窗口(被上面两者共用) | 保留 |
| `src/arm_application/arm_application/handeye_realsense.py` | 内参查询、话题解析、曝光设置 | 拆开:相机相关的进 `driver/`,标定相关的进 `handeye/` |
+141
View File
@@ -0,0 +1,141 @@
# =============================================================================
# devices/cameras/realsense/manifest.yaml
#
# Intel RealSense 相机驱动清单。覆盖两种型号:
# D405 —— 腕部相机,眼在手上,参与跟踪与手眼标定
# D435 —— 手外相机,顶视,参与粗定位兜底与手眼标定
#
# 这里【不放现场数值】。序列号 / 分辨率 / 曝光一律在 config/site.yaml。
# =============================================================================
id: realsense
label: Intel RealSense D405 / D435
kind: camera
vendor: intel
version: "pyrealsense2"
# 从哪里读出「当前用哪个型号」。值是 config_schema 里的 field key。
model_selector: model
description: >
RealSense 深度相机。D405 装在法兰/夹爪上做腕部视觉(眼在手上),
D435 架在双臂中间做顶视(眼在手外)。USB 独占,同一时刻只能一个进程打开。
# --- 厂商物料放置要求 ------------------------------------------------------
assets:
- path: driver
required: false
what: 厂商驱动(若使用 pyrealsense2 则无需放置,由 conda 环境提供)
format: 厂商原始格式
naming: 保持原样
where_used: driver 通过 pyrealsense2 或官方 ROS 2 包访问相机
# --- 适配器 ----------------------------------------------------------------
driver:
package: arm_driver_realsense
executable: realsense_publisher
build: colcon
# --- 能力声明 --------------------------------------------------------------
capabilities:
- color
- depth
- aligned_depth_to_color
- infrared_left
- infrared_right
- query_intrinsics # 手眼标定必需
- set_exposure
# --- 型号与角色 ------------------------------------------------------------
models:
- id: d405
label: D405 腕部相机
roles: [wrist_eye_in_hand]
default_resolution: "848x480"
default_fps: 30
notes: >
腕部使用,必须关闭红外投射器(emitter_enabled: false),
否则投射的红外点阵会污染跟踪图像。
- id: d435
label: D435 手外顶视相机
roles: [overhead_eye_to_hand]
default_resolution: "1280x720"
default_fps: 30
notes: >
手外使用,通常需要开启红外投射器以提升无纹理表面的深度质量。
当前尚未完成手眼标定。
# --- 配置项声明 ------------------------------------------------------------
config_schema:
- key: model
site_path: cameras[].model
type: str
required: true
doc: >
相机型号。必须与上面 models 列表里的某个 id 一致(d405 或 d435)。
型号决定默认分辨率与是否应开启红外投射器。
- key: serial
site_path: cameras[].serial
type: str
required: true
doc: >
相机序列号。用 scripts/list_realsense.sh 查看当前接入的全部序列号并映射角色。
每个角色必须是不同的序列号,否则两台相机抢同一台设备。
- key: role
site_path: cameras[].role
type: str
required: true
doc: >
相机角色,合法值: left_wrist | right_wrist | overhead_eye_to_hand。
以 _wrist 结尾表示装在法兰上(眼在手上,手眼标定用 eye_in_hand);
overhead_eye_to_hand 表示固定安装(眼在手外,手眼标定用 eye_to_hand)。
角色决定该相机参与哪条流程,所以必须与物理安装位置一致。
- key: width
site_path: cameras[].width
type: int
unit: px
required: true
doc: 彩色流宽度。注意 USB2 链路会自动降到 640 并告警。
- key: height
site_path: cameras[].height
type: int
unit: px
required: true
doc: 彩色流高度。注意 USB2 链路会自动降到 480 并告警。
- key: fps
site_path: cameras[].fps
type: int
unit: Hz
required: false
default: 30
doc: 帧率。
- key: auto_exposure
site_path: cameras[].auto_exposure
type: bool
required: false
default: true
doc: 自动曝光。
- key: ae_limit_us
site_path: cameras[].ae_limit_us
type: float
unit: us
required: false
doc: >
曝光上限。腕部 D405 建议限到 4000us 以内 —— 跟踪时曝光过长会导致运动拖影。
0 表示不封顶。
- key: emitter_enabled
site_path: cameras[].emitter_enabled
type: bool
required: true
doc: >
红外投射器。腕部必须 false(投射点阵污染跟踪图像),
手外通常 true(提升无纹理表面深度质量)。