Download _isaaclab/IsaacLab/source/isaaclab/test/envs/test_scale_randomization.py from Xinyi0214/UWLab: direct link, hf CLI and curl.
- Browser
- Download file 11.4 kB
-
https://huggingface.co/Xinyi0214/UWLab/resolve/main/_isaaclab/IsaacLab/source/isaaclab/test/envs/test_scale_randomization.py
- Command line
-
hf download hf://Xinyi0214/UWLab/_isaaclab/IsaacLab/source/isaaclab/test/envs/test_scale_randomization.py
-
curl -L -o test_scale_randomization.py https://huggingface.co/Xinyi0214/UWLab/resolve/main/_isaaclab/IsaacLab/source/isaaclab/test/envs/test_scale_randomization.py
11.4 kB
| # Copyright (c) 2022-2026, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md). | |
| # All rights reserved. | |
| # | |
| # SPDX-License-Identifier: BSD-3-Clause | |
| """ | |
| This script checks the functionality of scale randomization. | |
| """ | |
| from __future__ import annotations | |
| """Launch Isaac Sim Simulator first.""" | |
| from isaaclab.app import AppLauncher | |
| # launch omniverse app | |
| app_launcher = AppLauncher(headless=True, enable_cameras=True) | |
| simulation_app = app_launcher.app | |
| """Rest everything follows.""" | |
| import pytest | |
| import torch | |
| import omni.usd | |
| from pxr import Sdf | |
| import isaaclab.envs.mdp as mdp | |
| import isaaclab.sim as sim_utils | |
| from isaaclab.assets import AssetBaseCfg, RigidObject, RigidObjectCfg | |
| from isaaclab.envs import ManagerBasedEnv, ManagerBasedEnvCfg | |
| from isaaclab.managers import ActionTerm, ActionTermCfg, SceneEntityCfg | |
| from isaaclab.managers import EventTermCfg as EventTerm | |
| from isaaclab.managers import ObservationGroupCfg as ObsGroup | |
| from isaaclab.managers import ObservationTermCfg as ObsTerm | |
| from isaaclab.scene import InteractiveSceneCfg | |
| from isaaclab.terrains import TerrainImporterCfg | |
| from isaaclab.utils import configclass | |
| ## | |
| # Custom action term | |
| ## | |
| class CubeActionTerm(ActionTerm): | |
| """Simple action term that implements a PD controller to track a target position. | |
| The action term is applied to the cube asset. It involves two steps: | |
| 1. **Process the raw actions**: Typically, this includes any transformations of the raw actions | |
| that are required to map them to the desired space. This is called once per environment step. | |
| 2. **Apply the processed actions**: This step applies the processed actions to the asset. | |
| It is called once per simulation step. | |
| In this case, the action term simply applies the raw actions to the cube asset. The raw actions | |
| are the desired target positions of the cube in the environment frame. The pre-processing step | |
| simply copies the raw actions to the processed actions as no additional processing is required. | |
| The processed actions are then applied to the cube asset by implementing a PD controller to | |
| track the target position. | |
| """ | |
| _asset: RigidObject | |
| """The articulation asset on which the action term is applied.""" | |
| def __init__(self, cfg: CubeActionTermCfg, env: ManagerBasedEnv): | |
| # call super constructor | |
| super().__init__(cfg, env) | |
| # create buffers | |
| self._raw_actions = torch.zeros(env.num_envs, 3, device=self.device) | |
| self._processed_actions = torch.zeros(env.num_envs, 3, device=self.device) | |
| self._vel_command = torch.zeros(self.num_envs, 6, device=self.device) | |
| # gains of controller | |
| self.p_gain = cfg.p_gain | |
| self.d_gain = cfg.d_gain | |
| """ | |
| Properties. | |
| """ | |
| def action_dim(self) -> int: | |
| return self._raw_actions.shape[1] | |
| def raw_actions(self) -> torch.Tensor: | |
| return self._raw_actions | |
| def processed_actions(self) -> torch.Tensor: | |
| return self._processed_actions | |
| """ | |
| Operations | |
| """ | |
| def process_actions(self, actions: torch.Tensor): | |
| # store the raw actions | |
| self._raw_actions[:] = actions | |
| # no-processing of actions | |
| self._processed_actions[:] = self._raw_actions[:] | |
| def apply_actions(self): | |
| # implement a PD controller to track the target position | |
| pos_error = self._processed_actions - (self._asset.data.root_pos_w - self._env.scene.env_origins) | |
| vel_error = -self._asset.data.root_lin_vel_w | |
| # set velocity targets | |
| self._vel_command[:, :3] = self.p_gain * pos_error + self.d_gain * vel_error | |
| self._asset.write_root_velocity_to_sim(self._vel_command) | |
| class CubeActionTermCfg(ActionTermCfg): | |
| """Configuration for the cube action term.""" | |
| class_type: type = CubeActionTerm | |
| """The class corresponding to the action term.""" | |
| p_gain: float = 5.0 | |
| """Proportional gain of the PD controller.""" | |
| d_gain: float = 0.5 | |
| """Derivative gain of the PD controller.""" | |
| ## | |
| # Custom observation term | |
| ## | |
| def base_position(env: ManagerBasedEnv, asset_cfg: SceneEntityCfg) -> torch.Tensor: | |
| """Root linear velocity in the asset's root frame.""" | |
| # extract the used quantities (to enable type-hinting) | |
| asset: RigidObject = env.scene[asset_cfg.name] | |
| return asset.data.root_pos_w - env.scene.env_origins | |
| ## | |
| # Scene definition | |
| ## | |
| class MySceneCfg(InteractiveSceneCfg): | |
| """Example scene configuration. | |
| The scene comprises of a ground plane, light source and floating cubes (gravity disabled). | |
| """ | |
| # add terrain | |
| terrain = TerrainImporterCfg(prim_path="/World/ground", terrain_type="plane", debug_vis=False) | |
| # add cube for scale randomization | |
| cube1: RigidObjectCfg = RigidObjectCfg( | |
| prim_path="{ENV_REGEX_NS}/cube1", | |
| spawn=sim_utils.CuboidCfg( | |
| size=(0.2, 0.2, 0.2), | |
| rigid_props=sim_utils.RigidBodyPropertiesCfg(max_depenetration_velocity=1.0, disable_gravity=True), | |
| mass_props=sim_utils.MassPropertiesCfg(mass=1.0), | |
| physics_material=sim_utils.RigidBodyMaterialCfg(), | |
| visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(0.0, 0.0, 0.0)), | |
| ), | |
| init_state=RigidObjectCfg.InitialStateCfg(pos=(0.0, 0.0, 5)), | |
| ) | |
| # add cube for static scale values | |
| cube2: RigidObjectCfg = RigidObjectCfg( | |
| prim_path="{ENV_REGEX_NS}/cube2", | |
| spawn=sim_utils.CuboidCfg( | |
| size=(0.2, 0.2, 0.2), | |
| rigid_props=sim_utils.RigidBodyPropertiesCfg(max_depenetration_velocity=1.0, disable_gravity=True), | |
| mass_props=sim_utils.MassPropertiesCfg(mass=1.0), | |
| physics_material=sim_utils.RigidBodyMaterialCfg(), | |
| visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(0.0, 0.0, 0.0)), | |
| ), | |
| init_state=RigidObjectCfg.InitialStateCfg(pos=(0.0, 0.0, 5)), | |
| ) | |
| # lights | |
| light = AssetBaseCfg( | |
| prim_path="/World/light", | |
| spawn=sim_utils.DistantLightCfg(color=(0.75, 0.75, 0.75), intensity=3000.0), | |
| ) | |
| ## | |
| # Environment settings | |
| ## | |
| class ActionsCfg: | |
| """Action specifications for the MDP.""" | |
| joint_pos = CubeActionTermCfg(asset_name="cube1") | |
| class ObservationsCfg: | |
| """Observation specifications for the MDP.""" | |
| class PolicyCfg(ObsGroup): | |
| """Observations for policy group.""" | |
| # cube velocity | |
| position = ObsTerm(func=base_position, params={"asset_cfg": SceneEntityCfg("cube1")}) | |
| def __post_init__(self): | |
| self.enable_corruption = True | |
| self.concatenate_terms = True | |
| # observation groups | |
| policy: PolicyCfg = PolicyCfg() | |
| class EventCfg: | |
| """Configuration for events.""" | |
| reset_base = EventTerm( | |
| func=mdp.reset_root_state_uniform, | |
| mode="reset", | |
| params={ | |
| "pose_range": {"x": (-0.5, 0.5), "y": (-0.5, 0.5), "yaw": (-3.14, 3.14)}, | |
| "velocity_range": { | |
| "x": (-0.5, 0.5), | |
| "y": (-0.5, 0.5), | |
| "z": (-0.5, 0.5), | |
| }, | |
| "asset_cfg": SceneEntityCfg("cube1"), | |
| }, | |
| ) | |
| # Scale randomization as intended | |
| randomize_cube1__scale = EventTerm( | |
| func=mdp.randomize_rigid_body_scale, | |
| mode="prestartup", | |
| params={ | |
| "scale_range": {"x": (0.5, 1.5), "y": (0.5, 1.5), "z": (0.5, 1.5)}, | |
| "asset_cfg": SceneEntityCfg("cube1"), | |
| }, | |
| ) | |
| # Static scale values | |
| randomize_cube2__scale = EventTerm( | |
| func=mdp.randomize_rigid_body_scale, | |
| mode="prestartup", | |
| params={ | |
| "scale_range": {"x": (1.0, 1.0), "y": (1.0, 1.0), "z": (1.0, 1.0)}, | |
| "asset_cfg": SceneEntityCfg("cube2"), | |
| }, | |
| ) | |
| ## | |
| # Environment configuration | |
| ## | |
| class CubeEnvCfg(ManagerBasedEnvCfg): | |
| """Configuration for the locomotion velocity-tracking environment.""" | |
| # Scene settings | |
| scene: MySceneCfg = MySceneCfg(num_envs=10, env_spacing=2.5, replicate_physics=False) | |
| # Basic settings | |
| observations: ObservationsCfg = ObservationsCfg() | |
| actions: ActionsCfg = ActionsCfg() | |
| events: EventCfg = EventCfg() | |
| def __post_init__(self): | |
| """Post initialization.""" | |
| # general settings | |
| self.decimation = 2 | |
| # simulation settings | |
| self.sim.dt = 0.01 | |
| self.sim.physics_material = self.scene.terrain.physics_material | |
| self.sim.render_interval = self.decimation | |
| def test_scale_randomization(device): | |
| """Test scale randomization for cube environment.""" | |
| # create a new stage | |
| omni.usd.get_context().new_stage() | |
| # set the device | |
| env_cfg = CubeEnvCfg() | |
| env_cfg.sim.device = device | |
| # setup base environment | |
| env = ManagerBasedEnv(cfg=env_cfg) | |
| # setup target position commands | |
| target_position = torch.rand(env.num_envs, 3, device=env.device) * 2 | |
| target_position[:, 2] += 2.0 | |
| # offset all targets so that they move to the world origin | |
| target_position -= env.scene.env_origins | |
| # test to make sure all assets in the scene are created | |
| all_prim_paths = sim_utils.find_matching_prim_paths("/World/envs/env_.*/cube.*/.*") | |
| assert len(all_prim_paths) == (env.num_envs * 2) | |
| # test to make sure randomized values are truly random | |
| applied_scaling_randomization = set() | |
| prim_paths = sim_utils.find_matching_prim_paths("/World/envs/env_.*/cube1") | |
| # get the stage | |
| stage = omni.usd.get_context().get_stage() | |
| # check if the scale values are truly random | |
| for i in range(3): | |
| prim_spec = Sdf.CreatePrimInLayer(stage.GetRootLayer(), prim_paths[i]) | |
| scale_spec = prim_spec.GetAttributeAtPath(prim_paths[i] + ".xformOp:scale") | |
| if scale_spec.default in applied_scaling_randomization: | |
| raise ValueError( | |
| "Detected repeat in applied scale values - indication scaling randomization is not working." | |
| ) | |
| applied_scaling_randomization.add(scale_spec.default) | |
| # test to make sure that fixed values are assigned correctly | |
| prim_paths = sim_utils.find_matching_prim_paths("/World/envs/env_.*/cube2") | |
| for i in range(3): | |
| prim_spec = Sdf.CreatePrimInLayer(stage.GetRootLayer(), prim_paths[i]) | |
| scale_spec = prim_spec.GetAttributeAtPath(prim_paths[i] + ".xformOp:scale") | |
| assert tuple(scale_spec.default) == (1.0, 1.0, 1.0) | |
| # simulate physics | |
| with torch.inference_mode(): | |
| for count in range(200): | |
| # reset every few steps to check nothing breaks | |
| if count % 100 == 0: | |
| env.reset() | |
| # step the environment | |
| env.step(target_position) | |
| env.close() | |
| def test_scale_randomization_failure_replicate_physics(): | |
| """Test scale randomization failure when replicate physics is set to True.""" | |
| # create a new stage | |
| omni.usd.get_context().new_stage() | |
| # set the arguments | |
| cfg_failure = CubeEnvCfg() | |
| cfg_failure.scene.replicate_physics = True | |
| # run the test | |
| with pytest.raises(RuntimeError): | |
| env = ManagerBasedEnv(cfg_failure) | |
| env.close() | |