Files
ros_contorl/devices/sensors/orisys
arm_dev 883ed6b0b9 P1:设备契约层收尾 + Flexiv 驱动适配器 + 触觉四路数据打通
新增包
- arm_kinematics:从 arm_application 提取几何雅可比 + DLS 逆解(纯 numpy)。
  它被应用层和驱动层共用,留在应用层会让驱动反向依赖应用层。
  arm_application/geom_ik.py 改为 re-export shim,现有 import 一行未改。
- arm_driver_flexiv:非夕驱动适配器。只补 manifest 声明而现有节点缺失的接口
  (/home /enable /clear_fault /switch_tool /soft_drag /compliant_descent),
  已有能力不重复实现。RDK 访问经 rdk_py310 下的长驻桥,本包不 import flexivrdk。

新接口
- arm_msgs/SwitchTool.srv、arm_msgs/CompliantDescent.action
- 合并 capabilities 里语义重复的 set_tool / switch_tool

修复(都是只在真机上暴露、且难以定位的问题)
- rdk_client 会永久挂死:select 的"可读"不等于"有完整一行",readline 遇到
  半行 JSON 会一直阻塞等换行符,超时机制完全失效。改用 os.read + 自己做行缓冲。
- CompliantDescent 行程少一步:descended + step > max 在浮点累加下会提前跳出,
  永远到不了标称行程。改用整数步数计数。
- CompliantDescentRunner 的 TF frame 退化成 _base_link:没继承节点已解析的 SN。
- resolve_orisys_config 仍指向旧路径;load_orisys_from_site 读的是旧键 config。

触觉四路数据打通
- 深度图 / 力矢量场原先被 tactile_worker 有意丢弃(注释写"图像不过队列"),
  从未发布到 ROS。新增 image_utils(数组→Image,编码自动判定)、独立的图像
  队列(maxsize=1 满则丢旧)与 /tactile/<side>/{image,vector}。
  默认关闭(tactile.image_hz=0),开启也不影响三力的 30fps 时序。
- mock 后端也会发图像,无硬件即可验证整条发布链路。

配置
- site.yaml 新增 tactile.image_hz;移除与 model 重复的旧键 tactile.config
- 型号配置从 src/arm_application/config/orisys/ 迁到
  devices/sensors/orisys/models/dd03/(随 SDK 一起放)

测试:198 个(原 139)
- arm_kinematics 24(雅可比/逆解的解析算例与不变量)
- arm_driver_flexiv 69(下压状态机 34 + RDK 协议层 35)
- arm_application 59(图像打包 36 + 矢量场探测 23)
2026-09-23 11:17:12 +08:00
..

devices/sensors/orisys/ —— Orisys 视触觉(框架核心)

这是整个框架的核心。 后续所有 ROS 2 项目都会围绕它开发,它也会持续迭代优化更新, 所以它单独占一个文件夹,不与其它传感器混放。

先搞清楚它输出什么

这是上层算法真正依赖的数据契约。注意单位与坐标系的定义,这是最容易出错的地方。

数据 维度 说明 框架内部话题
切向力 1 标量 任意单位(非牛顿),且基线会漂移 ~/tangential_1
切向力 2 标量 同上,另一正交方向 ~/tangential_2
法向力 标量 同上 ~/normal
深度图 图像 接触面深度 ~/depth
力矢量图 图像 接触点的力矢量可视化 ~/force_vector

两个必须记住的坑

1. 力是任意单位,不是牛顿。 现有 site.yaml 里所有力阈值(touch_delta、press_delta、 safe_press_delta 等)全部是「相对静止均值的增量」,不是绝对值。节点启动后会先自动测基线。 改阈值时改的也是增量,不是绝对读数。

2. 基线会漂移,所以阈值必须相对化。 写任何新的力判据时,不允许直接比较绝对读数。

3. 切向力的 X / Y 通道归属尚未确认。 通止规装配里「接触到面时某一路切向力突变」「拧紧判定时 某一路切向力超阈值」都需要知道是哪个通道。在确认之前,框架按两个切向通道都监控、任一满足即判定 来实现,避免猜错通道导致整段流程静默失效。确认后会把配置项收敛为指定通道。

厂商物料放置要求

项 要求
SDK 格式 厂商原始发布格式,不要转换、不要重新打包
SDK 命名 保持厂商原目录名与文件名,一律不要改名。SDK 内部常按自己包名做导入与资源查找
SDK 版本 在 manifest.yaml 的 version 记录,并写进 docs/CHANGELOG_ORISYS.md
型号配置 每个型号一份配置放 models/<型号名>/,不要混在一起
相机路径 必须用 /dev/v4l/by-path/ 稳定路径,不要写 /dev/video0 —— video 编号会随插拔漂移,这是现有框架已经踩过的坑
生效 放好 SDK → pip install -e 或加进 PYTHONPATH → 改 registry.yaml 选 orisys → 改 site.yaml 的 tactile.models.<型号> → 重启 scripts/run_tactile.sh

目录结构

sensors/orisys/
├── README.md                    # 本文件
├── manifest.yaml                # 型号清单 + 能力 + 配置项声明
├── sdk/                         # ★ 厂商 SDK 原样放置
│   └── README.md                #   放进来之后怎么让它生效(见下)
├── models/                      # ★ 多个传感器型号
│   ├── README.md
│   └── <型号名>/                #   每个型号一份配置
│       └── config.json
└── driver/                      # 适配器:统一成上面的数据契约

多型号怎么切换

传感器有多个型号,切换只改两处,不改任何代码:

  1. devices/registry.yaml → sensors: orisys(选厂商,通常不用改)
  2. config/site.yaml → tactile.model: "<型号名>",指向 models/<型号名>/config.json

型号之间的差异(通道数、内参、标定参数、拼接参数)全部由 models/<型号名>/ 承载。 上层只订阅统一话题,换型号不影响上层代码。

当前状态(迁移参考)

现有位置 内容 迁移去向
src/arm_application/arm_application/orisys_tactile.py SDK 适配 + 多进程 worker + load_orisys_from_site driver/
src/arm_application/arm_application/tactile_node.py ROS 节点,双指各一个进程 driver/
src/arm_application/arm_application/tactile_cli.py 读数量级 CLI(调试阈值用) 保留为调试工具
src/arm_application/arm_application/tactile_interface.py 数据类 driver/,其中的 MockTactile 类已死,P2 删除
src/arm_application/config/orisys/dd03.json 当前型号 dd03 的厂商配置 models/dd03/config.json

已解决的历史坑,迁移时必须保留这些做法:

  • 左右指各起一个独立进程,不要合并成一个进程双路并行 —— 会抢 CUDA 上下文互相拖慢。
  • tactile.cuda 保持 false,infer_backend 用 cpu。
  • 退出时残留的孤儿 worker 会占死 /dev/video,run_tactile.sh 里那段 pkill 清理必须保留。