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_enabled | bool | 是否启用所选形状的碰撞。与视口中的显示可见性分开设置。 |
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_mass | ek.vec3,刚体局部坐标系中的质心,m。 |
inertia | ek.mat33,对称惯性张量,kg·m²,需通过物理有效性校验。 |
gravcomp | 0~1 的有限数,重力补偿比例。 |
starts_asleep | bool,设置构建时的初始睡眠状态。 |
例如,将左右各一根夹指连杆的质量都配置为 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() 等创建的程序化物体 | 当前这套源属性编辑接口不支持,应在创建时配置其物理参数。 |

