NVIDIA IsaacSim¶
Comprehensive robotics simulation platform built on Omniverse.
Overview¶
IsaacSim is NVIDIA's flagship robotics simulator offering:
- Photorealistic ray-traced rendering
- Accurate PhysX 5 physics engine
- ROS/ROS2 integration
- Synthetic data generation for ML
- Digital twin capabilities
Installation¶
Via Omniverse Launcher¶
- Download Omniverse Launcher
- Install Isaac Sim from the launcher
- Launch and accept EULA
Via Docker¶
docker pull nvcr.io/nvidia/isaac-sim:2023.1.1
docker run --name isaac-sim --entrypoint bash -it \
--gpus all \
-e "ACCEPT_EULA=Y" \
--rm \
--network=host \
-v ~/docker/isaac-sim/cache/kit:/isaac-sim/kit/cache:rw \
-v ~/docker/isaac-sim/cache/ov:/root/.cache/ov:rw \
-v ~/docker/isaac-sim/cache/pip:/root/.cache/pip:rw \
-v ~/docker/isaac-sim/cache/glcache:/root/.cache/nvidia/GLCache:rw \
-v ~/docker/isaac-sim/cache/computecache:/root/.nv/ComputeCache:rw \
-v ~/docker/isaac-sim/logs:/root/.nvidia-omniverse/logs:rw \
-v ~/docker/isaac-sim/data:/root/.local/share/ov/data:rw \
nvcr.io/nvidia/isaac-sim:2023.1.1
Basic Usage¶
Standalone Python¶
from isaacsim import SimulationApp
# Launch simulation
simulation_app = SimulationApp({"headless": False})
from omni.isaac.core import World
from omni.isaac.core.objects import DynamicCuboid
from omni.isaac.core.utils.nucleus import get_assets_root_path
# Create world
world = World()
world.scene.add_default_ground_plane()
# Add object
cube = world.scene.add(
DynamicCuboid(
prim_path="/World/Cube",
name="cube",
position=[0, 0, 1.0],
size=0.1
)
)
# Reset and run
world.reset()
for i in range(1000):
world.step(render=True)
if i % 100 == 0:
print(f"Cube position: {cube.get_world_pose()[0]}")
simulation_app.close()
With Robot¶
from isaacsim import SimulationApp
simulation_app = SimulationApp({"headless": False})
from omni.isaac.core import World
from omni.isaac.franka import Franka
from omni.isaac.core.utils.types import ArticulationAction
# Create world and robot
world = World()
franka = world.scene.add(Franka(prim_path="/World/Franka", name="franka"))
world.reset()
# Control robot
for _ in range(1000):
# Get observation
joint_positions = franka.get_joint_positions()
# Compute action
action = ArticulationAction(
joint_positions=joint_positions + 0.01 # Small movement
)
# Apply action
franka.apply_action(action)
world.step(render=True)
simulation_app.close()
Robot Assets¶
Loading from Nucleus¶
from omni.isaac.core.utils.nucleus import get_assets_root_path
from omni.isaac.core.utils.stage import add_reference_to_stage
assets_root_path = get_assets_root_path()
# Load Franka robot
robot_path = assets_root_path + "/Isaac/Robots/Franka/franka_alt_fingers.usd"
add_reference_to_stage(usd_path=robot_path, prim_path="/World/Franka")
Importing URDF¶
from omni.isaac.core.utils.extensions import enable_extension
enable_extension("omni.importer.urdf")
import omni.kit.commands
from pxr import UsdPhysics
# Import URDF
omni.kit.commands.execute(
"URDFParseAndImportFile",
urdf_path="/path/to/robot.urdf",
import_config=omni.isaac.core.utils.extensions.get_extension_path_from_name(
"omni.importer.urdf"
) + "/data/configs/ur10.json"
)
Sensors¶
RGB Camera¶
from omni.isaac.sensor import Camera
import numpy as np
# Create camera
camera = Camera(
prim_path="/World/Camera",
position=np.array([2.0, 2.0, 2.0]),
frequency=30,
resolution=(640, 480)
)
# Initialize
camera.initialize()
# Get image
world.step(render=True)
rgb = camera.get_rgba()[:, :, :3] # Remove alpha channel
Depth Camera¶
from omni.isaac.sensor import Camera
camera = Camera(
prim_path="/World/DepthCamera",
position=np.array([2.0, 2.0, 2.0])
)
camera.initialize()
camera.add_distance_to_camera_to_frame()
world.step(render=True)
depth = camera.get_distance_to_camera()
LiDAR¶
from omni.isaac.range_sensor import LidarRtx
lidar = LidarRtx(
prim_path="/World/Lidar",
config="Example_Rotary",
translation=np.array([0, 0, 1.0])
)
lidar.initialize()
world.step(render=True)
point_cloud = lidar.get_point_cloud()
ROS/ROS2 Integration¶
ROS2 Bridge¶
# Enable ROS2 bridge extension
from omni.isaac.core.utils.extensions import enable_extension
enable_extension("omni.isaac.ros2_bridge")
# Configure topics in Simulation menu -> ROS2 -> Bridges
Publishing Joint States¶
# ROS2 joint state publishing happens automatically when bridge is enabled
# Subscribe from ROS2 side:
# ros2 topic echo /joint_states
Synthetic Data Generation¶
Replicator for Data Gen¶
import omni.replicator.core as rep
# Setup camera
camera = rep.create.camera(position=(2, 2, 2))
# Randomize objects
def randomize_scene():
cube = rep.get.prims(path_pattern="/World/Cube")
with cube:
rep.modify.pose(
position=rep.distribution.uniform((-1, -1, 0.5), (1, 1, 1.5)),
rotation=rep.distribution.uniform((0, 0, 0), (360, 360, 360))
)
# Register randomizer
rep.randomizer.register(randomize_scene)
# Setup writer
writer = rep.WriterRegistry.get("BasicWriter")
writer.initialize(output_dir="output", rgb=True, bounding_box_2d_tight=True)
# Run
rep.orchestrator.run()
Domain Randomization¶
from omni.isaac.core.utils.prims import get_prim_at_path
from pxr import UsdShade
def randomize_appearance():
# Randomize object color
prim = get_prim_at_path("/World/Cube")
material = UsdShade.MaterialBindingAPI(prim).ComputeBoundMaterial()[0]
# Set random color
color = np.random.rand(3)
material.GetInput("diffuse_color_constant").Set(tuple(color))
def randomize_physics():
from omni.isaac.core.materials import PhysicsMaterial
# Randomize friction
material = PhysicsMaterial(prim_path="/World/Physics/Material")
material.set_static_friction(np.random.uniform(0.2, 1.0))
material.set_dynamic_friction(np.random.uniform(0.2, 1.0))
# Apply in reset
def reset():
randomize_appearance()
randomize_physics()
world.reset()
Performance Optimization¶
Headless Mode¶
Physics Settings¶
from omni.physx.scripts import physicsUtils
# Adjust physics parameters for speed
physicsUtils.set_physics_scene_asyncsimrender(True)
physicsUtils.set_physics_max_velocity(1000.0)
# Lower physics rate if accuracy allows
world.set_simulation_dt(physics_dt=1.0/60.0, rendering_dt=1.0/30.0)
Common Tasks¶
Pick and Place¶
from omni.isaac.core.tasks import BaseTask
class PickAndPlaceTask(BaseTask):
def __init__(self):
super().__init__()
self.robot = None
self.cube = None
def set_up_scene(self, scene):
super().set_up_scene(scene)
# Add robot
self.robot = scene.add(Franka(prim_path="/World/Franka"))
# Add object
self.cube = scene.add(DynamicCuboid(
prim_path="/World/Cube",
position=[0.5, 0, 0.05],
size=0.05
))
def get_observations(self):
return {
"robot_state": self.robot.get_joint_positions(),
"cube_position": self.cube.get_world_pose()[0]
}
def calculate_reward(self):
# Implement reward logic
pass
Next Steps¶
- IsaacLab - RL framework built on IsaacSim
- ROS2 Integration - Detailed ROS2 setup
- RL Training - Train RL agents