Rigid object group tutorial#
This tutorial shows how to create and use a RigidObjectGroup in SimulationManager.
It follows the style used in the create_scene tutorial and references the
example script located in scripts/tutorials/sim/create_rigid_object_group.py.
The Code#
The tutorial corresponds to the create_rigid_object_group.py script in the
scripts/tutorials/sim directory.
Code for create_rigid_object_group.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 rigid object group using SimulationManager.
19"""
20
21from __future__ import annotations
22
23import argparse
24import time
25from embodichain.cli.sim import add_sim_args_to_parser
26
27
28def build_parser() -> argparse.ArgumentParser:
29 """Build CLI options without initializing simulation resources."""
30 parser = argparse.ArgumentParser(
31 description="Create a simulation scene with SimulationManager"
32 )
33 add_sim_args_to_parser(parser)
34 return parser
35
36
37if __name__ == "__main__":
38 # Parse before importing optional simulation/planning dependencies.
39 _cli_args = build_parser().parse_args()
40
41
42from embodichain.lab.sim import SimulationManager, SimulationManagerCfg
43from embodichain.lab.sim.cfg import (
44 RigidBodyPhysicsCfg,
45 RenderCfg,
46 physics_cfg_for_backend,
47)
48from embodichain.lab.visualization import visualization_cfg_from_args
49from embodichain.lab.sim.shapes import CubeCfg
50from embodichain.lab.sim.objects import (
51 RigidObjectGroup,
52 RigidObjectGroupCfg,
53 RigidObjectCfg,
54)
55
56
57def main(args: argparse.Namespace | None = None) -> None:
58 """Main function to create and run the simulation scene."""
59
60 # Parse command line arguments
61 parser = build_parser()
62 if args is None:
63 args = parser.parse_args()
64
65 # Configure the simulation
66 sim_cfg = SimulationManagerCfg(
67 width=1920,
68 height=1080,
69 headless=True,
70 physics_dt=1.0 / 100.0, # Physics timestep (100 Hz)
71 device=args.device,
72 render_cfg=RenderCfg(
73 renderer=args.renderer
74 ), # Enable ray tracing for better visuals
75 physics_cfg=physics_cfg_for_backend(args.physics),
76 num_envs=args.num_envs,
77 arena_space=3.0,
78 visualization=visualization_cfg_from_args(args),
79 )
80
81 # Create the simulation instance
82 sim = SimulationManager(sim_cfg)
83
84 physics_attrs = RigidBodyPhysicsCfg.from_dict(
85 {
86 "mass_props": {"mass": 1.0},
87 "material_props": {
88 "dynamic_friction": 0.5,
89 "static_friction": 0.5,
90 "restitution": 0.1,
91 },
92 }
93 )
94
95 # Add objects to the scene
96 obj_group: RigidObjectGroup = sim.add_rigid_object_group(
97 cfg=RigidObjectGroupCfg(
98 uid="obj_group",
99 rigid_objects={
100 "cube_1": RigidObjectCfg(
101 uid="cube_1",
102 shape=CubeCfg(size=[0.1, 0.1, 0.1]),
103 attrs=physics_attrs,
104 init_pos=[0.0, 0.0, 1.0],
105 ),
106 "cube_2": RigidObjectCfg(
107 uid="cube_2",
108 shape=CubeCfg(size=[0.2, 0.2, 0.2]),
109 attrs=physics_attrs,
110 init_pos=[0.5, 0.0, 1.0],
111 ),
112 "cube_3": RigidObjectCfg(
113 uid="cube_3",
114 shape=CubeCfg(size=[0.3, 0.3, 0.3]),
115 attrs=physics_attrs,
116 init_pos=[-0.5, 0.0, 1.0],
117 ),
118 },
119 )
120 )
121
122 print("[INFO]: Scene setup complete!")
123 print(f"[INFO]: Running simulation with {args.num_envs} environment(s)")
124 print("[INFO]: Press Ctrl+C to stop the simulation")
125
126 # Open window when the scene has been set up
127 sim.prepare()
128 if not args.headless:
129 sim.open_window()
130
131 # Run the simulation
132 run_simulation(sim)
133
134
135def run_simulation(sim: SimulationManager):
136 """Run the simulation loop.
137
138 Args:
139 sim: The SimulationManager instance to run
140 """
141
142 step_count = 0
143
144 try:
145 last_time = time.time()
146 last_step = 0
147 while True:
148 # Update physics simulation
149 sim.update(step=1)
150 step_count += 1
151
152 # Print FPS every second
153 if step_count % 100 == 0:
154 current_time = time.time()
155 elapsed = current_time - last_time
156 fps = (
157 sim.num_envs * (step_count - last_step) / elapsed
158 if elapsed > 0
159 else 0
160 )
161 print(f"[INFO]: Simulation step: {step_count}, FPS: {fps:.2f}")
162 last_time = current_time
163 last_step = step_count
164
165 except KeyboardInterrupt:
166 print("\n[INFO]: Stopping simulation...")
167 finally:
168 # Clean up resources
169 sim.destroy()
170 print("[INFO]: Simulation terminated successfully")
171
172
173if __name__ == "__main__":
174 main(_cli_args)
The Code Explained#
Adding a RigidObjectGroup#
The key part of the tutorial demonstrates creating a RigidObjectGroup via
sim.add_rigid_object_group. The group is configured with a mapping of
object UIDs to RigidObjectCfg entries. Each entry defines a shape
(here CubeCfg), physics attributes, and initial pose.
obj_group: RigidObjectGroup = sim.add_rigid_object_group(
cfg=RigidObjectGroupCfg(
uid="obj_group",
rigid_objects={
"cube_1": RigidObjectCfg(
uid="cube_1",
shape=CubeCfg(size=[0.1, 0.1, 0.1]),
attrs=physics_attrs,
init_pos=[0.0, 0.0, 1.0],
),
"cube_2": RigidObjectCfg(
uid="cube_2",
shape=CubeCfg(size=[0.2, 0.2, 0.2]),
attrs=physics_attrs,
init_pos=[0.5, 0.0, 1.0],
),
"cube_3": RigidObjectCfg(
uid="cube_3",
shape=CubeCfg(size=[0.3, 0.3, 0.3]),
attrs=physics_attrs,
init_pos=[-0.5, 0.0, 1.0],
),
},
)
)
print("[INFO]: Scene setup complete!")
Running the tutorial#
To run the script from the repository root:
python scripts/tutorials/sim/create_rigid_object_group.py
You can pass flags such as --headless, --num_envs <n>, and
--device <cpu|cuda> to customize the run.
Use --viser to publish every constituent object in the group to the browser:
python scripts/tutorials/sim/create_rigid_object_group.py --viser
Each group member has its own pose and browser node. Shared geometry remains batched by the Viser backend. See Browser visualization with Viser for server and environment-selection options.