Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions embodichain/lab/sim/cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,14 @@ class RigidObjectCfg(ObjectBaseCfg):
body_scale: Union[tuple, list] = (1.0, 1.0, 1.0)
"""Scale of the rigid body in the simulation world frame."""

use_usd_properties: bool = False
"""Whether to use physical properties from USD file instead of config.

When True: Keep all physical properties (drive, physics attrs, etc.) from USD file.
When False (default): Override USD properties with config values (URDF behavior).
Only effective for USD files, ignored for URDF files.
Comment on lines +550 to +554
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RigidObjectCfg.use_usd_properties docstring mentions “URDF behavior” and “drive” properties, but rigid objects are mesh-based and don’t have URDF or joint drives in this codepath. Consider rewording to avoid confusion (e.g., “Only effective for USD mesh files; ignored for non-USD meshes” and remove “drive” wording).

Suggested change
"""Whether to use physical properties from USD file instead of config.
When True: Keep all physical properties (drive, physics attrs, etc.) from USD file.
When False (default): Override USD properties with config values (URDF behavior).
Only effective for USD files, ignored for URDF files.
"""Whether to use physical properties stored in the USD asset instead of config values.
When True: keep physics-related attributes (e.g., collision, mass, physical materials) defined in the USD file.
When False (default): override physics-related attributes from the USD file with values from this config.
Only effective when loading USD mesh assets; ignored for non-USD mesh formats.

Copilot uses AI. Check for mistakes.
"""

def to_dexsim_body_type(self) -> ActorType:
"""Convert the body type to dexsim ActorType."""
if self.body_type == "dynamic":
Expand Down Expand Up @@ -1018,6 +1026,14 @@ class ArticulationCfg(ObjectBaseCfg):
Currently, the uv mapping is computed for each link with projection uv mapping method.
"""

use_usd_properties: bool = False
"""Whether to use physical properties from USD file instead of config.

When True: Keep all physical properties (drive, physics attrs, etc.) from USD file.
When False (default): Override USD properties with config values (URDF behavior).
Only effective for USD files, ignored for URDF files.
"""


@configclass
class RobotCfg(ArticulationCfg):
Expand Down
74 changes: 39 additions & 35 deletions embodichain/lab/sim/objects/articulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -582,41 +582,45 @@ def __init__(
if self.cfg.init_qpos is None:
self.cfg.init_qpos = torch.zeros(self.dof, dtype=torch.float32)

# Set articulation configuration in DexSim
set_dexsim_articulation_cfg(entities, self.cfg)

# Init joint drive parameters.
num_entities = len(entities)
dof = self._data.dof
default_cfg = JointDrivePropertiesCfg()
self.default_joint_damping = torch.full(
(num_entities, dof), default_cfg.damping, dtype=torch.float32, device=device
)
self.default_joint_stiffness = torch.full(
(num_entities, dof),
default_cfg.stiffness,
dtype=torch.float32,
device=device,
)
self.default_joint_max_effort = torch.full(
(num_entities, dof),
default_cfg.max_effort,
dtype=torch.float32,
device=device,
)
self.default_joint_max_velocity = torch.full(
(num_entities, dof),
default_cfg.max_velocity,
dtype=torch.float32,
device=device,
)
self.default_joint_friction = torch.full(
(num_entities, dof),
default_cfg.friction,
dtype=torch.float32,
device=device,
)
self._set_default_joint_drive()
if not cfg.use_usd_properties:
# Set articulation configuration in DexSim
set_dexsim_articulation_cfg(entities, self.cfg)

Comment on lines +585 to +588
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Articulation.__init__ now skips set_dexsim_articulation_cfg(...) when cfg.use_usd_properties is True, regardless of whether the asset was actually loaded from USD. This contradicts ArticulationCfg.use_usd_properties docstring (“ignored for URDF files”) and can lead to URDF-loaded articulations missing expected config application. Consider forcing use_usd_properties=False for non-USD fpath (similar to what load_mesh_objects_from_cfg does for non-USD meshes) or gating this behavior on file extension.

Copilot uses AI. Check for mistakes.
Comment on lines +585 to +588
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are existing articulation/robot tests under tests/sim/objects/; the new use_usd_properties branch isn’t covered. Add a unit test to confirm that drive/physical overrides happen when False and are skipped when True (can be validated with a stub articulation entity that records setter calls).

Copilot uses AI. Check for mistakes.
# Init joint drive parameters.
Comment on lines +585 to +589
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use_usd_properties=True now skips set_dexsim_articulation_cfg(...), but that helper also applies non-USD-physics settings like compute_uv (and clamps inertia). As a result, cfg.compute_uv will be ignored for USD articulations, and inertia clamping won’t run. If the intent is “don’t override physics attrs/drives” but still honor visual/robustness settings, consider splitting set_dexsim_articulation_cfg so only the USD-sensitive pieces are gated.

Suggested change
if not cfg.use_usd_properties:
# Set articulation configuration in DexSim
set_dexsim_articulation_cfg(entities, self.cfg)
# Init joint drive parameters.
# Always apply articulation configuration in DexSim so that visual and
# robustness-related settings (e.g., compute_uv, inertia clamping) are
# consistently honored, even when using USD-authored properties.
set_dexsim_articulation_cfg(entities, self.cfg)
if not cfg.use_usd_properties:
# Init joint drive parameters when not using USD-authored properties.

Copilot uses AI. Check for mistakes.
num_entities = len(entities)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These parts must be set and should not be placed inside the if condition. self._set_default_joint_drive() could be placed here

dof = self._data.dof
default_cfg = JointDrivePropertiesCfg()
self.default_joint_damping = torch.full(
(num_entities, dof),
default_cfg.damping,
dtype=torch.float32,
device=device,
)
self.default_joint_stiffness = torch.full(
(num_entities, dof),
default_cfg.stiffness,
dtype=torch.float32,
device=device,
)
self.default_joint_max_effort = torch.full(
(num_entities, dof),
default_cfg.max_effort,
dtype=torch.float32,
device=device,
)
self.default_joint_max_velocity = torch.full(
(num_entities, dof),
default_cfg.max_velocity,
dtype=torch.float32,
device=device,
)
self.default_joint_friction = torch.full(
(num_entities, dof),
default_cfg.friction,
dtype=torch.float32,
device=device,
)
self._set_default_joint_drive()

self.pk_chain = None
if self.cfg.build_pk_chain:
Expand Down
7 changes: 4 additions & 3 deletions embodichain/lab/sim/objects/rigid_object.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,9 +211,10 @@ def __init__(
self._visual_material: List[VisualMaterialInst] = [None] * len(entities)
self.is_shared_visual_material = False

for entity in entities:
entity.set_body_scale(*cfg.body_scale)
entity.set_physical_attr(cfg.attrs.attr())
if not cfg.use_usd_properties:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also check whether the fpath is USD file.

for entity in entities:
entity.set_body_scale(*cfg.body_scale)
Comment on lines +214 to +216
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With use_usd_properties=True, this skips both set_physical_attr and set_body_scale. The cfg field name/docstring suggests only physics properties should come from USD, but this change also makes cfg.body_scale ineffective for USD assets. Either document that scale will also come from USD, or apply set_body_scale regardless and only skip the physical-attribute override.

Suggested change
if not cfg.use_usd_properties:
for entity in entities:
entity.set_body_scale(*cfg.body_scale)
for entity in entities:
# Always apply configured body scale, even when using USD properties.
entity.set_body_scale(*cfg.body_scale)
# Only override physical attributes from cfg when not using USD properties.
if not cfg.use_usd_properties:

Copilot uses AI. Check for mistakes.
entity.set_physical_attr(cfg.attrs.attr())
Comment on lines +214 to +217
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are existing tests for rigid objects under tests/sim/objects/; this new use_usd_properties behavior isn’t covered. Add a unit test that verifies config-driven physical attributes are applied when use_usd_properties=False and are not overridden when True (can be done with a stub/mocked MeshObject).

Copilot uses AI. Check for mistakes.

if device.type == "cuda":
self._world.update(0.001)
Expand Down
56 changes: 50 additions & 6 deletions embodichain/lab/sim/sim_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -1041,9 +1041,31 @@ def add_articulation(
env_list = [self._env] if len(self._arenas) == 0 else self._arenas
obj_list = []

for env in env_list:
art = env.load_urdf(cfg.fpath)
obj_list.append(art)
is_usd = cfg.fpath.endswith((".usd", ".usda", ".usdc"))
if is_usd:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently add checking for num_envs when file is USD. After we support spawn via cloning, we can remove this.

# TODO: currently not supporting multiple arenas for USD
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

USD import path currently ignores env_list/arenas and always imports into self._env, but the method still proceeds even when self._arenas is non-empty. Since batch entities assume one entity per env, this will silently create an articulation with a single instance in a multi-arena simulation. Add an explicit check (e.g., error if len(env_list) != 1) before importing USD.

Suggested change
# TODO: currently not supporting multiple arenas for USD
# TODO: currently not supporting multiple arenas for USD
if len(env_list) != 1:
logger.log_error(
"USD articulation import currently supports exactly one environment; "
f"got {len(env_list)}. This can happen when using multiple arenas."
)
return None

Copilot uses AI. Check for mistakes.
env = self._env
results = env.import_from_usd_file(cfg.fpath, return_object=True)
print("USD import results:", results)
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid print() in core library code; it will spam stdout in downstream applications. Use the project logger (or log at debug level) for USD import results, or remove the output entirely.

Suggested change
print("USD import results:", results)
logger.log_debug(f"USD import results: {results}")

Copilot uses AI. Check for mistakes.

articulations_found = []
for key, value in results.items():
if isinstance(value, dexsim.engine.Articulation):
articulations_found.append(value)

if len(articulations_found) == 0:
logger.log_error(f"No articulation found in USD file {cfg.fpath}.")
return None
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add_articulation() is annotated to return Articulation, but the new USD branch has return None after logger.log_error(...). Since logger.log_error raises, the return None is unreachable and also misleading for type/contract. Either remove the return None and rely on the exception (consistent with other error paths in this file) or change the API to return Articulation | None and avoid raising in this case.

Suggested change
return None

Copilot uses AI. Check for mistakes.
elif len(articulations_found) > 1:
logger.log_error(
f"Multiple articulations found in USD file {cfg.fpath}. "
)
elif len(articulations_found) == 1:
obj_list.append(articulations_found[0])
else:
for env in env_list:
art = env.load_urdf(cfg.fpath)
obj_list.append(art)

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

Expand Down Expand Up @@ -1109,9 +1131,31 @@ def add_robot(self, cfg: RobotCfg) -> Robot | None:
env_list = [self._env] if len(self._arenas) == 0 else self._arenas
obj_list = []

for env in env_list:
art = env.load_urdf(cfg.fpath)
obj_list.append(art)
is_usd = cfg.fpath.endswith((".usd", ".usda", ".usdc"))
if is_usd:
# TODO: currently not supporting multiple arenas for USD
env = self._env
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same multi-arena issue as add_articulation: USD import always uses self._env, so in multi-arena simulations this will create a robot batch with only one instance. Add an explicit len(env_list) == 1 guard (or implement cloning into each arena) before allowing USD import.

Suggested change
env = self._env
if len(env_list) != 1:
logger.log_error(
"USD robot import currently supports only a single arena; "
f"got {len(env_list)} arenas for file {cfg.fpath}."
)
return None
env = env_list[0]

Copilot uses AI. Check for mistakes.
results = env.import_from_usd_file(cfg.fpath, return_object=True)
print("USD import results:", results)
Comment on lines 1134 to 1139
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to add_articulation(), the USD import path in add_robot() doesn’t support multiple arenas but doesn’t enforce it: it always imports into self._env even if self._arenas is populated. Add an explicit guard (raise when len(self._arenas) > 0) to prevent creating robots with a batch size that doesn’t match the simulation’s number of envs.

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid print() in library code here as well; use the project logger (preferably debug level) or remove the output.

Suggested change
print("USD import results:", results)
logger.log_debug(f"USD import results: {results}")

Copilot uses AI. Check for mistakes.

articulations_found = []
for key, value in results.items():
if isinstance(value, dexsim.engine.Articulation):
articulations_found.append(value)

if len(articulations_found) == 0:
logger.log_error(f"No articulation found in USD file {cfg.fpath}.")
return None
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In add_robot(), the USD branch includes return None after logger.log_error(...). Because logger.log_error raises, this return None is dead code and makes the control flow harder to read. Prefer either raising without a return (consistent with existing patterns here) or replacing the error with a non-raising log if you truly want to return None.

Suggested change
return None

Copilot uses AI. Check for mistakes.
elif len(articulations_found) > 1:
Comment on lines +1146 to +1149
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logger.log_error(...) raises, so the subsequent return None is unreachable. Since add_robot already returns Robot | None, consider either (a) returning None without raising (use logger.log_warning/log_info), or (b) remove the return None and consistently raise on failure.

Copilot uses AI. Check for mistakes.
logger.log_error(
f"Multiple articulations found in USD file {cfg.fpath}. "
)
elif len(articulations_found) == 1:
obj_list.append(articulations_found[0])
else:
for env in env_list:
art = env.load_urdf(cfg.fpath)
obj_list.append(art)

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

Expand Down
22 changes: 22 additions & 0 deletions embodichain/lab/sim/utility/sim_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,28 @@ def load_mesh_objects_from_cfg(

compute_uv = cfg.shape.compute_uv

is_usd = fpath.endswith((".usd", ".usda", ".usdc"))
if is_usd:
# TODO: currently not supporting multiple arenas for USD
_env: dexsim.environment.Env = dexsim.default_world().get_env()
results = _env.import_from_usd_file(fpath, return_object=True)
print(f"import usd result: {results}")
Comment on lines +224 to +227
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

USD import bypasses the provided env_list by calling dexsim.default_world().get_env(), which can import into a different world/env than the SimulationManager passed into this function. Use env_list[0] (and explicitly error if len(env_list) != 1 since USD multi-arena isn’t supported yet) and avoid print() in library code (use the project logger or remove).

Suggested change
# TODO: currently not supporting multiple arenas for USD
_env: dexsim.environment.Env = dexsim.default_world().get_env()
results = _env.import_from_usd_file(fpath, return_object=True)
print(f"import usd result: {results}")
# USD import currently supports exactly one arena/env.
if len(env_list) != 1:
raise ValueError(
f"USD import currently supports exactly one arena/env, but got {len(env_list)}."
)
_env = env_list[0]
results = _env.import_from_usd_file(fpath, return_object=True)

Copilot uses AI. Check for mistakes.

rigidbodys_found = []
for key, value in results.items():
if isinstance(value, dexsim.cuda.pybind.models.MeshObject):
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The USD import path filters returned objects using isinstance(value, dexsim.cuda.pybind.models.MeshObject). This can break on CPU-only installs/builds where dexsim.cuda may not exist. Since this module already imports MeshObject from dexsim.models, prefer checking against MeshObject (or another CPU-safe base type) instead of a CUDA-specific pybind class.

Suggested change
if isinstance(value, dexsim.cuda.pybind.models.MeshObject):
if isinstance(value, MeshObject):

Copilot uses AI. Check for mistakes.
rigidbodys_found.append(value)
if len(rigidbodys_found) == 0:
logger.log_error(f"No rigid body found in USD file: {fpath}")
elif len(rigidbodys_found) > 1:
logger.log_error(f"Multiple rigid bodies found in USD file: {fpath}.")
elif len(rigidbodys_found) == 1:
obj_list.append(rigidbodys_found[0])
return obj_list
else:
# non-usd file does not support this option, will be ignored if set.
cfg.use_usd_properties = False
Comment on lines +240 to +242
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

load_mesh_objects_from_cfg mutates the caller’s config (cfg.use_usd_properties = False) for non-USD meshes. This side effect can leak out to other code paths that reuse the same cfg instance. Prefer treating this as a local effective flag (e.g., use_usd_properties_effective = ...) rather than modifying cfg in-place.

Copilot uses AI. Check for mistakes.

for i, env in enumerate(env_list):
if max_convex_hull_num > 1:
obj = env.load_actor_with_coacd(
Expand Down
168 changes: 168 additions & 0 deletions scripts/tutorials/sim/import_usd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# ----------------------------------------------------------------------------
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also add docs for usd

# Copyright (c) 2021-2025 DexForce Technology Co., Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ----------------------------------------------------------------------------

"""
This script demonstrates how to create a simulation scene using SimulationManager.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change description

It shows the basic setup of simulation context, adding objects, and sensors.
"""

import argparse
import time

from embodichain.lab.sim import SimulationManager, SimulationManagerCfg
from embodichain.lab.sim.cfg import RigidBodyAttributesCfg
from embodichain.lab.sim.shapes import CubeCfg, MeshCfg
from embodichain.lab.sim.objects import (
RigidObject,
RigidObjectCfg,
ArticulationCfg,
Articulation,
)
from dexsim.utility.path import get_resources_data_path
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import of 'get_resources_data_path' is not used.

Suggested change
from dexsim.utility.path import get_resources_data_path

Copilot uses AI. Check for mistakes.


def main():
"""Main function to create and run the simulation scene."""

# Parse command line arguments
parser = argparse.ArgumentParser(
description="Create a simulation scene with SimulationManager"
)
parser.add_argument(
"--headless",
action="store_true",
default=False,
help="Run simulation in headless mode",
)
parser.add_argument(
"--device", type=str, default="cpu", help="Simulation device (cuda or cpu)"
)
parser.add_argument(
"--enable_rt",
action="store_true",
default=True,
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--enable_rt is declared with action='store_true' but also default=True, which makes the flag always True and provides no way to disable ray tracing from the CLI. Set the default to False (consistent with other tutorials) or switch to a --disable_rt/store_false pattern.

Suggested change
default=True,
default=False,

Copilot uses AI. Check for mistakes.
help="Enable ray tracing for better visuals",
)
Comment on lines +55 to +58
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--enable_rt is declared with action='store_true' but also default=True, which makes the flag impossible to disable from the CLI (it will always be True). Use default=False (store_true) or switch to a --disable_rt (store_false) pattern so users can actually control ray tracing.

Suggested change
action="store_true",
default=True,
help="Enable ray tracing for better visuals",
)
dest="enable_rt",
action="store_true",
help="Enable ray tracing for better visuals",
)
parser.add_argument(
"--disable_rt",
dest="enable_rt",
action="store_false",
help="Disable ray tracing",
)
parser.set_defaults(enable_rt=True)

Copilot uses AI. Check for mistakes.
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,
enable_rt=args.enable_rt, # Enable ray tracing for better visuals
num_envs=1,
arena_space=3.0,
)

# Create the simulation instance
sim = SimulationManager(sim_cfg)
# Open window when the scene has been set up
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment says the window is opened after the scene is set up, but open_window() is called before adding any objects. Either move the window-opening block to after scene creation or adjust the comment to match the actual behavior.

Suggested change
# Open window when the scene has been set up
# Open window if not running in headless mode

Copilot uses AI. Check for mistakes.
if not args.headless:
sim.open_window()

cube: RigidObject = sim.add_rigid_object(
cfg=RigidObjectCfg(
uid="cube",
shape=CubeCfg(size=[0.1, 0.1, 0.1]),
body_type="dynamic",
attrs=RigidBodyAttributesCfg(
mass=1.0,
dynamic_friction=0.5,
static_friction=0.5,
restitution=0.1,
),
init_pos=[0.0, 0.0, 1.0],
)
)

usdpath = "/home/xiemh/model/004_sugar_box/004_sugar_box_xmh.usda"
sugar_box: RigidObject = sim.add_rigid_object(
cfg=RigidObjectCfg(
uid="sugar_box",
shape=MeshCfg(fpath=usdpath),
body_type="dynamic",
init_pos=[0.2, 0.2, 1.0],
use_usd_properties=True,
)
)

# Add objects to the scene
h1: Articulation = sim.add_articulation(
cfg=ArticulationCfg(
uid="h1",
# fpath="/home/xiemh/model/Collected_ur10/ur10.usd",
fpath="/home/xiemh/model/Collected_h1/h1.usda",
build_pk_chain=False,
init_pos=[-0.2, -0.2, 1.0],
use_usd_properties=False,
)
Comment on lines +94 to +114
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tutorial hard-codes absolute local USD paths (e.g., /home/...). This will break for anyone else and for CI/doc builds. Prefer accepting these as CLI args and/or building paths from packaged assets (you already import get_resources_data_path, but it’s unused).

Copilot uses AI. Check for mistakes.
)

print("[INFO]: Scene setup complete!")
print("[INFO]: Press Ctrl+C to stop the simulation")

# Run the simulation
run_simulation(sim)


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)
time.sleep(0.03) # Sleep to limit update rate (optional)
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}")
Comment on lines +146 to +155
Copy link

Copilot AI Feb 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable fps is not used.

Suggested change
# 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}")
# Periodically update timing counters (FPS computation removed)
if step_count % 100 == 0:
current_time = time.time()

Copilot uses AI. Check for mistakes.
last_time = current_time
last_step = step_count

except KeyboardInterrupt:
print("\n[INFO]: Stopping simulation...")
finally:
# Clean up resources
sim.destroy()
print("[INFO]: Simulation terminated successfully")


if __name__ == "__main__":
main()