接触与力传感器#

Contact、ContactForce 和 JointTorque 直接从刚体求解器读取刚体连杆或关节与场景其余部分的交互方式。它们基于求解器:与仿真在物理上自洽,但只报告求解器实际解算出接触的位置。当你需要连杆或关节层面的真值交互时使用它们。如果需要在表面上获得密集的逐 taxel 读数场,请改用 触觉传感器。

关于传感器如何采样、回读、用 scene.read_sensors() 批处理,以及如何配置噪声、延迟和 history_length,请参阅 传感器总览。

选择传感器#

传感器

read() 返回值

形状

坐标系 / 单位

Contact

是否接触的标志

([n_envs,] 1)

bool

ContactForce

作用在连杆上的合力

([n_envs,] 3)

连杆局部坐标系,N

JointTorque

每个自由度的执行器作用力

([n_envs,] n_dofs)

N·m(旋转关节)/ N(移动关节)

只有当场景以多个环境构建时才存在 [n_envs,] 轴。以 history_length > 0 创建的传感器会在批次轴之后多出一个轴(见 总览)。

接触与接触力#

Contact 和 ContactForce 都读取刚体求解器针对某一个连杆的接触冲量。Contact 报告该连杆是否接触到任何东西;ContactForce 报告作用在其上的合力向量,并旋转到连杆自身的坐标系中。

完整脚本是 examples/sensors/contact_force_go2.py,它在 Go2 四足机器人的每只脚上挂载一个传感器(传入 --no-force 可将 ContactForce 换成 Contact):

foot_link_names = ("FR_foot", "FL_foot", "RR_foot", "RL_foot")
go2 = scene.add_entity(
    gs.morphs.URDF(
        file="urdf/go2/urdf/go2.urdf",
        pos=(0.0, 0.0, 0.2),
        links_to_keep=foot_link_names,
    )
)

for link_name in foot_link_names:
    sensor = scene.add_sensor(
        gs.sensors.ContactForce(
            entity_idx=go2.idx,
            link_idx_local=go2.get_link(link_name).idx_local,
            draw_debug=True,
        )
    )

entity_idx 和实体局部的 link_idx_local 把传感器绑定到一个连杆。构建并步进之后,这样读取它:

force = sensor.read()  # shape ([n_envs,] 3), N, in the link-local frame

Contact 和 ContactForce 都接受 filter_link_idx,即要忽略的全局连杆索引列表,这样传感器读取起来就像这些对应连杆没有接触一样。可以用它来限定读数范围,例如只读取脚与地面之间的力而排除自接触。Contact 还有一个接触 threshold,ContactForce 会把每个轴钳制到 [min_force, max_force];这些参数及其默认值见 接触参考。

一只 Go2 四足机器人站在地面上,每只脚处都绘制了一个洋红色箭头,显示该脚的 ContactForce 传感器报告的接触力

关节力矩#

JointTorque 测量每个执行器输出轴处提供的广义作用力:旋转自由度为力矩,移动自由度为力。这是一种本体感知的交互感知方式:外部接触会表现为关节所需提供的作用力发生变化,而接触的连杆上无需任何专用接触传感器。

读数建模的是减速箱接口处的作用力:

actuator_force = tau_control - armature * qacc + tau_frictionloss + tau_damping

因为 qacc 是约束求解后的加速度,读数会隐式地包含重力、科氏力和接触载荷。在自由空间中,读数大致是重力载荷与科氏力载荷之和;当机械臂压向障碍物时,它还会携带接触反作用力。

完整脚本是 examples/sensors/joint_torque_franka.py,它让 Franka 机械臂顶住一个固定的墙壁方块,并绘制控制力矩与感知力矩的对比:

joint_torque = scene.add_sensor(
    gs.sensors.JointTorque(
        entity_idx=franka.idx,
        dofs_idx_local=(0, 1, 2, 3, 4, 5, 6),  # None (default) selects all dofs
    )
)

# ... build, then each step ...
tau = joint_torque.read()  # shape ([n_envs,] n_dofs)

另见#

  • 触觉:用于触觉皮肤的密集逐 taxel 接触场(探针与 taxel)。

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

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