UniSim 统一接口
UniSim 是 FastSim 与底层仿真引擎之间的唯一接口层。它将"启动仿真器、推进物理、查询运行状态"这三件事抽象成一组固定接口,使得 SceneManager、ControllerManager 等上层模块完全不感知当前运行的是 IsaacLab、Mujoco 还是其他引擎。
职责边界
UniSim 只做以下几件事:
- 启动底层仿真 App 或 SimulationContext
- 推进物理引擎一个时间步(
step()) - 查询仿真器是否仍在运行(
is_running()) - 提供少量全局级辅助能力(如 viewport 相机设置)
不属于 UniSim 职责的事情:
- 实体的创建与管理 →
SceneManager - 控制命令的执行 →
ControllerManager - 录制、服务化等扩展功能 →
ExtensionManager - 任务编排与目标检查 →
TaskManager
这个边界划分使得每一层都可以独立测试和扩展,也是 FastSim 能够支持多后端的基础。
核心接口
UniSim 抽象基类定义在 fastsim/unisim/unisim.py,所有后端均需实现以下方法:
| 方法 | 调用时机 | 说明 |
|---|---|---|
initialize_simulation() | setup_all_before_loop() 阶段 | 启动仿真 App / SimulationContext,完成底层初始化 |
setup_viewport_camera() | 初始化后(可选) | 设置默认视角,调试时使用 |
reset() | 场景构建完成后 | 复位仿真状态,执行初始化步骤 |
step() | 每个仿真帧 | 推进物理引擎一个时间步(dt) |
is_running() | 主循环判断条件 | 查询底层 App 是否仍在运行 |
UniSim 在仿真主循环中的位置
FastSim.step() 的执行顺序如下。UniSim 的 step() 是其中的物理推进核心,前后各有一个 SceneManager 的读写阶段:
ControllerManager.run_all_commands() ← 执行控制命令队列
SceneManager.pre_physics_update() ← 将目标值/脏数据写入仿真器
UniSim.step() ← 物理引擎推进一帧(dt)
SceneManager.post_physics_update() ← 从仿真器读取最新状态
[step callbacks] ← record、benchmark 等扩展挂接点
UniSim.step() 本身只负责推进物理,不涉及任何实体读写。实体的写入发生在它之前(pre_physics_update),读取发生在它之后(post_physics_update)。
后端选择:从配置到实例
后端由配置文件中的 simulation.stereotype 字段决定。UniSimFactory.create(config) 在 FastSim.__init__() 中被调用,根据 stereotype 实例化对应后端:
simulation:
stereotype: isaaclab # 决定使用哪个后端
dt: 0.01667
device: cuda:0
对应的工厂逻辑(源码:fastsim/unisim/unisim.py):
simulation.stereotype
↓
UniSimFactory.create(config)
↓
IsaacLab(UniSim) / Mujoco(UniSim) / ...
stereotype 的可用值由注册表决定。可通过以下 CLI 工具查看当前注册的所有后端:
fastsim show-registry
IsaacLab 后端
当 simulation.stereotype: isaaclab 时,实际运行的是 fastsim/simulators/isaaclab/isaaclab_app.py 中的 IsaacLab(UniSim)。
初始化行为:
AppLauncher(**launch_config)启动 Isaac Sim 进程- 构造
SimulationCfg(包含dt、gravity、physx、render等参数) - 创建
SimulationContext并绑定到物理场景
步进行为:
step()调用sim.step(render=True),推进物理并渲染一帧is_running()对应app.is_running()
IsaacLab 专有配置字段(在 simulation 块下扩展):
| 字段 | 说明 |
|---|---|
device | 计算设备,如 cuda:0、cpu |
dt | 物理时间步长(秒),通常 0.01667(60Hz) |
gravity | 重力向量,默认 [0, 0, -9.81] |
enable_scene_query_support | 是否启用场景查询(碰撞检测等) |
use_gpu_pipeline | 是否使用 GPU 物理流水线 |
详细字段定义见 fastsim/simulators/isaaclab/isaaclab_config.py。
实现自定义后端
如需接入新的仿真器,只需继承 UniSim 并实现上述五个接口方法,然后通过 stereotype 注册机制注册:
from fastsim.unisim.unisim import UniSim
from fastsim.annotations.stereotype import stereotype
@stereotype("my_simulator")
class MySimulator(UniSim):
def initialize_simulation(self): ...
def step(self): ...
def reset(self): ...
def is_running(self) -> bool: ...
注册后,在配置中写 simulation.stereotype: my_simulator 即可使用,上层代码无需任何改动。