IPC 耦合器#

IPC 耦合器使用增量势接触(Incremental Potential Contact)来求解接触,这是一种构建在 libuipc 库之上的、基于障碍势的模型。它通过一个光滑势来推进所有被耦合的物体,当两个表面相互靠近时,该势的障碍项会无限增大,因此 IPC 处理的接触即使在大变形下也保持无交叠。IPC 的每步开销高于传统耦合器,所以我们仍将传统耦合器作为默认选项,并允许你按场景选择 IPC。

它适用于带自碰撞的布料、被紧紧压在一起的 FEM 固体,以及夹爪合拢抓取可变形物体的场景。对于混合连续介质场景(MPM、SPH、PBD)或粗糙的刚体接触,请继续使用传统耦合器;完整对比见耦合器总览。

FEM 物体直接通过其顶点位置参与耦合;刚体则以仿射体(ABD)的形式进入 IPC 世界。时间步、重力和可微分仿真模式来自 SimOptions,而不是由耦合器提供。

前置条件#

IPC 耦合依赖 libuipc,它以 pyuipc 包的形式分发(导入名为 uipc)。这是一个可选依赖,默认不会随 Genesis World 一起安装。

pip install pyuipc

Warning

pyuipc 目前只支持 x86 Linux 和 Windows,运行在 CPU 或 NVIDIA GPU 上。在其他平台上无法使用 IPC 耦合器。如果导入失败,Genesis World 会在你构建使用 IPCCouplerOptions 的场景时抛出错误。

最小示例#

完整脚本见 examples/ipc/ipc_objects_falling.py:一块布落到刚体盒子和一个软 FEM 球体上,全部由 IPC 求解。向 Scene 传入 IPCCouplerOptions 即可选择该耦合器:

import genesis as gs

gs.init(backend=gs.cpu)

scene = gs.Scene(
    sim_options=gs.options.SimOptions(dt=0.02),  # dt and gravity live here, not on the coupler
    coupler_options=gs.options.IPCCouplerOptions(
        contact_d_hat=0.01,  # contact barrier distance (m); size to your mesh resolution
        two_way_coupling=True,  # IPC forces act back on Genesis rigid bodies
    ),
)

实体通过其材质加入 IPC 世界。布料是一种 FEM 薄壳:

cloth = scene.add_entity(
    morph=gs.morphs.Mesh(file="path/to/grid20x20.obj", pos=(0.0, 0.0, 1.0)),
    material=gs.materials.FEM.Cloth(
        E=1e5,  # Young's modulus (Pa)
        nu=0.499,  # Poisson's ratio, nearly incompressible
        rho=200,  # density (kg/m3)
        thickness=0.001,  # shell thickness (m)
        bending_stiffness=50.0,
    ),
)

如果希望刚体完全由 IPC 驱动,使用 coup_type="ipc_only":

box = scene.add_entity(
    morph=gs.morphs.Box(pos=(-0.25, 0.0, 0.3), size=(0.2, 0.2, 0.2)),
    material=gs.materials.Rigid(rho=500, coup_type="ipc_only"),
)

Note

该示例下载的是较粗的 grid20x20.obj 布料网格,而非细密网格。IPC 的接触障碍要求网格相对于 contact_d_hat 足够粗;若网格三角形小于障碍距离,就会触发厚度违反。应让 contact_d_hat 与你的网格分辨率匹配(通常为 0.5–2 mm),而不是盲目调小它。

实体如何参与耦合#

每个实体的刚体材质通过 coup_type 声明其参与方式,因此耦合器无需逐连杆注册:

  • two_way_soft_constraint: Genesis 与 IPC 通过一个软的位置与姿态约束交换力。适用于浮动基座机器人,或任何由 Genesis 控制运动、但又必须感受接触的刚体。

  • external_articulation: 面向关节机器人的关节级耦合:IPC 在 dof 层面而非逐连杆层面耦合。适用于固定基座机械臂。

  • ipc_only: IPC 拥有物体的动力学(重力与碰撞),并将得到的变换单向复制回 Genesis。适用于被动的刚体道具。

当 coup_type 为 None(默认值)时,Genesis 会根据实体类型自动选择:固定基座机器人用 external_articulation,浮动基座机器人用 two_way_soft_constraint,非关节物体用 ipc_only。

若要限制 two_way_soft_constraint 机器人只有特定连杆参与(例如只耦合夹爪的手指而不耦合手臂),传入 coup_links:

franka = scene.add_entity(
    gs.morphs.MJCF(file="xml/franka_emika_panda/panda_non_overlap.xml"),
    material=gs.materials.Rigid(
        coup_type="two_way_soft_constraint",
        coup_links=("left_finger", "right_finger"),  # only these links couple
        coup_friction=0.8,
    ),
)

耦合器选项#

IPCCouplerOptions 既暴露 Genesis 侧的耦合行为,也提供透传给 libuipc 求解器的参数。大多数求解器参数默认是 None,表示采用 libuipc 自身的默认值;下面列出的是你最可能设置的字段。完整列表(包括 Newton、线搜索和线性系统参数)见IPCCoupler 选项 API。

参数

默认值

说明

contact_d_hat

None(libuipc:0.01)

接触障碍距离,单位米。应按网格分辨率设定。

contact_enable

None(libuipc:True)

是否启用接触检测。

contact_friction_enable

None(libuipc:True)

接触是否施加摩擦。逐物体的摩擦来自材质(刚体用 coup_friction,FEM 用 friction_mu)。

contact_resistance

1e9

地面与默认的接触刚度;当材质未设置 contact_resistance 时作为逐实体的回退值。

constraint_strength_translation

100.0

Genesis 刚体与其 IPC 仿射体之间位置耦合的刚度。

constraint_strength_rotation

100.0

姿态耦合的刚度。越大越刚硬,但可能导致不稳定。

two_way_coupling

True

IPC 的力与力矩是否反作用于 Genesis 刚体。设为 False 则为单向耦合。

enable_rigid_ground_contact

True

IPC 物体是否与地平面碰撞。禁用可避免与 Genesis 已处理的地面接触重复计算。

enable_rigid_rigid_contact

True

IPC 是否检测刚体(ABD)之间的接触。禁用后只保留软-软与软-刚接触。

摩擦是逐材质属性,不是耦合器的全局设置:在 gs.materials.Rigid 上设置 coup_friction,在 FEM 材质上设置 friction_mu。

机器人抓取#

完整脚本见 examples/ipc/ipc_robot_grasp_cube.py:Franka 机械臂抓取并抬起一个可变形立方体。这里 IPC 只耦合手指,而可变形立方体是 FEM 固体:

scene = gs.Scene(
    sim_options=gs.options.SimOptions(dt=0.01),
    coupler_options=gs.options.IPCCouplerOptions(
        constraint_strength_translation=10.0,
        constraint_strength_rotation=10.0,
        enable_rigid_rigid_contact=False,  # only finger-cube contact matters here
        enable_rigid_ground_contact=False,
    ),
)

franka = scene.add_entity(
    gs.morphs.MJCF(file="xml/franka_emika_panda/panda_non_overlap.xml"),
    material=gs.materials.Rigid(
        coup_type="two_way_soft_constraint",
        coup_links=("left_finger", "right_finger"),
        coup_friction=0.8,
    ),
)

cube = scene.add_entity(
    morph=gs.morphs.Box(pos=(0.65, 0.0, 0.03), size=(0.05, 0.05, 0.05)),
    material=gs.materials.FEM.Elastic(
        E=5.0e4,  # Young's modulus (Pa)
        nu=0.45,
        rho=1000.0,
        friction_mu=0.5,
        model="stable_neohookean",
    ),
)

如需可通过键盘遥操作的交互版本,见 examples/ipc/ipc_robot_cloth_teleop.py。

延伸阅读#