触觉传感器#

触觉传感器把连杆表面变成网格状的感知点,即 taxel(触觉单元),并直接从场景的有符号距离场(SDF)或采样的点云读取接触几何,而不是从求解器的接触冲量中获取。它们能在任意位置给出密集的 taxel 场,而不向求解器添加接触,代价是结果为近似值。由于布局是连杆局部的,规则网格可以模拟指尖或传感垫上的 taxel 阵列。

用 probe_local_pos 描述一次布局即可,它是一组连杆局部坐标系中的 (x, y, z) 偏移((N, 3) 集合或 (M, N, 3) 平面网格),探针会随连杆刚性移动。对于平面网格,genesis.utils.geom.generate_grid_points_on_plane(lo, hi, normal, nx, ny) 返回一个 (ny, nx, 3) 数组;n_probes 是展平后的探针数量。

两个系列共用这套接口,但以不同方式估计接触:

  • SDF 查询探针(ContactProbe、ContactDepthProbe 和 KinematicTaxel)直接查询每个探针到附近碰撞几何的有符号距离。它们不需要目标连杆列表,不过可选的 filter_link_idx(全局连杆索引)可以把指定的对应连杆排除在查询之外。

  • 点云探针(ElastomerTaxel 和 ProximityTaxel)从 track_link_idx(全局连杆索引)指定的网格中采样点云,并相对这些点进行测量。n_sample_points 设置采样预算。

读数是几何估计而非求解器冲量,并且未经过标定。除非你针对自己的装置调整系数,否则应把它们当作相对信号。taxel 还提供硬件风格的误差,因此你可以针对真实传感器产生的噪声训练策略。关于传感器如何采样、回读和批处理,请参阅 传感器总览。

Note

这些触觉传感器在 Tactile Genesis: Exploring Tactile Sensors at Scale for Learning Dexterous Tasks 中提出。 Genesis World 的实现行为可能与论文报告有所不同。 不过,如果你在研究中使用了它们,请引用:

@article{chung2026tactilegenesis,
  title   = {Tactile Genesis: Exploring Tactile Sensors at Scale for Learning Dexterous Tasks},
  author  = {Chung, Trinity and Yamazaki, Kashu and Patel, Dhruv and Duburcq, Alexis and Qiao, Yiling and Fragkiadaki, Katerina and Nayebi, Aran},
  journal = {arXiv preprint},
  year    = {2026},
  url     = {https://arxiv.org/abs/2606.22332}
}

选择传感器#

传感器

read() 返回值

形状

坐标系 / 单位

ContactProbe

每个探针的接触标志

([n_envs,] n_probes)

bool

ContactDepthProbe

每个探针的穿透深度

([n_envs,] n_probes)

m

KinematicTaxel

每个探针的 (force, torque)

各自 ([n_envs,] n_probes, 3)

连杆局部坐标系,N / N·m

ElastomerTaxel

每个探针的标记点位移

([n_envs,] n_probes, 3)

连杆局部坐标系,m

ProximityTaxel

每个探针的 (force, torque)

各自 ([n_envs,] n_probes, 3)

连杆局部坐标系,N / N·m

两个交互式演示驱动这些传感器:

  • examples/sensors/tactile_franka.py 为 Franka 的两个指尖都装上传感器,并允许你遥操作一次抓取(--sensor {depth,kinematic,elastomer,proximity})。

  • examples/sensors/tactile_sandbox.py 在四个并行环境中把可控物体压入一个固定的 taxel 垫(盒形或穹顶形)(--sensor {contact,depth,kinematic,elastomer,proximity}),用 --contact-depth-query {sdf,raycast} 选择深度后端,并用 --noise 启用下文的误差。

接触深度与接触探针#

最简单的探针只报告几何信息。ContactDepthProbe 以米为单位返回每个探针处的穿透深度;ContactProbe 则对该深度做阈值判断,输出每个探针的布尔值。

depth_probe = scene.add_sensor(
    gs.sensors.ContactDepthProbe(
        entity_idx=franka.idx,
        link_idx_local=franka.get_link("left_finger").idx_local,
        probe_local_pos=probe_local_pos.reshape(-1, 3),
        probe_radius=0.002,
    )
)

depth = depth_probe.read()  # shape ([n_envs,] n_probes), m

probe_radius 是 taxel 的感知半径,而不是容差:每个读数为 depth = max(0, probe_radius - signed_distance_to_surface),因此半径越大,探测范围越广,同时也会给报告的深度加上一个恒定偏移。SDF 查询探针通过 contact_depth_query 选择接触深度后端:"sdf"(默认)查询每个几何体的解析 SDF 网格,而 "raycast" 遍历刚体求解器的碰撞网格 BVH,取到最近三角形的有符号距离(与 RaycasterSensor 共用该 BVH)。该模式是类级别的:同一个类的所有传感器必须一致。

ContactProbe 用施密特触发器对其布尔输出做门控以抑制颤振:当深度达到 contact_threshold(默认 1e-4 m)时置位,当深度回落到 release_threshold(默认等于 contact_threshold,即无迟滞;可以为负,以要求先分离再释放)时复位。

运动学 taxel#

KinematicTaxel 在深度查询之上增加了弹簧-阻尼力模型。对于每个 taxel,它根据沿接触表面法线的穿透量估计力,并根据扭转估计力矩,使用的是探针相对其所接触物体的运动:

s = penetration ** normal_exponent
F = normal_stiffness * s * n  +  normal_damping * s * v_n  -  shear_scalar * v_t

其中 n 是探针处的接触表面法线:在 "sdf" 模式下是 SDF 梯度,在 "raycast" 模式下是最近三角形的面法线(见上文的 contact_depth_query)。v_n / v_t 是法向和切向相对速度。KinematicTaxel 从查询到的几何本身推导 n,而下文的点云 taxel 则把 probe_local_normal 作为表面法线。赫兹(球面)接触请使用 normal_exponent=1.5;默认的 1.0 是线性弹簧。

taxel = scene.add_sensor(
    gs.sensors.KinematicTaxel(
        entity_idx=franka.idx,
        link_idx_local=franka.get_link("left_finger").idx_local,
        probe_local_pos=probe_local_pos.reshape(-1, 3),
        probe_radius=0.002,
        normal_stiffness=5000.0,
        normal_exponent=1.5,
    )
)

data = taxel.read()
data.force   # shape ([n_envs,] n_probes, 3), N, link-local
data.torque  # shape ([n_envs,] n_probes, 3), N*m, link-local

read() 返回 KinematicTaxelReturnType 命名元组,因此 data.force 和 data.torque 可以按名字解包。

弹性体 taxel#

ElastomerTaxel 在不仿真形变的情况下建模柔性触觉皮肤。每个探针报告由局部压入和相对被跟踪几何的剪切造成的三维标记点位移,采用 HydroShear 风格模型计算。当你需要基于视觉的触觉传感器那种直观的“点位移”信号时使用它。

tactile = scene.add_sensor(
    gs.sensors.ElastomerTaxel(
        entity_idx=franka.idx,
        link_idx_local=franka.get_link("left_finger").idx_local,
        probe_local_pos=probe_local_pos,  # (ny, nx, 3) grid, or (N, 3)
        probe_local_normal=(0.0, -1.0, 0.0),
        probe_radius=0.002,
        track_link_idx=(cube.base_link_idx,),  # global link idx to sense against
        dilate_scale=10.0,   # gain on normal indentation
        shear_scale=100.0,   # gain on tangential slip
    )
)

displacement = tactile.read()  # shape ([n_envs,] n_probes, 3), m, link-local

dilate_scale 和 shear_scale 缩放压入与剪切的响应;lambda_d 和 lambda_s 控制每种效应在相邻标记点之间扩散的范围。面外(法向)凸起按 depth ** normal_exponent 缩放(默认 2.0,即 HydroShear 的二次响应);无论 normal_exponent 取何值,切向膨胀和剪切对深度都保持线性。当 probe_local_pos 是具有单一共享法线的规则平面网格时,Genesis World 会用 FFT 计算膨胀项,以保持大数组的计算速度。剪切锚点由同一套 contact_threshold / release_threshold 施密特触发器门控(被跟踪点在穿透达到 contact_threshold 时开始锚定剪切,一旦分离回到 release_threshold 就释放)。

邻近 taxel#

ProximityTaxel 从被跟踪网格上采样的点云估计每个 taxel 的力和力矩,范围是每个 taxel 周围半径为 probe_radius 的球形感知体积。它在硬接触之前就能读取,因此既能捕捉接近,也能捕捉接触。

proximity = scene.add_sensor(
    gs.sensors.ProximityTaxel(
        entity_idx=pad.idx,
        link_idx_local=0,
        probe_local_pos=probe_local_pos.reshape(-1, 3),
        probe_local_normal=(0.0, 0.0, 1.0),
        probe_radius=0.008,
        track_link_idx=(obj.base_link_idx,),
        n_sample_points=4000,
        stiffness=200.0,
        shear_coupling=100.0,  # 0.0 disables shear, leaving only the normal channel
    )
)

data = proximity.read()
data.force   # shape ([n_envs,] n_probes, 3), N, link-local
data.torque  # shape ([n_envs,] n_probes, 3), N*m, link-local

与 KinematicTaxel 一样,它返回带 force 和 torque 字段的命名元组(ProximityTaxelReturnType)。

传感器误差#

除了通用的逐传感器误差(noise、bias、resolution、delay、jitter,每个传感器都有)之外,触觉探针和 taxel 传感器还提供硬件风格的误差。它们只作用于测量分支:read() 返回带误差的信号,而 read_ground_truth() 保持干净。

选项

建模内容

适用范围

hysteresis_strength, hysteresis_tau

粘弹性(单 Maxwell)迟滞:阶跃输入会超调 hysteresis_strength,并以时间常数 hysteresis_tau 秒松弛;循环输入会描出一条加载-卸载回线(平衡增益为 1)。

所有探针和 taxel

probe_gain, probe_gain_resample_range

对测得的接触深度施加逐 taxel 的乘性增益(标量或逐 taxel 数组);给定范围时,在每次 scene.reset() 时按均匀分布重新采样。

所有探针和 taxel

dead_taxel_probability, dead_taxel_value_range

每次 scene.reset() 时,每个 taxel 以伯努利概率失效;失效 taxel 的输出会被替换为从 dead_taxel_value_range 中抽取的常数。

所有探针和 taxel

crosstalk_strength, crosstalk_sigma

高斯空间串扰:每个 taxel 的力/力矩会渗漏到其网格邻居上(crosstalk_strength=1 即宽度为 crosstalk_sigma 的纯高斯模糊)。

网格 taxel:KinematicTaxel、ProximityTaxel

crosstalk_kernel

用于空间串扰的显式点扩散核(奇数尺寸;中心抽头为自身权重)。与高斯选项互斥。genesis.utils.misc.gaussian_crosstalk_kernel(n_rows, n_cols, sigma) 会构建一个 L1 归一化的高斯核。

网格 taxel:KinematicTaxel、ProximityTaxel

空间串扰要求 probe_local_pos 是规则的平面 (M, N, 3) 网格;不规则布局可用 probe_radius=0 的填充 taxel 补齐,这些 taxel 读数为零并被跳过。

import genesis.utils.misc as misc

taxel = scene.add_sensor(
    gs.sensors.KinematicTaxel(
        entity_idx=platform.idx,
        link_idx_local=0,
        probe_local_pos=grid_positions,  # (M, N, 3) grid
        probe_radius=0.004,
        # measured-branch imperfections:
        hysteresis_strength=0.5,
        hysteresis_tau=0.1,
        probe_gain=1.5,
        crosstalk_kernel=misc.gaussian_crosstalk_kernel(3, 3, sigma=1.0),
    )
)

另见#

  • 接触:基于求解器的连杆级接触、接触力和关节力矩。

  • 传感器总览:采样率、read_ground_truth()、批处理 scene.read_sensors()、噪声、延迟和 history_length。

  • 扩展 Genesis World → 传感器:传感器流水线以及如何添加你自己的传感器类型。