-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Adds Raycaster with tracking for Dynamic Meshes #3298
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
base: main
Are you sure you want to change the base?
Changes from all commits
c9bcd3b
b7c172f
e1a9124
4ca82f6
d13331c
3f5d008
5decd09
f585a31
7242ea2
2c6c607
86418d3
fa6b498
8beb0d2
5ca6e6e
eefcb3a
6eda9c8
0712ee5
004184e
9287efe
f80e384
bcd747a
4f6c772
f98150e
5940b98
500931c
586858c
4d167ec
5b8563d
17b5819
b3747c4
ad7cbfc
e2e7f9e
8a37d61
3a6a242
16cd7c2
8efd58d
7509d45
4e40239
88da283
13ba4e2
abbc8ed
df9f660
f2894a0
3eaecb5
0a47268
b27caa5
39fa91b
82f72ce
332b8be
f5e91cf
7c98e27
a048c16
123cd01
bfeaf48
532b1f6
cc7dfee
2ec9bd7
2743d03
b44eaf2
7ce6d6d
6066474
5984c82
09f17f5
3a2de0d
7b39736
e9fb9a1
43da984
12de1fa
1635968
115ce9f
636406b
8ac9ad6
404bc69
eef0399
d9a5f3a
d196bbd
f094b27
c764f0c
bccb267
3d7c8f7
ab7eac2
8ae7743
e6cbead
796c1a4
9c34e95
41c5f7a
371785d
90ef912
616d677
2d1c3c2
a289d1c
20772f4
04a7185
5c927da
7864b21
dd61d3e
82819d8
f5af366
50fc172
c891112
85fbe94
c251913
22040a7
0c2955b
41924f2
a194b3b
9a0f5ab
80908ed
30ceb59
4439744
0a832b5
e1a5780
c09b9d0
b2103cb
335dc71
3c5bd81
0d3f5be
ee12bb3
bc6886f
8d84fb1
8796999
9b2871b
64a9a61
04cd1c5
ee857ce
dfc9283
8b2de9b
c97b616
0dbb2da
ddcc3d8
dfd08df
193e02a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -20,6 +20,7 @@ | |
| timer | ||
| types | ||
| warp | ||
| mesh | ||
|
|
||
| .. Rubric:: Functions | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,308 @@ | ||
| # Copyright (c) 2022-2025, The Isaac Lab Project Developers (https://github.com/isaac-sim/IsaacLab/blob/main/CONTRIBUTORS.md). | ||
| # All rights reserved. | ||
| # | ||
| # SPDX-License-Identifier: BSD-3-Clause | ||
|
|
||
|
|
||
| """Example on using the MultiMesh Raycaster sensor. | ||
| Usage: | ||
| `python scripts/demos/sensors/multi_mesh_raycaster.py --num_envs 16 --asset_type <allegro_hand|anymal_d|multi>` | ||
| """ | ||
|
|
||
| import argparse | ||
|
|
||
| from isaaclab.app import AppLauncher | ||
|
|
||
| # add argparse arguments | ||
| parser = argparse.ArgumentParser(description="Example on using the raycaster sensor.") | ||
| parser.add_argument("--num_envs", type=int, default=16, help="Number of environments to spawn.") | ||
| parser.add_argument( | ||
| "--asset_type", | ||
| type=str, | ||
| default="allegro_hand", | ||
| help="Asset type to use.", | ||
| choices=["allegro_hand", "anymal_d", "multi"], | ||
| ) | ||
| # 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 random | ||
| import torch | ||
|
|
||
| import omni.usd | ||
| from pxr import Gf, Sdf | ||
|
|
||
| ## | ||
| # Pre-defined configs | ||
| ## | ||
| from isaaclab_assets.robots.allegro import ALLEGRO_HAND_CFG | ||
| from isaaclab_assets.robots.anymal import ANYMAL_D_CFG | ||
|
|
||
| import isaaclab.sim as sim_utils | ||
| from isaaclab.assets import Articulation, AssetBaseCfg, RigidObjectCfg | ||
| from isaaclab.markers.config import VisualizationMarkersCfg | ||
| from isaaclab.scene import InteractiveScene, InteractiveSceneCfg | ||
| from isaaclab.sensors.ray_caster import MultiMeshRayCasterCfg, patterns | ||
| from isaaclab.utils import configclass | ||
| from isaaclab.utils.assets import ISAAC_NUCLEUS_DIR | ||
|
|
||
| RAY_CASTER_MARKER_CFG = VisualizationMarkersCfg( | ||
| markers={ | ||
| "hit": sim_utils.SphereCfg( | ||
| radius=0.01, | ||
| visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(1.0, 0.0, 0.0)), | ||
| ), | ||
| }, | ||
| ) | ||
|
|
||
|
|
||
| if args_cli.asset_type == "allegro_hand": | ||
| asset_cfg = ALLEGRO_HAND_CFG.replace(prim_path="{ENV_REGEX_NS}/Robot") | ||
| ray_caster_cfg = MultiMeshRayCasterCfg( | ||
| prim_path="{ENV_REGEX_NS}/Robot", | ||
| update_period=1 / 60, | ||
| offset=MultiMeshRayCasterCfg.OffsetCfg(pos=(0, -0.1, 0.3)), | ||
| mesh_prim_paths=[ | ||
| "/World/Ground", | ||
| MultiMeshRayCasterCfg.RaycastTargetCfg(target_prim_expr="{ENV_REGEX_NS}/Robot/thumb_link_.*/visuals_xform"), | ||
| MultiMeshRayCasterCfg.RaycastTargetCfg(target_prim_expr="{ENV_REGEX_NS}/Robot/index_link.*/visuals_xform"), | ||
| MultiMeshRayCasterCfg.RaycastTargetCfg( | ||
| target_prim_expr="{ENV_REGEX_NS}/Robot/middle_link_.*/visuals_xform" | ||
| ), | ||
| MultiMeshRayCasterCfg.RaycastTargetCfg(target_prim_expr="{ENV_REGEX_NS}/Robot/ring_link_.*/visuals_xform"), | ||
| MultiMeshRayCasterCfg.RaycastTargetCfg(target_prim_expr="{ENV_REGEX_NS}/Robot/palm_link/visuals_xform"), | ||
| MultiMeshRayCasterCfg.RaycastTargetCfg(target_prim_expr="{ENV_REGEX_NS}/Robot/allegro_mount/visuals_xform"), | ||
| ], | ||
| ray_alignment="world", | ||
| pattern_cfg=patterns.GridPatternCfg(resolution=0.005, size=(0.4, 0.4), direction=(0, 0, -1)), | ||
| debug_vis=not args_cli.headless, | ||
| visualizer_cfg=RAY_CASTER_MARKER_CFG.replace(prim_path="/Visuals/RayCaster"), | ||
| ) | ||
|
|
||
| elif args_cli.asset_type == "anymal_d": | ||
| asset_cfg = ANYMAL_D_CFG.replace(prim_path="{ENV_REGEX_NS}/Robot") | ||
| ray_caster_cfg = MultiMeshRayCasterCfg( | ||
| prim_path="{ENV_REGEX_NS}/Robot", | ||
| update_period=1 / 60, | ||
| offset=MultiMeshRayCasterCfg.OffsetCfg(pos=(0, -0.1, 0.3)), | ||
| mesh_prim_paths=[ | ||
| "/World/Ground", | ||
| MultiMeshRayCasterCfg.RaycastTargetCfg(target_prim_expr="{ENV_REGEX_NS}/Robot/LF_.*/visuals"), | ||
| MultiMeshRayCasterCfg.RaycastTargetCfg(target_prim_expr="{ENV_REGEX_NS}/Robot/RF_.*/visuals"), | ||
| MultiMeshRayCasterCfg.RaycastTargetCfg(target_prim_expr="{ENV_REGEX_NS}/Robot/LH_.*/visuals"), | ||
| MultiMeshRayCasterCfg.RaycastTargetCfg(target_prim_expr="{ENV_REGEX_NS}/Robot/RH_.*/visuals"), | ||
| MultiMeshRayCasterCfg.RaycastTargetCfg(target_prim_expr="{ENV_REGEX_NS}/Robot/base/visuals"), | ||
| ], | ||
| ray_alignment="world", | ||
| pattern_cfg=patterns.GridPatternCfg(resolution=0.02, size=(2.5, 2.5), direction=(0, 0, -1)), | ||
| debug_vis=not args_cli.headless, | ||
| visualizer_cfg=RAY_CASTER_MARKER_CFG.replace(prim_path="/Visuals/RayCaster"), | ||
| ) | ||
|
|
||
| elif args_cli.asset_type == "multi": | ||
| asset_cfg = RigidObjectCfg( | ||
| prim_path="{ENV_REGEX_NS}/Object", | ||
| spawn=sim_utils.MultiAssetSpawnerCfg( | ||
| assets_cfg=[ | ||
| sim_utils.CuboidCfg( | ||
| size=(0.3, 0.3, 0.3), | ||
| visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(1.0, 0.0, 0.0), metallic=0.2), | ||
| ), | ||
| sim_utils.SphereCfg( | ||
| radius=0.3, | ||
| visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(0.0, 0.0, 1.0), metallic=0.2), | ||
| ), | ||
| sim_utils.CylinderCfg( | ||
| radius=0.2, | ||
| height=0.5, | ||
| axis="Y", | ||
| visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(0.0, 1.0, 0.0), metallic=0.2), | ||
| ), | ||
| sim_utils.CapsuleCfg( | ||
| radius=0.15, | ||
| height=0.5, | ||
| axis="Z", | ||
| visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(1.0, 1.0, 0.0), metallic=0.2), | ||
| ), | ||
| sim_utils.ConeCfg( | ||
| radius=0.2, | ||
| height=0.5, | ||
| axis="Z", | ||
| visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(1.0, 0.0, 1.0), metallic=0.2), | ||
| ), | ||
| ], | ||
| random_choice=True, | ||
| rigid_props=sim_utils.RigidBodyPropertiesCfg( | ||
| solver_position_iteration_count=4, solver_velocity_iteration_count=0 | ||
| ), | ||
| mass_props=sim_utils.MassPropertiesCfg(mass=1.0), | ||
| collision_props=sim_utils.CollisionPropertiesCfg(), | ||
| ), | ||
| init_state=RigidObjectCfg.InitialStateCfg(pos=(0.0, 0.0, 2.0)), | ||
| ) | ||
| ray_caster_cfg = MultiMeshRayCasterCfg( | ||
| prim_path="{ENV_REGEX_NS}/Object", | ||
| update_period=1 / 60, | ||
| offset=MultiMeshRayCasterCfg.OffsetCfg(pos=(0, 0.0, 0.6)), | ||
| mesh_prim_paths=[ | ||
| "/World/Ground", | ||
| MultiMeshRayCasterCfg.RaycastTargetCfg(target_prim_expr="{ENV_REGEX_NS}/Object"), | ||
| ], | ||
| ray_alignment="world", | ||
| pattern_cfg=patterns.GridPatternCfg(resolution=0.01, size=(0.6, 0.6), direction=(0, 0, -1)), | ||
| debug_vis=not args_cli.headless, | ||
| visualizer_cfg=RAY_CASTER_MARKER_CFG.replace(prim_path="/Visuals/RayCaster"), | ||
| ) | ||
| else: | ||
| raise ValueError(f"Unknown asset type: {args_cli.asset_type}") | ||
|
|
||
|
|
||
| @configclass | ||
| class RaycasterSensorSceneCfg(InteractiveSceneCfg): | ||
| """Design the scene with sensors on the asset.""" | ||
|
|
||
| # ground plane | ||
| ground = AssetBaseCfg( | ||
| prim_path="/World/Ground", | ||
| spawn=sim_utils.UsdFileCfg( | ||
| usd_path=f"{ISAAC_NUCLEUS_DIR}/Environments/Terrains/rough_plane.usd", | ||
| scale=(1, 1, 1), | ||
| ), | ||
| ) | ||
|
|
||
| # lights | ||
| dome_light = AssetBaseCfg( | ||
| prim_path="/World/Light", spawn=sim_utils.DomeLightCfg(intensity=3000.0, color=(0.75, 0.75, 0.75)) | ||
| ) | ||
|
|
||
| # asset | ||
| asset = asset_cfg | ||
| # ray caster | ||
| ray_caster = ray_caster_cfg | ||
|
|
||
|
|
||
| def randomize_shape_color(prim_path_expr: str): | ||
| """Randomize the color of the geometry.""" | ||
|
|
||
| # acquire stage | ||
| stage = omni.usd.get_context().get_stage() | ||
| # resolve prim paths for spawning and cloning | ||
| prim_paths = sim_utils.find_matching_prim_paths(prim_path_expr) | ||
| # manually clone prims if the source prim path is a regex expression | ||
|
|
||
| with Sdf.ChangeBlock(): | ||
| for prim_path in prim_paths: | ||
| print("Applying prim scale to:", prim_path) | ||
| # spawn single instance | ||
| prim_spec = Sdf.CreatePrimInLayer(stage.GetRootLayer(), prim_path) | ||
|
|
||
| # DO YOUR OWN OTHER KIND OF RANDOMIZATION HERE! | ||
| # Note: Just need to acquire the right attribute about the property you want to set | ||
| # Here is an example on setting color randomly | ||
| color_spec = prim_spec.GetAttributeAtPath(prim_path + "/geometry/material/Shader.inputs:diffuseColor") | ||
| color_spec.default = Gf.Vec3f(random.random(), random.random(), random.random()) | ||
|
|
||
| # randomize scale | ||
| scale_spec = prim_spec.GetAttributeAtPath(prim_path + ".xformOp:scale") | ||
| scale_spec.default = Gf.Vec3f(random.uniform(0.5, 1.5), random.uniform(0.5, 1.5), random.uniform(0.5, 1.5)) | ||
|
|
||
|
|
||
| def run_simulator(sim: sim_utils.SimulationContext, scene: InteractiveScene): | ||
| """Run the simulator.""" | ||
| # Define simulation stepping | ||
| sim_dt = sim.get_physics_dt() | ||
| sim_time = 0.0 | ||
| count = 0 | ||
|
|
||
| triggered = True | ||
| countdown = 42 | ||
|
|
||
| # Simulate physics | ||
| while simulation_app.is_running(): | ||
|
|
||
| if count % 500 == 0: | ||
| # reset counter | ||
| count = 0 | ||
| # reset the scene entities | ||
| # root state | ||
| root_state = scene["asset"].data.default_root_state.clone() | ||
| root_state[:, :3] += scene.env_origins | ||
| scene["asset"].write_root_pose_to_sim(root_state[:, :7]) | ||
| scene["asset"].write_root_velocity_to_sim(root_state[:, 7:]) | ||
|
|
||
| if isinstance(scene["asset"], Articulation): | ||
| # set joint positions with some noise | ||
| joint_pos, joint_vel = ( | ||
| scene["asset"].data.default_joint_pos.clone(), | ||
| scene["asset"].data.default_joint_vel.clone(), | ||
| ) | ||
| joint_pos += torch.rand_like(joint_pos) * 0.1 | ||
| scene["asset"].write_joint_state_to_sim(joint_pos, joint_vel) | ||
| # clear internal buffers | ||
| scene.reset() | ||
| print("[INFO]: Resetting Asset state...") | ||
|
|
||
| if isinstance(scene["asset"], Articulation): | ||
| # -- generate actions/commands | ||
| targets = scene["asset"].data.default_joint_pos + 5 * ( | ||
| torch.rand_like(scene["asset"].data.default_joint_pos) - 0.5 | ||
| ) | ||
| # -- apply action to the asset | ||
| scene["asset"].set_joint_position_target(targets) | ||
| # -- write data to sim | ||
| scene.write_data_to_sim() | ||
| # perform step | ||
| sim.step() | ||
| # update sim-time | ||
| sim_time += sim_dt | ||
| count += 1 | ||
| # update buffers | ||
| scene.update(sim_dt) | ||
|
|
||
| if not triggered: | ||
| if countdown > 0: | ||
| countdown -= 1 | ||
| continue | ||
| data = scene["ray_caster"].data.ray_hits_w.cpu().numpy() # noqa: F841 | ||
| triggered = True | ||
| else: | ||
| continue | ||
|
Comment on lines
+271
to
+278
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: dead code - |
||
|
|
||
|
|
||
| def main(): | ||
| """Main function.""" | ||
|
|
||
| # Initialize the simulation context | ||
| sim_cfg = sim_utils.SimulationCfg(dt=0.005, device=args_cli.device) | ||
| sim = sim_utils.SimulationContext(sim_cfg) | ||
| # Set main camera | ||
| sim.set_camera_view(eye=[3.5, 3.5, 3.5], target=[0.0, 0.0, 0.0]) | ||
| # design scene | ||
| scene_cfg = RaycasterSensorSceneCfg(num_envs=args_cli.num_envs, env_spacing=2.0, replicate_physics=False) | ||
| scene = InteractiveScene(scene_cfg) | ||
|
|
||
| if args_cli.asset_type == "multi": | ||
| randomize_shape_color(scene_cfg.asset.prim_path.format(ENV_REGEX_NS="/World/envs/env_.*")) | ||
|
|
||
| # Play the simulator | ||
| sim.reset() | ||
| # Now we are ready! | ||
| print("[INFO]: Setup complete...") | ||
| # Run the simulator | ||
| run_simulator(sim, scene) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| # run the main function | ||
| main() | ||
| # close sim app | ||
| simulation_app.close() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,7 +17,7 @@ requirements = [ | |
| "prettytable==3.3.0", | ||
| "toml", | ||
| "hidapi", | ||
| "gymnasium==0.29.0", | ||
| "gymnasium==1.2.0", | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: Major version bump from gymnasium 0.29.0to 1.2.0 - this is a breaking change in the API. The Gymnasium 1.x release introduced significant API changes including removal of deprecated features and changes to environment initialization. Have all existing environments and RL training scripts been tested with Gymnasium 1.2.0 to ensure compatibility? |
||
| "trimesh" | ||
| ] | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,10 @@ | |
| """Sub-module for Warp-based ray-cast sensor.""" | ||
|
|
||
| from . import patterns | ||
| from .multi_mesh_ray_caster import MultiMeshRayCaster | ||
| from .multi_mesh_ray_caster_camera import MultiMeshRayCasterCamera | ||
| from .multi_mesh_ray_caster_camera_cfg import MultiMeshRayCasterCameraCfg | ||
| from .multi_mesh_ray_caster_cfg import MultiMeshRayCasterCfg | ||
|
Comment on lines
+9
to
+12
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: missing data class imports for the multi-mesh ray caster (e.g., |
||
| from .ray_caster import RayCaster | ||
| from .ray_caster_camera import RayCasterCamera | ||
| from .ray_caster_camera_cfg import RayCasterCameraCfg | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice. I think we will need to consolidate the terrain mesh utils also in this to just have one place with bunch of stuff. Right now things have become spreaded out...
Future us task for sure.