跳到主要内容

Scene 物理参数接口

Scene 提供物理属性编辑接口,用于在加载资产后、构建仿真模型前修改对象配置。本篇介绍接触、刚体、关节、驱动及场景的 Scene Physics Properties API,包含单路径和路径列表调用。

这些接口直接修改对象 GeoDomain 中的物理源数据,返回 None。后续 scene.finalize__ektro() 从这些数据生成刚体描述,并交给 Solver 构建模型。

加载 URDF / USD 资产
→ 设置接触、刚体、关节和驱动属性
→ scene.finalize__ektro(...)
→ Solver 使用修改后的配置执行仿真

省略参数或传入 None 表示保持原值;传入 0、0.0 或 False 表示显式设置该值,不表示忽略。

单路径与路径列表​

配置类别单路径接口路径列表接口及参数
刚体set_body_physics_properties(path, ...)set_bodies_physics_properties(paths, ...)
关节set_joint_physics_properties(path, ...)set_joints_physics_properties(paths, ...)
驱动set_actuator_physics_properties(joint_path, ...)set_actuators_physics_properties(joint_paths, ...)
接触使用集合接口set_contact_physics_properties(body_paths=... 或 geom_paths=..., ...)
当前场景set_scene_physics_properties(gravity=..., timestep=...)直接配置当前 Scene,无路径列表参数。

集合参数类型为 Sequence[str],支持 list 和 tuple。集合不能为空、不能含重复 路径;每项必须是完整 Scene 路径。单个目标可以使用单路径接口,也可以放入一个 元素的列表;不能把字符串直接传给集合接口,也不能把列表传给单路径接口。

一套属性值应用于列表中的全部目标。例如 stiffness=80.0 将所有选中驱动的 刚度都设置为 80.0。省略的属性沿用各目标自己的原值。需要不同数值时,分别 调用单路径接口,或按相同数值分组调用批量接口。

一次批量调用先校验所有目标和数值,再统一写入。任一目标不存在、类型不符或 参数无效时,整批不提交。各批量接口的属性参数、默认值、单位和调用时机与对应 单路径接口一致。

以下参数声明中的 Sequence 来自标准库:

from collections.abc import Sequence

接触及摩擦力设置​

该接口修改碰撞形状的摩擦、碰撞开关及接触参数。可以按刚体批量设置其碰撞形状,也可以直接指定碰撞形状路径。

接口声明​

def set_contact_physics_properties(
self,
*,
body_paths: Sequence[str] = (),
geom_paths: Sequence[str] = (),
sliding_friction: float | None = None,
torsional_friction: float | None = None,
rolling_friction: float | None = None,
collision_enabled: bool | None = None,
collision_group: int | None = None,
margin: float | None = None,
gap: float | None = None,
) -> None: ...

以上为参数声明,调用示例见下文。

选择修改对象​

参数说明
body_paths刚体的绝对 Scene 路径列表或元组。修改每个刚体所属的全部碰撞形状,不包含其子刚体所属的形状。
geom_paths碰撞形状的绝对 Scene 路径列表或元组。只修改明确选中的形状。

两种选择方式必须且只能提供一种非空集合。单个路径可写成 [path] 或 (path,),不能直接传字符串。

路径应定位到已导入的物理对象,例如 /root/obj/g1_d/G1_D_with_DEX1_1/left_dex1_1_link1_1。普通显示网格或任意父级分组不能代替刚体、碰撞形状路径。

接触参数​

参数类型与取值作用
sliding_friction有限、非负数滑动摩擦参数。
torsional_friction有限、非负数绕接触法线的扭转摩擦参数。
rolling_friction有限、非负数滚动摩擦参数。
collision_enabledbool是否启用所选形状的碰撞。与视口中的显示可见性分开设置。
collision_group非负整数碰撞形状的分组编号,具体使用方式由 Solver 配置决定。
margin有限、非负数,单位 m接触裕量,传递到后端的 margin 配置。
gap有限、非负数,单位 m接触间隙参数,传递到后端的 gap 配置。

三个摩擦参数不是统一的 0~1 滑块。 此 API 没有将摩擦值上限限制为 1,具体含义和接触双方的组合规则由后端解释。提高某一侧的滑动摩擦,也不等于接触中的其它摩擦分量和约束同时改变。

当前实现将三种摩擦保存在 Sim 使用的 physics:friction 三分量扩展中,顺序为滑动、扭转、滚动。它不是标准 USD MaterialAPI 的静摩擦、动摩擦两个字段。

首次设置时,如果源数据没有完整的三分量摩擦值,必须一次提供全部三个参数;已有完整值后,允许只修改其中一项,其余分量保持原值。

对于 MuJoCo-Ektro,collision_group 默认写入几何分组,不会仅凭组号自动过滤碰撞。只有显式启用 MujocoModelConfig.collision_filter_from_group 时,才按分组生成过滤掩码;此模式要求组号在 0~31 之间。

三种摩擦的区别​

参数阻碍的相对运动直观理解
sliding_friction沿接触平面的滑动,通过切向摩擦力阻碍运动。夹住料箱后,阻碍料箱沿夹指表面下滑。
torsional_friction绕接触法线的旋转,通过摩擦力矩阻碍运动。把橡皮压在桌面上,保持接触并原地拧转。
rolling_friction绕接触平面内的轴旋转,通过摩擦力矩阻碍运动。阻碍轮子或球在表面上继续滚动。

滑动、扭转与滚动摩擦的运动方向对比

先确定接触法线 n:它垂直接触平面。夹指侧面夹住料箱时,法线通常沿夹持方向,并不等于世界坐标的竖直方向。图中蓝色箭头表示相对运动趋势,红色箭头表示摩擦的阻碍作用。

滑动看的是接触点的切向相对移动;扭转和滚动看的是相对转动的轴向。同一次接触可以同时包含这些运动。

在 MuJoCo 中,滑动摩擦系数无量纲,扭转和滚动摩擦系数具有长度量纲,不能将三者当成相同含义的数值比较。接触的 condim=3 包含滑动摩擦,condim=4 增加扭转摩擦,condim=6 再增加滚动摩擦;是否参与求解还取决于实际接触维度。set_contact_physics_properties() 当前不直接设置 condim。以上区别参见 MuJoCo 官方接触模型说明。

示例:设置夹指摩擦​

以下路径和参数取自双臂抓取 demo,演示同时修改左右各一根夹指:

scene.set_contact_physics_properties(
body_paths=[
"/root/obj/g1_d/G1_D_with_DEX1_1/left_dex1_1_link1_1",
"/root/obj/g1_d/G1_D_with_DEX1_1/right_dex1_1_link1_1",
],
sliding_friction=2.0,
torsional_friction=1.005,
rolling_friction=0.0001,
)

完整 demo 对左右共 12 个夹指连杆应用同样的设置。需要修改更多刚体时,将对应绝对路径加入 body_paths。

在上述完整摩擦值已经存在后,可以单独修改滑动摩擦:

scene.set_contact_physics_properties(
body_paths=[
"/root/obj/g1_d/G1_D_with_DEX1_1/left_dex1_1_link1_1",
],
sliding_friction=0.0,
)

这里明确将该侧滑动摩擦设为零;扭转、滚动摩擦保持原值。不能据此认定与它接触的另一侧摩擦也被设为零。

设置刚体属性​

单路径接口 set_body_physics_properties(path, ...) 设置一个刚体,批量接口使用 paths。下面给出批量接口的完整参数;单路径接口的属性参数和默认值相同。

def set_bodies_physics_properties(
self,
paths: Sequence[str],
*,
mass: float | None = None,
center_of_mass: ek.vec3 | None = None,
inertia: ek.mat33 | None = None,
gravcomp: float | None = None,
starts_asleep: bool | None = None,
) -> None: ...
参数类型、单位与作用
paths刚体的绝对 Scene 路径列表或元组。
mass有限正数,kg。
center_of_massek.vec3,刚体局部坐标系中的质心,m。
inertiaek.mat33,对称惯性张量,kg·m²,需通过物理有效性校验。
gravcomp0~1 的有限数,重力补偿比例。
starts_asleepbool,设置构建时的初始睡眠状态。

例如,将左右各一根夹指连杆的质量都配置为 0.1 kg:

scene.set_bodies_physics_properties(
paths=[
"/root/obj/g1_d/G1_D_with_DEX1_1/left_dex1_1_link1_1",
"/root/obj/g1_d/G1_D_with_DEX1_1/right_dex1_1_link1_1",
],
mass=0.1,
)

只修改一个料箱时,继续使用单路径接口:

scene.set_body_physics_properties("/root/obj/box/Box", mass=0.1)

设置关节属性​

单路径接口 set_joint_physics_properties(path, ...) 设置一个关节,批量接口使用 paths。两者修改关节自身的机械属性和初始状态。

def set_joints_physics_properties(
self,
paths: Sequence[str],
*,
limit_lower: float | None = None,
limit_upper: float | None = None,
velocity_limit: float | None = None,
passive_damping: float | None = None,
friction: float | None = None,
armature: float | None = None,
initial_position: float | None = None,
initial_velocity: float | None = None,
) -> None: ...
参数类型、单位与作用
paths单自由度转动关节或移动关节的绝对 Scene 路径集合。
limit_lower、limit_upper有限数,关节下限与上限;移动关节 m,转动关节 rad。结合原配置检查上下限完整且有序。
velocity_limit有限非负数,移动关节 m/s,转动关节 rad/s。
passive_damping有限非负数,关节被动阻尼。
friction有限非负数,关节摩擦。
armature有限非负数,附加关节惯量。
initial_position有限数,初始位置;单位同关节限位,并需满足限位。
initial_velocity有限数,初始速度;单位同速度上限。

例如,给四个夹爪主动滑动关节配置相同的速度上限和被动阻尼:

scene.set_joints_physics_properties(
paths=[
"/root/obj/g1_d/G1_D_with_DEX1_1/joints/left_dex1_1_joint1_1",
"/root/obj/g1_d/G1_D_with_DEX1_1/joints/left_dex1_1_joint2_1",
"/root/obj/g1_d/G1_D_with_DEX1_1/joints/right_dex1_1_joint1_1",
"/root/obj/g1_d/G1_D_with_DEX1_1/joints/right_dex1_1_joint2_1",
],
velocity_limit=0.05,
passive_damping=0.1,
)

设置 URDF 关节初始状态时,位置和速度必须能从本次参数与源配置共同取得, 不能只留下一个没有配对的初始状态分量。

设置关节驱动​

该接口通过关节路径配置位置或速度驱动,包括控制模式、增益、构建时目标及输出上限。

接口声明​

def set_actuator_physics_properties(
self,
joint_path: str,
*,
mode: str | None = None,
stiffness: float | None = None,
damping: float | None = None,
target_position: float | None = None,
target_velocity: float | None = None,
effort_limit: float | None = None,
) -> None: ...

joint_path 使用已有单自由度转动关节或移动关节的绝对 Scene 路径,不是连杆路径,也不要求调用方拼接内部驱动记录的名字。当前接口不支持固定关节、球关节和自由关节。

批量版本使用 joint_paths,其余参数和默认值相同:

def set_actuators_physics_properties(
self,
joint_paths: Sequence[str],
*,
mode: str | None = None,
stiffness: float | None = None,
damping: float | None = None,
target_position: float | None = None,
target_velocity: float | None = None,
effort_limit: float | None = None,
) -> None: ...

驱动参数​

参数类型与取值作用
mode"position" 或 "velocity"驱动模式。省略时必须能从源数据中确定。当前 URDF 来源只支持 "position";USD 来源支持两种模式。
stiffness有限、非负数位置驱动刚度,控制位置误差产生作用力的强度。仅位置模式支持。
damping有限、非负数驱动阻尼;在速度模式下作为速度反馈增益。与关节的被动机械阻尼分开配置。
target_position有限数构建时的位置目标,仅位置模式支持。移动关节使用 m,转动关节使用 rad。
target_velocity有限数构建时的速度目标,仅速度模式支持。移动关节使用 m/s,转动关节使用 rad/s。
effort_limit有限、非负数驱动输出的力或力矩上限,移动关节使用 N,转动关节使用 N·m。

位置模式要求能从本次参数或已有源数据取得 stiffness 和 damping;速度模式要求能取得 damping。缺失模式或必要增益会报错,不会自动生成默认控制器。

位置模式不能设置 target_velocity;速度模式不能设置 target_position 或 stiffness。转动关节的公开入参按弧度填写,由接口处理写入 USD 时的单位转换。

示例:覆盖夹爪驱动刚度​

G1-D 资产已包含位置驱动模式和阻尼,因此可以只覆盖刚度:

scene.set_actuators_physics_properties(
joint_paths=[
"/root/obj/g1_d/G1_D_with_DEX1_1/joints/left_dex1_1_joint1_1",
"/root/obj/g1_d/G1_D_with_DEX1_1/joints/left_dex1_1_joint2_1",
"/root/obj/g1_d/G1_D_with_DEX1_1/joints/right_dex1_1_joint1_1",
"/root/obj/g1_d/G1_D_with_DEX1_1/joints/right_dex1_1_joint2_1",
],
stiffness=80.0,
)

左右两只夹爪各有两个主动关节。这一次调用将四个驱动的刚度统一设置为 80.0,其余驱动属性沿用各关节原值。完整双臂抓取 demo 使用同一批量调用。

驱动阻尼属于控制器配置。要设置关节本身的被动阻尼,应使用 scene.set_joint_physics_properties(..., passive_damping=...),两者不能相互替代。

构建配置与播放控制​

target_position、target_velocity 定义构建时的驱动目标,不会直接把机器人移动到指定位置,也不是播放期间逐帧提交目标的接口。

双臂抓取 demo 在播放期间,将 IK 生成的关节目标写入 scene.sim_data.data["control"]["joint_target_pos"],再显式调用 solver.upload_control__ektro(scene.sim_data)。MuJoCo 根据驱动配置和当前物理状态执行计算。

构建前:set_actuator_physics_properties / set_actuators_physics_properties → 模式、增益、初始目标、输出上限
播放中:Demo.update → SimData 控制目标 → upload_control__ektro → 动力学计算

设置场景物理属性​

set_scene_physics_properties 配置当前 Scene 的重力和仿真时间步长,无需传入对象 路径。gravity 使用 ek.vec3,单位 m/s²;timestep 是有限正数,单位 s。

def set_scene_physics_properties(
self,
*,
gravity: ek.vec3 | None = None,
timestep: float | None = None,
) -> None: ...

该入口保留现有适用边界:USD 来源在导入后新增 PhysicsScene 的 finalize 路径仍有 已记录的校验失败,当前批量接口扩展没有修复该问题。已有 PhysicsScene 和 URDF 来源的行为按原接口执行。

调用时机与错误处理​

这套接口都要求 Scene 尚未 finalize,且未通过 scene.set_rigid_entity() 注入显式刚体描述。它们修改源数据,不直接修改已经构建的后端模型。

情况当前行为
路径不存在、对象类型不匹配或刚体没有碰撞形状报错,不创建替代对象。
路径重复,或多个选择命中同一源记录报错,避免重复覆盖。
数值不是有限数、非负参数为负数、将 bool 当数值传入报错。
一批目标中存在非法参数或目标全部校验后才提交;校验失败不提交本批修改。
Scene 已构建,或已有显式刚体描述报错,不在运行中重建模型。
同一 GeoDomain 被多个 SceneObject 共享,或编辑目标属于 USD 原型、实例及实例代理当前不支持编辑。
通过 scene.add_box__ektro() 等创建的程序化物体当前这套源属性编辑接口不支持,应在创建时配置其物理参数。