Creating a simulation scene#
This tutorial shows how to create a basic simulation scene using SimulationManager. It covers the setup of the simulation context, adding rigid objects, and running the simulation loop.
The Code#
The tutorial corresponds to the create_scene.py script in the scripts/tutorials/sim directory.
Code for create_scene.py
1# ----------------------------------------------------------------------------
2# Copyright (c) 2021-2026 DexForce Technology Co., Ltd.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15# ----------------------------------------------------------------------------
16
17"""
18This script demonstrates how to create a simulation scene using SimulationManager.
19It shows the basic setup of simulation context, adding objects, and sensors.
20"""
21
22import argparse
23import time
24
25from embodichain.lab.sim import SimulationManager, SimulationManagerCfg
26from embodichain.lab.sim.cfg import RigidBodyAttributesCfg, RenderCfg
27from embodichain.lab.sim.shapes import CubeCfg, MeshCfg
28from embodichain.lab.sim.objects import RigidObject, RigidObjectCfg
29from embodichain.lab.gym.utils.gym_utils import add_env_launcher_args_to_parser
30from embodichain.data import get_data_path
31
32
33def main():
34 """Main function to create and run the simulation scene."""
35
36 # Parse command line arguments
37 parser = argparse.ArgumentParser(
38 description="Create a simulation scene with SimulationManager"
39 )
40 add_env_launcher_args_to_parser(parser)
41 args = parser.parse_args()
42
43 # Configure the simulation
44 sim_cfg = SimulationManagerCfg(
45 width=1920,
46 height=1080,
47 headless=True,
48 physics_dt=1.0 / 100.0, # Physics timestep (100 Hz)
49 sim_device=args.device,
50 render_cfg=RenderCfg(
51 renderer=args.renderer,
52 ),
53 num_envs=args.num_envs,
54 arena_space=3.0,
55 )
56
57 # Create the simulation instance
58 sim = SimulationManager(sim_cfg)
59
60 # Add cube object to the scene
61 cube: RigidObject = sim.add_rigid_object(
62 cfg=RigidObjectCfg(
63 uid="cube",
64 shape=CubeCfg(size=[0.1, 0.1, 0.1]),
65 body_type="dynamic",
66 attrs=RigidBodyAttributesCfg(
67 mass=1.0,
68 dynamic_friction=0.5,
69 static_friction=0.5,
70 restitution=0.1,
71 ),
72 init_pos=[0, 0.0, 1.0],
73 )
74 )
75
76 # Add chair object to the scene
77 path = get_data_path("Chair/chair.glb")
78 chair: RigidObject = sim.add_rigid_object(
79 cfg=RigidObjectCfg(
80 uid="chair",
81 shape=MeshCfg(fpath=path),
82 body_type="dynamic",
83 attrs=RigidBodyAttributesCfg(
84 mass=3.0,
85 ),
86 body_scale=[0.5, 0.5, 0.5],
87 init_pos=[0.0, 0.0, 0.2],
88 init_rot=[90.0, 0.0, 0.0],
89 )
90 )
91
92 print("[INFO]: Scene setup complete!")
93 print(f"[INFO]: Running simulation with {args.num_envs} environment(s)")
94 print("[INFO]: Press Ctrl+C to stop the simulation")
95
96 # Open window when the scene has been set up
97 if not args.headless:
98 sim.open_window()
99
100 # Run the simulation
101 run_simulation(sim)
102
103
104def run_simulation(sim: SimulationManager):
105 """Run the simulation loop.
106
107 Args:
108 sim: The SimulationManager instance to run
109 """
110
111 # Initialize GPU physics if using CUDA
112 if sim.is_use_gpu_physics:
113 sim.init_gpu_physics()
114
115 step_count = 0
116
117 try:
118 last_time = time.time()
119 last_step = 0
120 while True:
121 # Update physics simulation
122 sim.update(step=1)
123 step_count += 1
124
125 # Print FPS every second
126 if step_count % 100 == 0:
127 current_time = time.time()
128 elapsed = current_time - last_time
129 fps = (
130 sim.num_envs * (step_count - last_step) / elapsed
131 if elapsed > 0
132 else 0
133 )
134 print(f"[INFO]: Simulation step: {step_count}, FPS: {fps:.2f}")
135 last_time = current_time
136 last_step = step_count
137
138 except KeyboardInterrupt:
139 print("\n[INFO]: Stopping simulation...")
140 finally:
141 # Clean up resources
142 sim.destroy()
143 print("[INFO]: Simulation terminated successfully")
144
145
146if __name__ == "__main__":
147 main()
The Code Explained#
Configuring the simulation#
The first step is to configure the simulation environment. This is done using the SimulationManagerCfg data class, which allows you to specify various parameters like window dimensions, headless mode, physics timestep, simulation device (CPU/GPU), and rendering options like ray tracing.
Command-line arguments are parsed using argparse to allow for easy customization of the simulation from the terminal.
# Parse command line arguments
parser = argparse.ArgumentParser(
description="Create a simulation scene with SimulationManager"
)
add_env_launcher_args_to_parser(parser)
args = parser.parse_args()
# Configure the simulation
sim_cfg = SimulationManagerCfg(
width=1920,
height=1080,
headless=True,
physics_dt=1.0 / 100.0, # Physics timestep (100 Hz)
sim_device=args.device,
render_cfg=RenderCfg(
renderer=args.renderer,
),
num_envs=args.num_envs,
arena_space=3.0,
)
# Create the simulation instance
sim = SimulationManager(sim_cfg)
There are two kinds of physics mode in SimulationManager:
manual: The physics updates only when the user calls the
SimulationManager.update()function. This mode is used for robot learning tasks where precise control over simulation steps is required. Enabled by settingSimulationManager.set_manual_update()to True.auto: The physics updates in a standalone thread, which enable asynchronous rendering and physics stepping. This mode is suitable for visualizations and demos for digital twins applications. This is the default mode.
Adding objects to the scene#
With the simulation context created, we can add objects. This tutorial demonstrates adding a dynamic rigid cube to the scene using the SimulationManager.add_rigid_object() method. The object’s properties, such as its shape, initial position, and physics attributes (mass, friction, restitution), are defined through a configuration object, cfg.RigidObjectCfg.
Running the simulation#
The simulation is advanced through a loop in the run_simulation function. Before starting the loop, GPU physics is initialized if a CUDA device is used.
Inside the loop, SimulationManager.update() is called to step the physics simulation forward. The script also includes logic to calculate and print the Frames Per Second (FPS) to monitor performance. The simulation runs until it’s manually stopped with Ctrl+C.
def run_simulation(sim: SimulationManager):
"""Run the simulation loop.
Args:
sim: The SimulationManager instance to run
"""
# Initialize GPU physics if using CUDA
if sim.is_use_gpu_physics:
sim.init_gpu_physics()
step_count = 0
try:
last_time = time.time()
last_step = 0
while True:
# Update physics simulation
sim.update(step=1)
step_count += 1
# Print FPS every second
if step_count % 100 == 0:
current_time = time.time()
elapsed = current_time - last_time
fps = (
sim.num_envs * (step_count - last_step) / elapsed
if elapsed > 0
else 0
)
print(f"[INFO]: Simulation step: {step_count}, FPS: {fps:.2f}")
last_time = current_time
last_step = step_count
Exiting the simulation#
Upon exiting the simulation loop (e.g., by a KeyboardInterrupt), it’s important to clean up resources. The SimulationManager.destroy() method is called in a finally block to ensure that the simulation is properly terminated and all allocated resources are released.
except KeyboardInterrupt:
print("\n[INFO]: Stopping simulation...")
finally:
# Clean up resources
sim.destroy()
The Code Execution#
To run the script and see the result, execute the following command:
python scripts/tutorials/sim/create_scene.py
A window should appear showing a cube dropping onto a flat plane. To stop the simulation, you can either close the window or press Ctrl+C in the terminal.
You can also pass arguments to customize the simulation. For example, to run in headless mode with n parallel environments using specified device:
python scripts/tutorials/sim/create_scene.py --headless --num_envs <n> --device <cuda/cpu>
Now that we have a basic understanding of how to create a scene, let’s move on to more advanced topics.
Next Steps#
Creating a soft-body simulation — Add deformable bodies to your scene
Simulating a Robot — Load and control a robot
Simulating a Camera Sensor — Add cameras and capture sensor data
Creating a Basic Environment — Create your first Gymnasium environment
Simulation Manager — Full SimulationManager API reference