Motrix Contact Sensor 适配笔记¶
背景¶
Sharpa Inhand Rotation 任务的触觉观测依赖 contact sensor 数据(指尖与物体的接触力)。该代码在 MuJoCo 后端下工作正常,但 Motrix 后端的 contact sensor 返回格式不同,读取路径需要同时兼容两种形状。
Contact Sensor 配置¶
指尖 contact sensor 定义在机器人场景 XML
src/unilab/assets/robots/sharpa_wave/right_sharpa_wave.xml 中:
<contact name="contact_right_thumb_elastomer_force" geom1="right_thumb_elastomer" geom2="object" num="1" data="force" reduce="netforce"/>
<!-- 每个指尖一个 sensor,参数相同 -->
参数说明:
num="1"— 最多报告 1 个接触点data="force"— 只返回力数据reduce="netforce"— 合成为单个接触点的合力,全局坐标系
两个后端的返回格式差异¶
MuJoCo¶
返回 (num_envs, 3) 的力向量,全局坐标系:
[[fx, fy, fz], # env 0
[fx, fy, fz], # env 1
...]
Motrix¶
返回 (num_envs, 1 + num * stride) 的扁平数组,首个元素为实际接触点数:
[[count, fx, fy, fz], # env 0, shape = (4,) 因为 num=1, stride=3
[count, fx, fy, fz], # env 1
...]
对于 reduce="netforce" + data="force" + num=1:
shape =
(num_envs, 4)[0]= 接触点数(0 或 1)[1:4]= 全局坐标系的合力向量(netforce模式使用全局坐标)
多接触点的通用格式(Motrix)¶
当 num=4, data="force pos normal tangent" 且无 reduce 时:
shape = (num_envs, 1 + 4 * 12) = (num_envs, 49)
[count,
f1_normal, f1_tangent0, f1_tangent1, # contact 1 force (contact 坐标系)
f1_x, f1_y, f1_z, # contact 1 position
f1_nx, f1_ny, f1_nz, # contact 1 normal
f1_tx, f1_ty, f1_tz, # contact 1 tangent
f2_normal, f2_tangent0, f2_tangent1, # contact 2 ...
...
padding_zeros] # 不足 num 个的用 0 填充
注意:无 reduce 时力是 contact 坐标系(法向标量 + 两个切向标量),不是全局 xyz 向量。只有 reduce="netforce" 返回全局坐标系的力向量。
Motrix reduce 模式参考¶
reduce 模式 |
坐标系 |
返回内容 |
|---|---|---|
|
全局 |
单个合成的合力向量 |
|
contact |
力最大的那个接触点 |
|
contact |
穿透最浅的那个接触点 |
无 |
contact |
前 |
其中只有 netforce 返回全局坐标系力向量,其他模式返回 contact 坐标系数据(法向标量 + 两个切向标量)。
单一 norm 分支为何不够¶
env 通过 src/unilab/envs/manipulation/sharpa_inhand/base.py 中的
_read_tactile_force() → _extract_sensor_scalar() 读取触觉力。该 helper 目前对任意 (N, >=3) 数组都用 np.linalg.norm(data[:, :3], axis=1) 折叠。
如果 env 仍把两种后端形状都走这一个分支,MuJoCo 的 (N, 3) 是正确的(对真实力向量取 norm),但 Motrix 的 (N, 4) 会出错:data[:, :3] 取到的是 [count, fx, fy]——把接触点数当成了力分量,并且漏掉了 fz。正确做法不是在 env 里按形状特判,而是把每个后端的布局知识下沉到 backend 方法。
建议的契约:用 backend 方法返回力大小¶
在 SimBackend 接口(src/unilab/base/backend/base.py)增加
get_contact_force_magnitude(sensor_name) -> np.ndarray,返回 (num_envs,) 的标量力大小。每个 backend 按自己的数据布局实现:
MuJoCo(
src/unilab/base/backend/mujoco/backend.py):对get_sensor_data(name)返回的 3D 力向量取范数。Motrix(
src/unilab/base/backend/motrix/backend.py):按 reduce 模式解释布局:reduce="netforce":取[1:4]后取 norm。无 reduce 多 contact:对各接触力求和后取 norm。
reduce="maxforce":取力最大的接触点。
env 层的 _read_tactile_force() 对 contact sensor 走 get_contact_force_magnitude() 路径,普通标量 sensor 仍走 _extract_sensor_scalar()。
这样 env 代码保持 backend 无关,并与高风险区的不变量一致:env 层只能调用 SimBackend 上已声明的方法——不向 env 泄漏后端功能,新增 backend 只需实现该接口方法。get_sensor_data 已是 SimBackend 上声明的方法,因此该提案是在同一边界上扩展,而不是伸手去调用 backend 子类。
相关文件¶
文件 |
说明 |
|---|---|
|
|
|
reward 计算,virtual torque |
|
contact sensor XML 定义 |
|
Motrix |
|
MuJoCo |
|
|