Skip to content

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

  1. Download Omniverse Launcher
  2. Install Isaac Sim from the launcher
  3. 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

# Run without GUI
simulation_app = SimulationApp({"headless": True})

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