Adding a simulator

July 30, 2026 · View on GitHub

RGBench couples benchmark code to simulator code only through a four-method abstract base class. Adding a new simulator means writing one subclass and one factory branch — about an afternoon's work plus however long it takes to wire up your simulator's stepping logic.

The contract

rgbench.envs.base.BaseEnvWrapper requires:

class MySimEnv(BaseEnvWrapper):
    def __init__(self, cfg: DictConfig, **kwargs):
        # Initialize your simulator from cfg.env / cfg.cloth_params /
        # cfg.sim_model / cfg.data.robot_joints. Load the robot trajectory
        # CSV with rgbench.csv_data.load_processed_data.
        ...

    def step_to_time(self, target_time: float) -> None:
        # Advance the simulator to absolute time `target_time` (seconds
        # since master_start_time). Run as many internal physics steps
        # as needed.
        ...

    def get_sim_vertices(self) -> np.ndarray:
        # Return (N, 3) cloth vertex positions in world frame at the
        # current simulator time. N can be anything > 0.
        ...

    def get_master_start_time(self) -> float:
        # Absolute timestamp (typically from the first row of the joint
        # trajectory CSV) used as t=0 reference.
        ...

    def get_current_sim_time(self) -> float:
        # Current simulator time relative to master_start_time.
        ...

Optional: override close() to release simulator resources.

Factory registration

Edit rgbench/envs/__init__.py and add a branch:

elif "my_sim" in env_name:
    from .my_sim.my_sim_env import MySimEnv
    return MySimEnv(cfg=env_cfg, **kwargs)

Then create a configs/env/my_sim.yaml that mirrors the existing pybullet.yaml / isaacsim.yaml skeletons.

Three reference implementations to crib from

WrapperFileNotes
PyBulletrgbench/envs/pybullet/cloth_pybullet_env.pySoft-body via p.loadSoftBody; bimanual Piper IK
Isaac Simrgbench/envs/isaacsim/cloth_isaacsim_env.pyParticle-cloth on USD assets
plain MuJoCorgbench/envs/mujoco/cloth_mujoco_env_fixed_point.pyNative MuJoCo flex, fixed-point end-effector control

A fourth slot exists for the not-yet-released GarmentDynamics simulator via a lazy import:

elif "mujoco_style3d" in env_name or "garment_dynamics" in env_name:
    from rgbench_garmentdynamics import GarmentDynamicsEnv
    return GarmentDynamicsEnv(cfg=env_cfg, **kwargs)

When the companion rgbench-garmentdynamics pip package is installed, this branch lights up automatically.

Common pitfalls

  • Coordinate frameget_sim_vertices must return world-frame coordinates. RGBench transforms real-world point clouds into world frame using the per-capture calibration; if your simulator works in a different frame, transform inside the wrapper.
  • Time alignmenttarget_time in step_to_time is wall-clock seconds from master_start_time, not a physics-step count. Always inner-loop on the simulator's native timestep until you reach the target.
  • Vertex count — point-cloud metrics are robust to differing point counts. You don't need to match the real-world cloud's resolution.
  • Cloth parametersconfigs/cloth_params/*.yaml are fitted against GarmentDynamics. Retune for your simulator before publishing sim-to-real numbers (see BENCHMARK.md for the rationale).

Testing

Add a smoke test under tests/test_<my_sim>.py modelled on tests/test_pybullet.py: load the wrapper on the smoke-test sample, step it for 1-2 seconds, and assert get_sim_vertices() returns a sensible shape.