Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test and check for texture randomization #1705

1 change: 1 addition & 0 deletions CONTRIBUTORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Guidelines for modifications:
* Gary Lvov
* Giulio Romualdi
* Haoran Zhou
* Harsh Patel
Copy link
Collaborator

Choose a reason for hiding this comment

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

🎉

* HoJin Jeon
* Hongwei Xiong
* Iretiayo Akinola
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,13 @@ def __init__(self, cfg: EventTermCfg, env: ManagerBasedEnv):
event_name = cfg.params.get("event_name")
texture_rotation = cfg.params.get("texture_rotation", (0.0, 0.0))

# check to make sure replicate_physics is set to False, else raise warning
if env.cfg.scene.replicate_physics:
raise ValueError(
Copy link
Contributor

Choose a reason for hiding this comment

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

shall we include the ValueError in the docstring?

"Unable to randomize visual texture material - ensure InteractiveSceneCfg's replicate_physics parameter"
" is set to False."
)

# convert from radians to degrees
texture_rotation = tuple(math.degrees(angle) for angle in texture_rotation)

Expand All @@ -212,9 +219,7 @@ def __init__(self, cfg: EventTermCfg, env: ManagerBasedEnv):

# Create the omni-graph node for the randomization term
def rep_texture_randomization():
prims_group = rep.get.prims(
path_pattern=f"{asset_entity.cfg.prim_path}/{body_names_regex}/visuals"
)
prims_group = rep.get.prims(path_pattern=f"{asset_entity.cfg.prim_path}/{body_names_regex}/visuals")

with prims_group:
rep.randomizer.texture(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
# Copyright (c) 2022-2025, The Isaac Lab Project Developers.
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause

"""
This script checks the functionality of texture randomization applied to the cartpole scene.
"""

"""Launch Isaac Sim Simulator first."""


import argparse

from omni.isaac.lab.app import AppLauncher

# add argparse arguments
parser = argparse.ArgumentParser(description="Check applying texture randomization to the cartpole scene.")
parser.add_argument("--num_envs", type=int, default=16, help="Number of environments to spawn.")
parser.add_argument(
Copy link
Collaborator

Choose a reason for hiding this comment

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

NIT: I might mention here that this should be set to False, but is left as a CLI arg for testing purposes?

"--replicate_physics",
type=bool,
default=False,
help="Replicates physics properties across all environments. For texture randomization, it must be set to False.",
)

# append AppLauncher cli args
AppLauncher.add_app_launcher_args(parser)
# parse the arguments
args_cli = parser.parse_args()

# launch omniverse app
app_launcher = AppLauncher(args_cli)
simulation_app = app_launcher.app

"""Rest everything follows."""

import math
import torch

import omni.isaac.lab.envs.mdp as mdp
from omni.isaac.lab.envs import ManagerBasedEnv, ManagerBasedEnvCfg
from omni.isaac.lab.managers import EventTermCfg as EventTerm
from omni.isaac.lab.managers import ObservationGroupCfg as ObsGroup
from omni.isaac.lab.managers import ObservationTermCfg as ObsTerm
from omni.isaac.lab.managers import SceneEntityCfg
from omni.isaac.lab.utils import configclass
from omni.isaac.lab.utils.assets import NVIDIA_NUCLEUS_DIR

from omni.isaac.lab_tasks.manager_based.classic.cartpole.cartpole_env_cfg import CartpoleSceneCfg


@configclass
class ActionsCfg:
"""Action specifications for the environment."""

joint_efforts = mdp.JointEffortActionCfg(asset_name="robot", joint_names=["slider_to_cart"], scale=5.0)


@configclass
class ObservationsCfg:
"""Observation specifications for the environment."""

@configclass
class PolicyCfg(ObsGroup):
"""Observations for policy group."""

# observation terms (order preserved)
joint_pos_rel = ObsTerm(func=mdp.joint_pos_rel)
joint_vel_rel = ObsTerm(func=mdp.joint_vel_rel)

def __post_init__(self) -> None:
self.enable_corruption = False
self.concatenate_terms = True

# observation groups
policy: PolicyCfg = PolicyCfg()


@configclass
class EventCfg:
"""Configuration for events."""

# on reset
cart_texture_randomizer = EventTerm(
func=mdp.randomize_visual_texture_material,
mode="reset",
params={
"asset_cfg": SceneEntityCfg("robot", body_names=["cart"]),
"texture_paths": [
f"{NVIDIA_NUCLEUS_DIR}/Materials/Base/Wood/Bamboo_Planks/Bamboo_Planks_BaseColor.png",
f"{NVIDIA_NUCLEUS_DIR}/Materials/Base/Wood/Cherry/Cherry_BaseColor.png",
f"{NVIDIA_NUCLEUS_DIR}/Materials/Base/Wood/Oak/Oak_BaseColor.png",
f"{NVIDIA_NUCLEUS_DIR}/Materials/Base/Wood/Timber/Timber_BaseColor.png",
f"{NVIDIA_NUCLEUS_DIR}/Materials/Base/Wood/Timber_Cladding/Timber_Cladding_BaseColor.png",
f"{NVIDIA_NUCLEUS_DIR}/Materials/Base/Wood/Walnut_Planks/Walnut_Planks_BaseColor.png",
],
"event_name": "cart_texture_randomizer",
"texture_rotation": (math.pi / 2, math.pi / 2),
},
)

pole_texture_randomizer = EventTerm(
func=mdp.randomize_visual_texture_material,
mode="reset",
params={
"asset_cfg": SceneEntityCfg("robot", body_names=["pole"]),
"texture_paths": [
f"{NVIDIA_NUCLEUS_DIR}/Materials/Base/Wood/Bamboo_Planks/Bamboo_Planks_BaseColor.png",
f"{NVIDIA_NUCLEUS_DIR}/Materials/Base/Wood/Cherry/Cherry_BaseColor.png",
f"{NVIDIA_NUCLEUS_DIR}/Materials/Base/Wood/Oak/Oak_BaseColor.png",
f"{NVIDIA_NUCLEUS_DIR}/Materials/Base/Wood/Timber/Timber_BaseColor.png",
f"{NVIDIA_NUCLEUS_DIR}/Materials/Base/Wood/Timber_Cladding/Timber_Cladding_BaseColor.png",
f"{NVIDIA_NUCLEUS_DIR}/Materials/Base/Wood/Walnut_Planks/Walnut_Planks_BaseColor.png",
],
"event_name": "pole_texture_randomizer",
"texture_rotation": (math.pi / 2, math.pi / 2),
},
)

reset_cart_position = EventTerm(
func=mdp.reset_joints_by_offset,
mode="reset",
params={
"asset_cfg": SceneEntityCfg("robot", joint_names=["slider_to_cart"]),
"position_range": (-1.0, 1.0),
"velocity_range": (-0.1, 0.1),
},
)

reset_pole_position = EventTerm(
func=mdp.reset_joints_by_offset,
mode="reset",
params={
"asset_cfg": SceneEntityCfg("robot", joint_names=["cart_to_pole"]),
"position_range": (-0.125 * math.pi, 0.125 * math.pi),
"velocity_range": (-0.01 * math.pi, 0.01 * math.pi),
},
)


@configclass
class CartpoleEnvCfg(ManagerBasedEnvCfg):
"""Configuration for the cartpole environment."""

# Scene settings
scene = CartpoleSceneCfg(env_spacing=2.5)

# Basic settings
actions = ActionsCfg()
observations = ObservationsCfg()
events = EventCfg()

def __post_init__(self):
"""Post initialization."""
# viewer settings
self.viewer.eye = [4.5, 0.0, 6.0]
self.viewer.lookat = [0.0, 0.0, 2.0]
# step settings
self.decimation = 4 # env step every 4 sim steps: 200Hz / 4 = 50Hz
# simulation settings
self.sim.dt = 0.005 # sim step every 5ms: 200Hz


def main():
Copy link
Contributor

Choose a reason for hiding this comment

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

This isn't a unit test. We should do it properly to check that texture is applied on the prim (besides visual inspection)?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The initial idea was to check the textures being applied changed on reset for the prims in the scene, however I was unable to find a way to directly access the albedo map information for each prim. If you have a way to access this information or a different approach I can convert this into a unit test.

Copy link
Collaborator

Choose a reason for hiding this comment

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

@hapatel-bdai let's take a look at this and figure out how to verify the textures for a little today / tomorrow

If we can't figure out how to check that the correct texture was applied, we can have a test_texture_randomization.py that is similar to this check script (only it needs to terminate). This will at least give us confidence that this codepath doesn't throw exceptions

Copy link
Contributor

Choose a reason for hiding this comment

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

I guess we didn't quite figure this out looking at the unit test? 😂 would it be possible to check the albedo map attribute in the unit test to at least make sure the expected image path was set correctly? I think the attribute name maps to inputs:diffuse_texture for the albedo texture path.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We tried that initially but we weren't able to access the albedo map since the textures are being applied through reference not directly.

"""Main function."""
# parse the arguments
env_cfg = CartpoleEnvCfg()
env_cfg.scene.num_envs = args_cli.num_envs
env_cfg.scene.replicate_physics = args_cli.replicate_physics

# setup base environment
env = ManagerBasedEnv(cfg=env_cfg)

# simulate physics
count = 0
while simulation_app.is_running():
with torch.inference_mode():
# reset
if count % 300 == 0:
count = 0
env.reset()
print("-" * 80)
print("[INFO]: Resetting environment...")
print("[INFO]: A new set of random textures have been applied.")

# sample random actions
joint_efforts = torch.randn_like(env.action_manager.action)
# step the environment
env.step(joint_efforts)

# update counter
count += 1

# close the environment
env.close()


if __name__ == "__main__":
# run the main function
main()
# close sim app
simulation_app.close()
Loading