Skip to content

Commit 44331b8

Browse files
author
xiemenghong
committed
usd example
1 parent 3eb881e commit 44331b8

6 files changed

Lines changed: 293 additions & 45 deletions

File tree

embodichain/lab/sim/cfg.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,14 @@ class RigidObjectCfg(ObjectBaseCfg):
546546
body_scale: Union[tuple, list] = (1.0, 1.0, 1.0)
547547
"""Scale of the rigid body in the simulation world frame."""
548548

549+
use_usd_properties: bool = False
550+
"""Whether to use physical properties from USD file instead of config.
551+
552+
When True: Keep all physical properties (drive, physics attrs, etc.) from USD file.
553+
When False (default): Override USD properties with config values (URDF behavior).
554+
Only effective for USD files, ignored for URDF files.
555+
"""
556+
549557
def to_dexsim_body_type(self) -> ActorType:
550558
"""Convert the body type to dexsim ActorType."""
551559
if self.body_type == "dynamic":
@@ -1017,6 +1025,14 @@ class ArticulationCfg(ObjectBaseCfg):
10171025
10181026
Currently, the uv mapping is computed for each link with projection uv mapping method.
10191027
"""
1028+
1029+
use_usd_properties: bool = False
1030+
"""Whether to use physical properties from USD file instead of config.
1031+
1032+
When True: Keep all physical properties (drive, physics attrs, etc.) from USD file.
1033+
When False (default): Override USD properties with config values (URDF behavior).
1034+
Only effective for USD files, ignored for URDF files.
1035+
"""
10201036

10211037

10221038
@configclass

embodichain/lab/sim/objects/articulation.py

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -581,42 +581,43 @@ def __init__(
581581
self.cfg: ArticulationCfg
582582
if self.cfg.init_qpos is None:
583583
self.cfg.init_qpos = torch.zeros(self.dof, dtype=torch.float32)
584-
585-
# Set articulation configuration in DexSim
586-
set_dexsim_articulation_cfg(entities, self.cfg)
587-
588-
# Init joint drive parameters.
589-
num_entities = len(entities)
590-
dof = self._data.dof
591-
default_cfg = JointDrivePropertiesCfg()
592-
self.default_joint_damping = torch.full(
593-
(num_entities, dof), default_cfg.damping, dtype=torch.float32, device=device
594-
)
595-
self.default_joint_stiffness = torch.full(
596-
(num_entities, dof),
597-
default_cfg.stiffness,
598-
dtype=torch.float32,
599-
device=device,
600-
)
601-
self.default_joint_max_effort = torch.full(
602-
(num_entities, dof),
603-
default_cfg.max_effort,
604-
dtype=torch.float32,
605-
device=device,
606-
)
607-
self.default_joint_max_velocity = torch.full(
608-
(num_entities, dof),
609-
default_cfg.max_velocity,
610-
dtype=torch.float32,
611-
device=device,
612-
)
613-
self.default_joint_friction = torch.full(
614-
(num_entities, dof),
615-
default_cfg.friction,
616-
dtype=torch.float32,
617-
device=device,
618-
)
619-
self._set_default_joint_drive()
584+
585+
if not cfg.use_usd_properties:
586+
# Set articulation configuration in DexSim
587+
set_dexsim_articulation_cfg(entities, self.cfg)
588+
589+
# Init joint drive parameters.
590+
num_entities = len(entities)
591+
dof = self._data.dof
592+
default_cfg = JointDrivePropertiesCfg()
593+
self.default_joint_damping = torch.full(
594+
(num_entities, dof), default_cfg.damping, dtype=torch.float32, device=device
595+
)
596+
self.default_joint_stiffness = torch.full(
597+
(num_entities, dof),
598+
default_cfg.stiffness,
599+
dtype=torch.float32,
600+
device=device,
601+
)
602+
self.default_joint_max_effort = torch.full(
603+
(num_entities, dof),
604+
default_cfg.max_effort,
605+
dtype=torch.float32,
606+
device=device,
607+
)
608+
self.default_joint_max_velocity = torch.full(
609+
(num_entities, dof),
610+
default_cfg.max_velocity,
611+
dtype=torch.float32,
612+
device=device,
613+
)
614+
self.default_joint_friction = torch.full(
615+
(num_entities, dof),
616+
default_cfg.friction,
617+
dtype=torch.float32,
618+
device=device,
619+
)
620+
self._set_default_joint_drive()
620621

621622
self.pk_chain = None
622623
if self.cfg.build_pk_chain:

embodichain/lab/sim/objects/rigid_object.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,10 @@ def __init__(
211211
self._visual_material: List[VisualMaterialInst] = [None] * len(entities)
212212
self.is_shared_visual_material = False
213213

214-
for entity in entities:
215-
entity.set_body_scale(*cfg.body_scale)
216-
entity.set_physical_attr(cfg.attrs.attr())
214+
if not cfg.use_usd_properties:
215+
for entity in entities:
216+
entity.set_body_scale(*cfg.body_scale)
217+
entity.set_physical_attr(cfg.attrs.attr())
217218

218219
if device.type == "cuda":
219220
self._world.update(0.001)

embodichain/lab/sim/sim_manager.py

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,9 +1030,31 @@ def add_articulation(
10301030
env_list = [self._env] if len(self._arenas) == 0 else self._arenas
10311031
obj_list = []
10321032

1033-
for env in env_list:
1034-
art = env.load_urdf(cfg.fpath)
1035-
obj_list.append(art)
1033+
is_usd = cfg.fpath.endswith((".usd", ".usda", ".usdc"))
1034+
if is_usd:
1035+
# TODO: currently not supporting multiple arenas for USD
1036+
env= self._env
1037+
results = env.import_from_usd_file(cfg.fpath, return_object=True)
1038+
print("USD import results:", results)
1039+
1040+
articulations_found = []
1041+
for key, value in results.items():
1042+
if isinstance(value, dexsim.engine.Articulation):
1043+
articulations_found.append(value)
1044+
1045+
if len(articulations_found) == 0:
1046+
logger.log_error(f"No articulation found in USD file {cfg.fpath}.")
1047+
return None
1048+
elif len(articulations_found) > 1:
1049+
logger.log_error(
1050+
f"Multiple articulations found in USD file {cfg.fpath}. "
1051+
)
1052+
elif len(articulations_found) == 1:
1053+
obj_list.append(articulations_found[0])
1054+
else:
1055+
for env in env_list:
1056+
art = env.load_urdf(cfg.fpath)
1057+
obj_list.append(art)
10361058

10371059
articulation = Articulation(cfg=cfg, entities=obj_list, device=self.device)
10381060

@@ -1092,9 +1114,31 @@ def add_robot(self, cfg: RobotCfg) -> Robot | None:
10921114
env_list = [self._env] if len(self._arenas) == 0 else self._arenas
10931115
obj_list = []
10941116

1095-
for env in env_list:
1096-
art = env.load_urdf(cfg.fpath)
1097-
obj_list.append(art)
1117+
is_usd = cfg.fpath.endswith((".usd", ".usda", ".usdc"))
1118+
if is_usd:
1119+
# TODO: currently not supporting multiple arenas for USD
1120+
env= self._env
1121+
results = env.import_from_usd_file(cfg.fpath, return_object=True)
1122+
print("USD import results:", results)
1123+
1124+
articulations_found = []
1125+
for key, value in results.items():
1126+
if isinstance(value, dexsim.engine.Articulation):
1127+
articulations_found.append(value)
1128+
1129+
if len(articulations_found) == 0:
1130+
logger.log_error(f"No articulation found in USD file {cfg.fpath}.")
1131+
return None
1132+
elif len(articulations_found) > 1:
1133+
logger.log_error(
1134+
f"Multiple articulations found in USD file {cfg.fpath}. "
1135+
)
1136+
elif len(articulations_found) == 1:
1137+
obj_list.append(articulations_found[0])
1138+
else:
1139+
for env in env_list:
1140+
art = env.load_urdf(cfg.fpath)
1141+
obj_list.append(art)
10981142

10991143
robot = Robot(cfg=cfg, entities=obj_list, device=self.device)
11001144

embodichain/lab/sim/utility/sim_utils.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,28 @@ def load_mesh_objects_from_cfg(
219219

220220
compute_uv = cfg.shape.compute_uv
221221

222+
is_usd = fpath.endswith((".usd", ".usda", ".usdc"))
223+
if is_usd:
224+
# TODO: currently not supporting multiple arenas for USD
225+
_env:dexsim.environment.Env = dexsim.default_world().get_env()
226+
results = _env.import_from_usd_file(fpath,return_object=True)
227+
print(f"import usd result: {results}")
228+
229+
rigidbodys_found=[]
230+
for key,value in results.items():
231+
if isinstance(value, dexsim.cuda.pybind.models.MeshObject):
232+
rigidbodys_found.append(value)
233+
if len(rigidbodys_found)==0:
234+
logger.log_error(f"No rigid body found in USD file: {fpath}")
235+
elif len(rigidbodys_found)>1:
236+
logger.log_error(f"Multiple rigid bodies found in USD file: {fpath}.")
237+
elif len(rigidbodys_found)==1:
238+
obj_list.append(rigidbodys_found[0])
239+
return obj_list
240+
else:
241+
# non-usd file does not support this option, will be ignored if set.
242+
cfg.use_usd_properties=False
243+
222244
for i, env in enumerate(env_list):
223245
if max_convex_hull_num > 1:
224246
obj = env.load_actor_with_coacd(
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
# ----------------------------------------------------------------------------
2+
# Copyright (c) 2021-2025 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+
"""
18+
This script demonstrates how to create a simulation scene using SimulationManager.
19+
It shows the basic setup of simulation context, adding objects, and sensors.
20+
"""
21+
22+
import argparse
23+
import time
24+
25+
from embodichain.lab.sim import SimulationManager, SimulationManagerCfg
26+
from embodichain.lab.sim.cfg import RigidBodyAttributesCfg
27+
from embodichain.lab.sim.shapes import CubeCfg, MeshCfg
28+
from embodichain.lab.sim.objects import RigidObject, RigidObjectCfg,ArticulationCfg,Articulation
29+
from dexsim.utility.path import get_resources_data_path
30+
31+
32+
def main():
33+
"""Main function to create and run the simulation scene."""
34+
35+
# Parse command line arguments
36+
parser = argparse.ArgumentParser(
37+
description="Create a simulation scene with SimulationManager"
38+
)
39+
parser.add_argument(
40+
"--headless",
41+
action="store_true",
42+
default=False,
43+
help="Run simulation in headless mode",
44+
)
45+
parser.add_argument(
46+
"--device", type=str, default="cpu", help="Simulation device (cuda or cpu)"
47+
)
48+
parser.add_argument(
49+
"--enable_rt",
50+
action="store_true",
51+
default=True,
52+
help="Enable ray tracing for better visuals",
53+
)
54+
args = parser.parse_args()
55+
56+
# Configure the simulation
57+
sim_cfg = SimulationManagerCfg(
58+
width=1920,
59+
height=1080,
60+
headless=True,
61+
physics_dt=1.0 / 100.0, # Physics timestep (100 Hz)
62+
sim_device=args.device,
63+
enable_rt=args.enable_rt, # Enable ray tracing for better visuals
64+
num_envs=1,
65+
arena_space=3.0,
66+
)
67+
68+
# Create the simulation instance
69+
sim = SimulationManager(sim_cfg)
70+
# Open window when the scene has been set up
71+
if not args.headless:
72+
sim.open_window()
73+
74+
75+
cube: RigidObject = sim.add_rigid_object(
76+
cfg=RigidObjectCfg(
77+
uid="cube",
78+
shape=CubeCfg(size=[0.1, 0.1, 0.1]),
79+
body_type="dynamic",
80+
attrs=RigidBodyAttributesCfg(
81+
mass=1.0,
82+
dynamic_friction=0.5,
83+
static_friction=0.5,
84+
restitution=0.1,
85+
),
86+
init_pos=[0.0, 0.0, 1.0],
87+
)
88+
)
89+
90+
usdpath="/home/xiemh/model/004_sugar_box/004_sugar_box_xmh.usda"
91+
sugar_box: RigidObject = sim.add_rigid_object(
92+
cfg=RigidObjectCfg(
93+
uid="sugar_box",
94+
shape=MeshCfg(fpath=usdpath),
95+
body_type="dynamic",
96+
init_pos=[0.2, 0.2, 1.0],
97+
use_usd_properties=True,
98+
)
99+
)
100+
101+
# Add objects to the scene
102+
h1 :Articulation= sim.add_articulation(
103+
cfg=ArticulationCfg(
104+
uid="h1",
105+
# fpath="/home/xiemh/model/Collected_ur10/ur10.usd",
106+
fpath="/home/xiemh/model/Collected_h1/h1.usda",
107+
build_pk_chain=False,
108+
init_pos=[-0.2, -0.2, 1.0],
109+
use_usd_properties=False,
110+
)
111+
)
112+
113+
print("[INFO]: Scene setup complete!")
114+
print("[INFO]: Press Ctrl+C to stop the simulation")
115+
116+
# Run the simulation
117+
run_simulation(sim)
118+
119+
120+
def run_simulation(sim: SimulationManager):
121+
"""Run the simulation loop.
122+
123+
Args:
124+
sim: The SimulationManager instance to run
125+
"""
126+
127+
# Initialize GPU physics if using CUDA
128+
if sim.is_use_gpu_physics:
129+
sim.init_gpu_physics()
130+
131+
step_count = 0
132+
133+
try:
134+
last_time = time.time()
135+
last_step = 0
136+
while True:
137+
# Update physics simulation
138+
sim.update(step=1)
139+
time.sleep(0.03) # Sleep to limit update rate (optional)
140+
step_count += 1
141+
142+
# Print FPS every second
143+
if step_count % 100 == 0:
144+
current_time = time.time()
145+
elapsed = current_time - last_time
146+
fps = (
147+
sim.num_envs * (step_count - last_step) / elapsed
148+
if elapsed > 0
149+
else 0
150+
)
151+
# print(f"[INFO]: Simulation step: {step_count}, FPS: {fps:.2f}")
152+
last_time = current_time
153+
last_step = step_count
154+
155+
except KeyboardInterrupt:
156+
print("\n[INFO]: Stopping simulation...")
157+
finally:
158+
# Clean up resources
159+
sim.destroy()
160+
print("[INFO]: Simulation terminated successfully")
161+
162+
163+
if __name__ == "__main__":
164+
main()

0 commit comments

Comments
 (0)