-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Add multirotor vision-based navigation task and acceleration, velocity and position controllers #3895
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?
Add multirotor vision-based navigation task and acceleration, velocity and position controllers #3895
Changes from 250 commits
5c927da
7864b21
dd61d3e
82819d8
f5af366
50fc172
c891112
85fbe94
c251913
22040a7
50622c9
0c2955b
f71fd00
72216ce
737aff6
41924f2
a194b3b
9a0f5ab
80908ed
30ceb59
4439744
473c295
ac2f724
e14defd
5d3fda7
7e037d4
8538b90
0a832b5
e1a5780
c09b9d0
b2103cb
335dc71
3c5bd81
976b2bc
0e0c5ce
9c03606
0d3f5be
ee12bb3
bc6886f
8d84fb1
8796999
9b2871b
64a9a61
b079a0e
658fae3
04cd1c5
ee857ce
461affb
89a22b9
00ee21e
94489da
c24fd6d
6235db8
4ae38af
bd277a4
62c58a7
c5bc93b
a3b09a8
a19cce3
1b5ad99
c48f0eb
9e880ad
27487e7
4197836
9fd4819
bb113c9
f4e48fd
dfc9283
8b2de9b
c97b616
0dbb2da
ddcc3d8
dfd08df
519f956
e27edff
b828403
a09c378
87cc1b6
fe5c95d
360f2be
aa90eed
44d4728
a11f1ff
0c3f77c
3ea7bc1
ab2783f
22568b9
bd3fd4e
f8ff26f
739309f
8e5724e
87c68cd
c8dfe1d
f583dda
9fdb66f
5de8148
2fcc00e
b055cb0
1760a21
f7723da
42265a7
5cd7a66
83dd1f4
3bb369a
d8d25eb
f0000d3
cebc6c6
c605b05
c82d66b
7177e2e
f2abb3b
2f4e363
e263236
a80a1a9
2429a66
df2e33f
5a52119
71e0ec6
e8ddd2c
febac18
a0a6b2b
af1436c
9cb7c99
e5cfa4c
f417b07
968b64f
64177b3
3eacbd5
ac20dbb
b39285c
9be0504
191a4b9
11cca2b
d6a82ba
93c7034
f90df4d
bf9bfe3
3372a9d
9284811
1692487
fd90c34
af34142
b17c7c2
cdb9380
f0dc677
d9348b1
193e02a
b0f90d6
a717121
104f66d
476798d
9d59216
b6d30f0
3292b8d
ef95d3f
4357abd
06e6ee7
a46ff1f
658ce9c
ecaad98
a54454f
f87ac8b
9ddab8f
0f7635e
5f4b475
412cf7a
ea6f322
2b6421e
f5ca3e3
b467e79
362e358
657d8f2
92750b2
766bf98
2e152f0
8c59a07
4b05304
153894b
2c4040e
6a1d06e
685885e
7b312d9
98ec5c5
35c5c1f
4fed595
c3115cd
ae34fa7
dadec71
571e4e9
80542aa
8bedf43
c62ae1d
aba6b95
c4218df
f525ff1
6e89052
b7f06dc
c3dcb2b
387f3d9
c3f5987
9286f62
7e85940
d8d6ac6
b0c5cfe
ac10a8c
22f8758
8587f17
865f407
8a01a1d
6b7e40b
2586248
895b888
df0384f
05fa7bc
280b979
256e4cb
4840b39
550956b
0d794b1
71028fa
577671d
27545b4
b9ed6a4
51f002e
f28d9d3
3cdb6e3
80d9dbb
0fb3f18
3c502d0
65ff02b
91ac1ca
5b37927
fcb0ee9
ddfd5cc
4c32c89
884f862
29a07ec
291e8db
6f19575
5cede36
e01ad86
c03d563
f757ed3
efb6e60
cb24ac1
cc4c19c
167225f
f7d0c84
e7c9c9c
357c6a0
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 |
|---|---|---|
|
|
@@ -12,3 +12,4 @@ | |
| *.hdf5 filter=lfs diff=lfs merge=lfs -text | ||
|
|
||
| *.bat text eol=crlf | ||
| docs/make.bat text eol=crlf | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| [submodule "source/isaaclab_tasks/isaaclab_tasks/manager_based/drone_arl/robot_model"] | ||
| path = source/isaaclab_tasks/isaaclab_tasks/manager_based/drone_arl/robot_model | ||
| url = https://github.com/ntnu-arl/robot_model.git |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,296 @@ | ||
| # 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) | ||
|
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. style: print statement says 'prim scale' but the function randomizes both color and scale |
||
| # 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 | ||
|
|
||
| # Simulate physics | ||
| while simulation_app.is_running(): | ||
|
|
||
| if count % 500 == 0: | ||
| # reset counter | ||
| count = 0 | ||
|
Comment on lines
+229
to
+231
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: counter is reset to 0 immediately after checking if it equals 0, creating unnecessary reset cycles. Is the intention to reset every 500 steps or reset immediately after the first reset? |
||
| # 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) | ||
|
|
||
|
|
||
| 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() | ||
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.
style: This specific rule is redundant since line 14 already covers all
.batfiles with CRLF line endings. The general pattern*.bat text eol=crlfshould includedocs/make.bat. Is there a specific reason this file needs explicit handling beyond the general*.batrule?