Skip to content
Merged
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
25 changes: 9 additions & 16 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -969,9 +969,8 @@ jobs:
performance-smoke:
name: performance-smoke-benchmarks
runs-on: [self-hosted, gpu]
# Ceiling is the sum of each leg's own bench_timeout_s x 3 + buffer
# Individual attempts are still bound tightly by `timeout` inside the loop.
timeout-minutes: 510
# Four legs x three samples, including one retry each: 372 minutes + setup/comparison buffer.
timeout-minutes: 450
needs: [build, config]
# Pull requests and manual dispatches run in gate mode. A push runs only on develop,
# where it also records a baseline; pushes to main and release/** skip this job.
Expand All @@ -991,19 +990,13 @@ jobs:
dockerfile-path: docker/Dockerfile.base
cache-tag: cache-base

# One row per combination: name|task|num_envs|bench_timeout_s|args
# Kit-free combinations only: name|task|num_envs|bench_timeout_s|args
- name: Define benchmark matrix
run: |
cat > benchmark-legs.tsv <<'EOF'
cartpole-physx|Isaac-Cartpole-Direct|4096|600|
cartpole-newton|Isaac-Cartpole-Direct|4096|600|physics=newton_mjwarp
gear-mesh-physx|IsaacContrib-Factory-GearMesh-Direct|512|900|
shadow-camera-physx-rtx|IsaacContrib-Reorient-Cube-Shadow-Camera-Benchmark-Direct|512|1200|renderer=isaacsim_rtx
shadow-camera-physx-newton-renderer|IsaacContrib-Reorient-Cube-Shadow-Camera-Benchmark-Direct|512|1200|renderer=newton_renderer
shadow-camera-newton-rtx|IsaacContrib-Reorient-Cube-Shadow-Camera-Benchmark-Direct|512|1200|physics=newton_mjwarp renderer=isaacsim_rtx
shadow-camera-newton-renderer|IsaacContrib-Reorient-Cube-Shadow-Camera-Benchmark-Direct|512|1200|physics=newton_mjwarp renderer=newton_renderer
shadow-camera-ovphysx-newton|IsaacContrib-Reorient-Cube-Shadow-Camera-Benchmark-Direct|512|1200|physics=ovphysx renderer=newton_renderer
g1-physx|Isaac-Velocity-Flat-G1|512|720|
g1-newton|Isaac-Velocity-Flat-G1|512|720|physics=newton_mjwarp
EOF

Expand All @@ -1027,7 +1020,6 @@ jobs:
perf-jit-warp${{ steps.warp_version.outputs.value }}-

- name: Run runtime benchmarks
id: runtime_benchmark
env:
CI_IMAGE_TAG: ${{ needs.config.outputs.ci_image_tag }}
run: |
Expand All @@ -1049,9 +1041,6 @@ jobs:
container="performance-smoke-${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}-${leg}-${sample}-${attempt}"
cleanup_container
timeout "${bench_timeout_s}" docker run --name "$container" --gpus all --network=host --ipc=host \
-e OMNI_KIT_ACCEPT_EULA=yes \
-e ACCEPT_EULA=Y \
-e ISAAC_SIM_HEADLESS=1 \
-e WARP_CACHE_PATH=/tmp/jit-cache/warp \
-e CUDA_CACHE_PATH=/tmp/jit-cache/nv \
-v "${GITHUB_WORKSPACE}/jit-cache:/tmp/jit-cache" \
Expand Down Expand Up @@ -1100,8 +1089,12 @@ jobs:
fi
fi
done
echo "$([ "$leg_ok" = true ] && echo ok || echo failed)" > "benchmark-output/${leg}/status"
[ "$leg_ok" = true ] || failed_legs+=("$leg")
if [ "$leg_ok" = true ]; then
echo ok > "benchmark-output/${leg}/status"
else
echo failed > "benchmark-output/${leg}/status"
failed_legs+=("$leg")
fi
echo "::endgroup::"
done < benchmark-legs.tsv

Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ Guidelines for modifications:
* Yuguo Shan
* Yujian Zhang
* Yun Liu
* Yusuf Guenena
* YuTeh Shen
* Zehao Wang
* Zeng Qingcheng
Expand Down
6 changes: 2 additions & 4 deletions docs/source/_static/css/environment-browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,13 @@
["Isaac-Reach-Franka", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "diffik,diffik_abs,joint_pos,newton_ik", "tasks/manipulation/franka_reach.jpg", true, {"*": ["joint_pos"]}],
["Isaac-Reach-Franka-OSC", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "diffik_abs", "tasks/manipulation/franka_reach.jpg", false, {"*": ["diffik_abs"]}],
["Isaac-Reach-UR10", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "", "tasks/manipulation/ur10_reach.jpg", true],
["Isaac-RenderBenchmark-Franka-Cabinet", "", "isaacsim_physx,newton_mjwarp", "isaacsim_rtx,newton_renderer,ovrtx", "albedo,depth,rgb,simple_shading_constant_diffuse,simple_shading_diffuse_mdl,simple_shading_full_mdl", "", false, {"*": ["rgb"]}],
["Isaac-RenderBenchmark-Franka-Cabinet", "", "isaacsim_physx,newton_mjwarp,ovphysx", "isaacsim_rtx,newton_renderer,ovrtx", "albedo,depth,rgb,simple_shading_constant_diffuse,simple_shading_diffuse_mdl,simple_shading_full_mdl", "", false, {"*": ["rgb"]}],
["Isaac-Reorient-Cube-Allegro-Direct", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "", "tasks/manipulation/allegro_cube.jpg", true],
["Isaac-Reorient-Cube-Allegro", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "randomized,reset_only", "tasks/manipulation/allegro_cube.jpg", false, {"*": ["reset_only"]}],
["Isaac-Reorient-Cube-Shadow-Direct", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "", "tasks/manipulation/shadow_cube.jpg"],
["Isaac-Reorient-Cube-Shadow", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "asymmetric,randomized"],
["Isaac-Reorient-Cube-Shadow-Camera-Direct", "rl_games,rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "isaacsim_rtx,newton_renderer,ovrtx", "albedo,depth,full,rgb,semantic_segmentation,simple_shading_constant_diffuse,simple_shading_diffuse_mdl,simple_shading_full_mdl", "tasks/manipulation/shadow_cube.jpg", false, {"*": ["full"]}],
["Isaac-Reorient-Cube-Shadow-Camera", "rl_games,rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "isaacsim_rtx,newton_renderer,ovrtx", "albedo,depth,full,randomized,rgb,semantic_segmentation,simple_shading_constant_diffuse,simple_shading_diffuse_mdl,simple_shading_full_mdl", "", false, {"*": ["full"]}],
["Isaac-Reorient-Franka", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "cube,shapes", "", false, {"*": ["shapes"]}],
["Isaac-Reorient-KukaAllegro", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "cube,shapes", "tasks/manipulation/kuka_allegro_reorient.jpg", false, {"*": ["shapes"]}],
["Isaac-Reorient-KukaAllegro-Camera", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "isaacsim_rtx,newton_renderer,ovrtx", "albedo128,albedo256,albedo64,cube,depth128,depth256,depth64,duo_camera,raycaster_depth128,raycaster_depth256,raycaster_depth64,rgb128,rgb256,rgb64,semantic_segmentation128,semantic_segmentation256,semantic_segmentation64,shapes,simple_shading_constant_diffuse128,simple_shading_constant_diffuse256,simple_shading_constant_diffuse64,simple_shading_diffuse_mdl128,simple_shading_diffuse_mdl256,simple_shading_diffuse_mdl64,simple_shading_full_mdl128,simple_shading_full_mdl256,simple_shading_full_mdl64,single_camera", "tasks/manipulation/kuka_allegro_reorient.jpg", false, {"*": ["rgb64", "shapes", "single_camera"]}],
["Isaac-Shadow-Handover-Direct", "rl_games,rsl_rl,skrl", "isaacsim_physx,newton_mjwarp,ovphysx", "", "", "tasks/manipulation/shadow_hand_over.jpg", false, {}, {"skrl": "MAPPO"}],
Expand Down Expand Up @@ -99,7 +98,7 @@
["IsaacContrib-Open-Drawer-Franka-IK-Abs", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", ""],
["IsaacContrib-Open-Drawer-Franka-IK-Rel", "rsl_rl", "isaacsim_physx,newton_mjwarp,ovphysx", "", ""],
["IsaacContrib-Open-Drawer-OpenArm", "rl_games,rsl_rl", "", "", "", "tasks/manipulation/openarm_uni_open_drawer.jpg"],
["IsaacContrib-PickPlace-FixedBaseUpperBodyIK-G1-Abs", "", "", "", "", "tasks/manipulation/g1_pick_place_fixed_base.jpg"],
["IsaacContrib-PickPlace-FixedBaseUpperBodyIK-G1-Abs", "", "", "isaacsim_rtx,newton_renderer,ovrtx", "", "tasks/manipulation/g1_pick_place_fixed_base.jpg"],
["IsaacContrib-PickPlace-G1-InspireFTP-Abs", "", "", "", "", "tasks/manipulation/g1_pick_place.jpg"],
["IsaacContrib-PickPlace-GR1T2-Abs", "", "", "isaacsim_rtx,newton_renderer,ovrtx", "", "tasks/manipulation/gr-1_pick_place.jpg"],
["IsaacContrib-PickPlace-GR1T2-WaistEnabled-Abs", "", "", "", "", "tasks/manipulation/gr-1_pick_place_waist.jpg"],
Expand Down Expand Up @@ -336,7 +335,6 @@
[/Reach-UR10/, "tasks/manipulation/ur10_reach.jpg"],
[/Reorient-Cube-Allegro/, "tasks/manipulation/allegro_cube.jpg"],
[/Reorient-Cube-Shadow/, "tasks/manipulation/shadow_cube.jpg"],
[/Reorient-Franka/, "tasks/manipulation/franka_lift.jpg"],
[/Reorient-KukaAllegro/, "tasks/manipulation/kuka_allegro_reorient.jpg"],
[/Shadow-Handover/, "tasks/manipulation/shadow_hand_over.jpg"],
[/AnymalB/, "tasks/locomotion/anymal_b_flat.jpg"],
Expand Down
1 change: 0 additions & 1 deletion examples/heterogeneous_scene.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@
"IsaacContrib-Navigation-Flat-AnymalC",
# arm and hand manipulation
"Isaac-Lift-Franka",
"Isaac-Reorient-Franka",
"Isaac-Lift-KukaAllegro",
"Isaac-Reorient-KukaAllegro",
"Isaac-Open-Drawer-Franka",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Removed the obsolete Newton collection path restriction from the configuration documentation.
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,4 @@ class RigidObjectCollectionCfg:
"""Dictionary of rigid object configurations to spawn.

The keys are the names for the objects, which are used as unique identifiers throughout the code.

.. note::

With the Newton backend, the configured root prim paths must share a combined prefix-and-suffix
pattern that does not match other rigid objects in the same world.
"""
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Fixed
^^^^^

* Fixed :class:`~isaaclab_newton.assets.RigidObjectCollection` selecting rigid bodies outside the
collection whose names share the members' prefix or suffix, and rejecting members at different
path depths. The collection view now matches each configured prim path exactly.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

from __future__ import annotations

import os
import warnings
from collections.abc import Sequence
from typing import TYPE_CHECKING
Expand Down Expand Up @@ -1207,22 +1206,19 @@ def has_rigid_body_api(prim) -> bool:
root_prim_path_exprs.append(sim_utils.path_expr_to_glob(root_expr))
self._body_names_list.append(name)

# Build a single pattern that matches ALL body types by wildcarding the differing path segment.
combined_pattern = self._build_combined_pattern(root_prim_path_exprs)

# Create a single ArticulationView matching all body types.
# Create a single ArticulationView matching exactly the configured bodies.
# The 2nd dimension (matches per world) corresponds to the body types.
self._root_view = ArticulationView(
SimulationManager.get_model(),
combined_pattern,
root_prim_path_exprs,
verbose=False,
)
# Newton matches each body once, so members whose prim paths alias the same prim come up short here.
if self._root_view.count_per_world != self.num_bodies:
raise RuntimeError(
f"Rigid object collection pattern {combined_pattern!r} matched "
f"Rigid object collection patterns {root_prim_path_exprs} matched "
f"{self._root_view.count_per_world} objects per world, but the collection config contains "
f"{self.num_bodies}. Ensure collection prim paths share a prefix or suffix that distinguishes them "
"from other rigid objects."
f"{self.num_bodies}."
)

# container for data access
Expand Down Expand Up @@ -1345,49 +1341,6 @@ def _resolve_body_mask(self, body_mask: wp.array | None) -> wp.array | torch.Ten
body_ids = self._ALL_BODY_INDICES
return body_ids

@staticmethod
def _build_combined_pattern(prim_path_exprs: list[str]) -> str:
"""Build a single fnmatch pattern that matches all body types.

Compares path segments across all expressions and wildcards only the differing portion of each segment.
For example, given::

["/World/Env_*/Object_A", "/World/Env_*/Object_B"]

produces ``"/World/Env_*/Object_*"``. Retaining common prefixes and suffixes avoids selecting
unrelated sibling articulations from the same world.

Args:
prim_path_exprs: List of prim path expressions, one per body type.

Returns:
A single fnmatch pattern string.

Raises:
ValueError: If the expressions have different numbers of path segments.
"""
if len(prim_path_exprs) == 1:
return prim_path_exprs[0]

split_paths = [p.split("/") for p in prim_path_exprs]
lengths = {len(s) for s in split_paths}
if len(lengths) != 1:
raise ValueError(
f"Cannot build combined pattern: path expressions have different segment counts: {prim_path_exprs}"
)

combined_segments = []
for segments in zip(*split_paths):
unique = set(segments)
if len(unique) == 1:
combined_segments.append(segments[0])
else:
common_prefix = os.path.commonprefix(segments)
remaining_segments = [segment[len(common_prefix) :] for segment in segments]
common_suffix = os.path.commonprefix([segment[::-1] for segment in remaining_segments])[::-1]
combined_segments.append(f"{common_prefix}*{common_suffix}")
return "/".join(combined_segments)

"""
Internal simulation callbacks.
"""
Expand Down
52 changes: 30 additions & 22 deletions source/isaaclab_newton/test/assets/test_rigid_object_collection.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,19 @@ def generate_cubes_scene(
kinematic_enabled: bool = False,
device: str = "cuda:0",
spawn_unrelated_sibling: bool = False,
object_paths: tuple[str, ...] | None = None,
) -> tuple[RigidObjectCollection, torch.Tensor]:
"""Generate a scene with the provided number of cubes.

Args:
num_envs: Number of envs to generate.
num_cubes: Number of cubes to generate.
num_cubes: Number of cubes to generate when object_paths is not specified.
height: Height of the cubes.
has_api: Whether the cubes have a rigid body API on them.
kinematic_enabled: Whether the cubes are kinematic.
device: Device to use for the simulation.
spawn_unrelated_sibling: Whether to spawn a rigid body outside the collection in each environment.
object_paths: Member paths relative to each environment. Defaults to Object_0, Object_1, etc.

Returns:
A tuple containing the rigid object collection representing the cubes and the origins of the cubes.
Expand All @@ -100,45 +102,45 @@ def generate_cubes_scene(

# create the rigid object configs
cube_config_dict = {}
for i in range(num_cubes):
if object_paths is None:
object_paths = tuple(f"Object_{i}" for i in range(num_cubes))
for i, path in enumerate(object_paths):
cube_object_cfg = RigidObjectCfg(
prim_path=f"/World/Env_[^/]*/Object_{i}",
prim_path=f"/World/Env_[^/]*/{path}",
spawn=clone(spawn_cfg),
init_state=RigidObjectCfg.InitialStateCfg(pos=(0.0, 3 * i, height)),
)
cube_config_dict[f"cube_{i}"] = cube_object_cfg
cfgs = list(cube_config_dict.values())
if spawn_unrelated_sibling:
cfgs.append(AssetBaseCfg(prim_path="/World/Env_[^/]*/UnrelatedObject"))
cfgs.append(AssetBaseCfg(prim_path="/World/Env_[^/]*/Object_Target"))
clone_plan_from_env_0(CloneCfg(clone_template="/World/Env_{}"), cfgs, num_envs, 3.0, positions=origins)
if spawn_unrelated_sibling:
spawn_cfg.func(
"/World/Env_0/UnrelatedObject",
spawn_cfg,
translation=(0.0, -3.0, height),
)
spawn_cfg.func("/World/Env_0/Object_Target", spawn_cfg, translation=(0.0, -3.0, height))
# create the rigid object collection
cube_object_collection_cfg = RigidObjectCollectionCfg(rigid_objects=cube_config_dict)
cube_object_collection = RigidObjectCollection(cfg=cube_object_collection_cfg)

return cube_object_collection, torch.as_tensor(origins, device=device)


@pytest.mark.parametrize(("num_envs", "num_cubes", "spawn_unrelated_sibling"), [(1, 1, False), (2, 3, True)])
@pytest.mark.parametrize(
("num_envs", "object_paths", "spawn_unrelated_sibling"),
[
(1, ("Object_A",), False),
(2, ("Object_A", "Object_B", "Object_C"), True),
(2, ("Object_A", "Shelf/Object_B"), False),
],
ids=["single_member", "sibling_sharing_prefix", "nested_member"],
)
@pytest.mark.parametrize("device", test_devices())
def test_initialization(num_envs, num_cubes, spawn_unrelated_sibling, device):
"""Test initialization for prim with rigid body API at the provided prim path.

With an unrelated rigid body next to the cubes in each environment, the collection view must still
select only its configured rigid objects.
"""
with _newton_sim_context(device, auto_add_lighting=True) as sim:
def test_initialization(num_envs, object_paths, spawn_unrelated_sibling, device):
"""Bind only configured members, including nested paths, and preserve each body's name-to-pose mapping."""
num_cubes = len(object_paths)
with _newton_sim_context(device, gravity_enabled=False, auto_add_lighting=True) as sim:
sim._app_control_on_stop_handle = None
object_collection, _ = generate_cubes_scene(
num_envs=num_envs,
num_cubes=num_cubes,
device=device,
spawn_unrelated_sibling=spawn_unrelated_sibling,
object_collection, origins = generate_cubes_scene(
num_envs, device=device, spawn_unrelated_sibling=spawn_unrelated_sibling, object_paths=object_paths
)

# Check that the framework doesn't hold excessive strong references.
Expand All @@ -161,6 +163,12 @@ def test_initialization(num_envs, num_cubes, spawn_unrelated_sibling, device):
assert object_collection.data.body_mass.torch.shape == (num_envs, num_cubes)
assert object_collection.data.body_inertia.torch.shape == (num_envs, num_cubes, 9)

for name, member_cfg in object_collection.cfg.rigid_objects.items():
body_ids, _ = object_collection.find_bodies(name)
body_pos = object_collection.data.body_link_pos_w.torch[:, body_ids[0]] - origins
expected_pos = torch.tensor(member_cfg.init_state.pos, device=device).expand(num_envs, 3)
torch.testing.assert_close(body_pos, expected_pos, atol=1e-5, rtol=0.0)


@pytest.mark.parametrize("device", test_devices())
def test_set_body_inertial_properties_updates_inverses(device):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Removed
^^^^^^^

* Removed the unsupported ``Isaac-Reorient-Franka`` task and its environment configuration. Migrate custom
reorientation experiments to a maintained task or keep a local copy of the old configuration.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#
# SPDX-License-Identifier: BSD-3-Clause

"""Lift Franka reorient and lift environments."""
"""Franka lift environment."""

import gymnasium as gym

Expand All @@ -13,17 +13,6 @@
# Register Gym environments.
##

gym.register(
id="Isaac-Reorient-Franka",
entry_point="isaaclab.envs:ManagerBasedRLEnv",
disable_env_checker=True,
kwargs={
"env_cfg_entry_point": f"{__name__}.franka_env_cfg:FrankaReorientEnvCfg",
"rsl_rl_cfg_entry_point": f"{agents.__name__}.rsl_rl_ppo_cfg:FrankaPPORunnerCfg",
"default_agent": "rsl_rl",
},
)

gym.register(
id="Isaac-Lift-Franka",
entry_point="isaaclab.envs:ManagerBasedRLEnv",
Expand Down
Loading
Loading