From a718ff81e8178638c57f7ab0ae066ccee659b4ca Mon Sep 17 00:00:00 2001 From: Xinjie Yao Date: Mon, 9 Feb 2026 00:14:29 -0800 Subject: [PATCH 1/3] allow user to modfy scale when loading rigid obj asset --- isaaclab_arena/assets/object_library.py | 165 +++++++++++++----- isaaclab_arena/tests/test_object_scale.py | 49 ++++++ .../kitchen_pick_and_place_environment.py | 11 ++ 3 files changed, 186 insertions(+), 39 deletions(-) create mode 100644 isaaclab_arena/tests/test_object_scale.py diff --git a/isaaclab_arena/assets/object_library.py b/isaaclab_arena/assets/object_library.py index acd28aad7..a02895c8f 100644 --- a/isaaclab_arena/assets/object_library.py +++ b/isaaclab_arena/assets/object_library.py @@ -45,16 +45,22 @@ class LibraryObject(Object): asset_cfg_addon: dict[str, Any] = {} def __init__( - self, instance_name: str | None = None, prim_path: str | None = None, initial_pose: Pose | None = None, **kwargs + self, + instance_name: str | None = None, + prim_path: str | None = None, + initial_pose: Pose | None = None, + scale: tuple[float, float, float] | None = None, + **kwargs, ): name = instance_name if instance_name is not None else self.name + scale = scale if scale is not None else self.scale super().__init__( name=name, prim_path=prim_path, tags=self.tags, usd_path=self.usd_path, object_type=self.object_type, - scale=self.scale, + scale=scale, initial_pose=initial_pose, spawn_cfg_addon=self.spawn_cfg_addon, asset_cfg_addon=self.asset_cfg_addon, @@ -73,9 +79,13 @@ class CrackerBox(LibraryObject): usd_path = f"{ISAAC_NUCLEUS_DIR}/Props/YCB/Axis_Aligned_Physics/003_cracker_box.usd" def __init__( - self, instance_name: str | None = None, prim_path: str | None = None, initial_pose: Pose | None = None + self, + instance_name: str | None = None, + prim_path: str | None = None, + initial_pose: Pose | None = None, + scale: tuple[float, float, float] | None = None, ): - super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose) + super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose, scale=scale) @register_asset @@ -89,9 +99,13 @@ class MustardBottle(LibraryObject): usd_path = f"{ISAAC_NUCLEUS_DIR}/Props/YCB/Axis_Aligned_Physics/006_mustard_bottle.usd" def __init__( - self, instance_name: str | None = None, prim_path: str | None = None, initial_pose: Pose | None = None + self, + instance_name: str | None = None, + prim_path: str | None = None, + initial_pose: Pose | None = None, + scale: tuple[float, float, float] | None = None, ): - super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose) + super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose, scale=scale) @register_asset @@ -105,9 +119,13 @@ class SugarBox(LibraryObject): usd_path = f"{ISAAC_NUCLEUS_DIR}/Props/YCB/Axis_Aligned_Physics/004_sugar_box.usd" def __init__( - self, instance_name: str | None = None, prim_path: str | None = None, initial_pose: Pose | None = None + self, + instance_name: str | None = None, + prim_path: str | None = None, + initial_pose: Pose | None = None, + scale: tuple[float, float, float] | None = None, ): - super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose) + super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose, scale=scale) @register_asset @@ -121,9 +139,13 @@ class TomatoSoupCan(LibraryObject): usd_path = f"{ISAAC_NUCLEUS_DIR}/Props/YCB/Axis_Aligned_Physics/005_tomato_soup_can.usd" def __init__( - self, instance_name: str | None = None, prim_path: str | None = None, initial_pose: Pose | None = None + self, + instance_name: str | None = None, + prim_path: str | None = None, + initial_pose: Pose | None = None, + scale: tuple[float, float, float] | None = None, ): - super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose) + super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose, scale=scale) @register_asset @@ -137,9 +159,13 @@ class PowerDrill(LibraryObject): usd_path = f"{ISAACLAB_NUCLEUS_DIR}/Arena/assets/object_library/power_drill_physics/power_drill_physics.usd" def __init__( - self, instance_name: str | None = None, prim_path: str | None = None, initial_pose: Pose | None = None + self, + instance_name: str | None = None, + prim_path: str | None = None, + initial_pose: Pose | None = None, + scale: tuple[float, float, float] | None = None, ): - super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose) + super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose, scale=scale) @register_asset @@ -251,9 +277,13 @@ class OfficeTable(LibraryObject): scale = (1.0, 1.0, 0.7) def __init__( - self, instance_name: str | None = None, prim_path: str | None = None, initial_pose: Pose | None = None + self, + instance_name: str | None = None, + prim_path: str | None = None, + initial_pose: Pose | None = None, + scale: tuple[float, float, float] | None = None, ): - super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose) + super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose, scale=scale) @register_asset @@ -268,9 +298,13 @@ class BlueSortingBin(LibraryObject): scale = (4.0, 2.0, 1.0) def __init__( - self, instance_name: str | None = None, prim_path: str | None = None, initial_pose: Pose | None = None + self, + instance_name: str | None = None, + prim_path: str | None = None, + initial_pose: Pose | None = None, + scale: tuple[float, float, float] | None = None, ): - super().__init__(prim_path=prim_path, initial_pose=initial_pose) + super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose, scale=scale) @register_asset @@ -285,9 +319,13 @@ class BlueExhaustPipe(LibraryObject): scale = (0.55, 0.55, 1.4) def __init__( - self, instance_name: str | None = None, prim_path: str | None = None, initial_pose: Pose | None = None + self, + instance_name: str | None = None, + prim_path: str | None = None, + initial_pose: Pose | None = None, + scale: tuple[float, float, float] | None = None, ): - super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose) + super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose, scale=scale) @register_asset @@ -302,9 +340,13 @@ class BrownBox(LibraryObject): scale = (1.0, 1.0, 1.0) def __init__( - self, instance_name: str | None = None, prim_path: str | None = None, initial_pose: Pose | None = None + self, + instance_name: str | None = None, + prim_path: str | None = None, + initial_pose: Pose | None = None, + scale: tuple[float, float, float] | None = None, ): - super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose) + super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose, scale=scale) @register_asset @@ -324,12 +366,17 @@ class Mug(LibraryObject, Placeable): orientation_threshold = 0.5 def __init__( - self, instance_name: str | None = None, prim_path: str | None = None, initial_pose: Pose | None = None + self, + instance_name: str | None = None, + prim_path: str | None = None, + initial_pose: Pose | None = None, + scale: tuple[float, float, float] | None = None, ): super().__init__( instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose, + scale=scale, upright_axis_name=self.upright_axis_name, orientation_threshold=self.orientation_threshold, ) @@ -406,9 +453,13 @@ class DexCube(LibraryObject): object_type = ObjectType.RIGID def __init__( - self, instance_name: str | None = None, prim_path: str | None = None, initial_pose: Pose | None = None + self, + instance_name: str | None = None, + prim_path: str | None = None, + initial_pose: Pose | None = None, + scale: tuple[float, float, float] | None = None, ): - super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose) + super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose, scale=scale) @register_asset @@ -555,9 +606,13 @@ class Broccoli(LibraryObject): object_type = ObjectType.RIGID def __init__( - self, instance_name: str | None = None, prim_path: str | None = None, initial_pose: Pose | None = None + self, + instance_name: str | None = None, + prim_path: str | None = None, + initial_pose: Pose | None = None, + scale: tuple[float, float, float] | None = None, ): - super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose) + super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose, scale=scale) @register_asset @@ -579,9 +634,13 @@ class SweetPotato(LibraryObject): scale = (1.5, 1.5, 1.5) def __init__( - self, instance_name: str | None = None, prim_path: str | None = None, initial_pose: Pose | None = None + self, + instance_name: str | None = None, + prim_path: str | None = None, + initial_pose: Pose | None = None, + scale: tuple[float, float, float] | None = None, ): - super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose) + super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose, scale=scale) @register_asset @@ -603,9 +662,13 @@ class Jug(LibraryObject): scale = (2.0, 2.0, 2.0) def __init__( - self, instance_name: str | None = None, prim_path: str | None = None, initial_pose: Pose | None = None + self, + instance_name: str | None = None, + prim_path: str | None = None, + initial_pose: Pose | None = None, + scale: tuple[float, float, float] | None = None, ): - super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose) + super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose, scale=scale) @register_asset @@ -621,9 +684,13 @@ class RanchDressingBottle(LibraryObject): scale = (0.8, 0.8, 1.2) def __init__( - self, instance_name: str | None = None, prim_path: str | None = None, initial_pose: Pose | None = None + self, + instance_name: str | None = None, + prim_path: str | None = None, + initial_pose: Pose | None = None, + scale: tuple[float, float, float] | None = None, ): - super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose) + super().__init__(instance_name=instance_name, prim_path=prim_path, initial_pose=initial_pose, scale=scale) @register_asset @@ -646,8 +713,13 @@ class RedCube(LibraryObject): default_prim_path = "{ENV_REGEX_NS}/RedCube" scale = (0.02, 0.02, 0.02) - def __init__(self, prim_path: str | None = None, initial_pose: Pose | None = None): - super().__init__(prim_path=prim_path, initial_pose=initial_pose) + def __init__( + self, + prim_path: str | None = None, + initial_pose: Pose | None = None, + scale: tuple[float, float, float] | None = None, + ): + super().__init__(prim_path=prim_path, initial_pose=initial_pose, scale=scale) @register_asset @@ -669,8 +741,13 @@ class GreenCube(LibraryObject): default_prim_path = "{ENV_REGEX_NS}/GreenCube" scale = (0.02, 0.02, 0.02) - def __init__(self, prim_path: str | None = None, initial_pose: Pose | None = None): - super().__init__(prim_path=prim_path, initial_pose=initial_pose) + def __init__( + self, + prim_path: str | None = None, + initial_pose: Pose | None = None, + scale: tuple[float, float, float] | None = None, + ): + super().__init__(prim_path=prim_path, initial_pose=initial_pose, scale=scale) @register_asset @@ -686,8 +763,13 @@ class RedContainer(LibraryObject): default_prim_path = "{ENV_REGEX_NS}/red_container" scale = (0.5, 0.5, 0.5) - def __init__(self, prim_path: str | None = None, initial_pose: Pose | None = None): - super().__init__(prim_path=prim_path, initial_pose=initial_pose) + def __init__( + self, + prim_path: str | None = None, + initial_pose: Pose | None = None, + scale: tuple[float, float, float] | None = None, + ): + super().__init__(prim_path=prim_path, initial_pose=initial_pose, scale=scale) @register_asset @@ -703,5 +785,10 @@ class GreenContainer(LibraryObject): default_prim_path = "{ENV_REGEX_NS}/green_container" scale = (0.5, 0.5, 0.5) - def __init__(self, prim_path: str | None = None, initial_pose: Pose | None = None): - super().__init__(prim_path=prim_path, initial_pose=initial_pose) + def __init__( + self, + prim_path: str | None = None, + initial_pose: Pose | None = None, + scale: tuple[float, float, float] | None = None, + ): + super().__init__(prim_path=prim_path, initial_pose=initial_pose, scale=scale) diff --git a/isaaclab_arena/tests/test_object_scale.py b/isaaclab_arena/tests/test_object_scale.py new file mode 100644 index 000000000..93fc56b4d --- /dev/null +++ b/isaaclab_arena/tests/test_object_scale.py @@ -0,0 +1,49 @@ +# Copyright (c) 2026, The Isaac Lab Arena Project Developers (https://github.com/isaac-sim/IsaacLab-Arena/blob/main/CONTRIBUTORS.md). +# All rights reserved. +# +# SPDX-License-Identifier: Apache-2.0 + +"""Tests for object scale parameter (LibraryObject and subclasses).""" + +from isaaclab_arena.tests.utils.subprocess import run_simulation_app_function + +HEADLESS = True + + +def _test_object_scale_default_and_override(simulation_app): + from isaaclab_arena.assets.asset_registry import AssetRegistry + + asset_registry = AssetRegistry() + + cracker_box_default = asset_registry.get_asset_by_name("cracker_box")() + assert cracker_box_default.scale == (1.0, 1.0, 1.0) + + # Same object with explicit scale override + custom_scale = (2.0, 2.0, 2.0) + cracker_box_scaled = asset_registry.get_asset_by_name("cracker_box")(scale=custom_scale) + assert cracker_box_scaled.scale == custom_scale + + dex_cube_default = asset_registry.get_asset_by_name("dex_cube")() + assert dex_cube_default.scale == (0.8, 0.8, 0.8) + + # Override object's own scale + override_scale = (0.5, 0.5, 0.5) + dex_cube_scaled = asset_registry.get_asset_by_name("dex_cube")(scale=override_scale) + assert dex_cube_scaled.scale == override_scale + + dex_cube_none = asset_registry.get_asset_by_name("dex_cube")(scale=None) + assert dex_cube_none.scale == (0.8, 0.8, 0.8) + + return True + + +def test_object_scale_default_and_override(): + result = run_simulation_app_function( + _test_object_scale_default_and_override, + headless=HEADLESS, + ) + assert result, "Test failed" + + +if __name__ == "__main__": + test_object_scale_default_and_override() diff --git a/isaaclab_arena_environments/kitchen_pick_and_place_environment.py b/isaaclab_arena_environments/kitchen_pick_and_place_environment.py index b6f1f5e94..6f417365c 100644 --- a/isaaclab_arena_environments/kitchen_pick_and_place_environment.py +++ b/isaaclab_arena_environments/kitchen_pick_and_place_environment.py @@ -88,6 +88,17 @@ def add_cli_args(parser: argparse.ArgumentParser) -> None: default=None, help="Multiple objects to spawn across environments. Mutually exclusive with --object.", ) + parser.add_argument( + "--object_scale", + nargs=3, + type=float, + default=None, + metavar=("X", "Y", "Z"), + help=( + "Scale (x, y, z) for the pick-up object(s). Example: --object_scale 1.0 1.0 1.0. If not set, uses the" + " object's default scale." + ), + ) parser.add_argument("--embodiment", type=str, default="franka") # NOTE(alexmillane, 2025.09.04): We need a teleop device argument in order # to be used in the record_demos.py script. From 3bcc1067ab263553d193293ea9692ffe3572f201 Mon Sep 17 00:00:00 2001 From: Xinjie Yao Date: Mon, 9 Feb 2026 00:19:41 -0800 Subject: [PATCH 2/3] add args into example --- .../kitchen_pick_and_place_environment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/isaaclab_arena_environments/kitchen_pick_and_place_environment.py b/isaaclab_arena_environments/kitchen_pick_and_place_environment.py index 6f417365c..51da209db 100644 --- a/isaaclab_arena_environments/kitchen_pick_and_place_environment.py +++ b/isaaclab_arena_environments/kitchen_pick_and_place_environment.py @@ -46,7 +46,7 @@ def get_env(self, args_cli: argparse.Namespace): # -> IsaacLabArenaEnvironment: objects = [self.asset_registry.get_asset_by_name(obj)() for obj in args_cli.object_set] pick_up_object = RigidObjectSet(name="object_set", objects=objects) else: - pick_up_object = self.asset_registry.get_asset_by_name(args_cli.object)() + pick_up_object = self.asset_registry.get_asset_by_name(args_cli.object)(scale=args_cli.object_scale) pick_up_object.set_initial_pose(pick_up_object_pose) # TODO(alexmillane, 2025.09.24): Add automatic object type detection of ObjectReferences. From 587e16e0b260b3814c5e7bd9b4f6087abbb546b9 Mon Sep 17 00:00:00 2001 From: Xinjie Yao Date: Mon, 9 Feb 2026 10:24:12 -0800 Subject: [PATCH 3/3] remove cli args --- .../kitchen_pick_and_place_environment.py | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/isaaclab_arena_environments/kitchen_pick_and_place_environment.py b/isaaclab_arena_environments/kitchen_pick_and_place_environment.py index 51da209db..b6f1f5e94 100644 --- a/isaaclab_arena_environments/kitchen_pick_and_place_environment.py +++ b/isaaclab_arena_environments/kitchen_pick_and_place_environment.py @@ -46,7 +46,7 @@ def get_env(self, args_cli: argparse.Namespace): # -> IsaacLabArenaEnvironment: objects = [self.asset_registry.get_asset_by_name(obj)() for obj in args_cli.object_set] pick_up_object = RigidObjectSet(name="object_set", objects=objects) else: - pick_up_object = self.asset_registry.get_asset_by_name(args_cli.object)(scale=args_cli.object_scale) + pick_up_object = self.asset_registry.get_asset_by_name(args_cli.object)() pick_up_object.set_initial_pose(pick_up_object_pose) # TODO(alexmillane, 2025.09.24): Add automatic object type detection of ObjectReferences. @@ -88,17 +88,6 @@ def add_cli_args(parser: argparse.ArgumentParser) -> None: default=None, help="Multiple objects to spawn across environments. Mutually exclusive with --object.", ) - parser.add_argument( - "--object_scale", - nargs=3, - type=float, - default=None, - metavar=("X", "Y", "Z"), - help=( - "Scale (x, y, z) for the pick-up object(s). Example: --object_scale 1.0 1.0 1.0. If not set, uses the" - " object's default scale." - ), - ) parser.add_argument("--embodiment", type=str, default="franka") # NOTE(alexmillane, 2025.09.04): We need a teleop device argument in order # to be used in the record_demos.py script.