Scene and Simulation Setup#
In this lesson, we’ll bootstrap Isaac Lab, load the Franka cube task scene, and configure Newton as the physics engine. By the end you’ll have a live environment stepping in simulation with the robot holding its default pose.
In this lesson, we will:
Bootstrap an interactive notebook with
AppLauncherand relate it to the scripts’launch_simulationlifecycle.Inspect how the task scene assembles a Franka, a cube, a table, and a ground plane.
Configure the three-layer Newton simulation stack.
Build the environment and step it with zero actions.
Part 1: Initial Setup and Imports#
For an interactive notebook, AppLauncher starts the application and enables the Viser web visualizer before the environment is constructed. The canonical external-project scripts use Isaac Lab 3.0’s launch_simulation context manager instead; this lets them resolve the task configuration and selected backends before starting the runtime.
from isaaclab.app import AppLauncher
app_launcher = AppLauncher({"visualizer": ["viser"], "visualizer_max_worlds": 4})
simulation_app = app_launcher.app
import gymnasium as gym
import torch
import isaaclab_tasks # noqa: F401
import franka_cube.tasks # noqa: F401
from franka_cube.tasks.direct.franka_cube.franka_cube_env import FrankaCubeEnv
from franka_cube.tasks.direct.franka_cube.franka_cube_env_cfg import FrankaCubeEnvCfg
Important
The runtime must be active before constructing or stepping the environment. In the notebook, create AppLauncher before the environment. In random_agent.py, train.py, and play.py, keep environment creation inside with launch_simulation(env_cfg, args_cli):.
The notebook version also defines display helpers (for example display_active_viewer) that embed the live Viser viewer inside Jupyter. Those are display conveniences and are not required to run the environment.
Part 2: Defining the Scene#
The FrankaCubeEnv already implements the scene used by the task: a fixed-base Franka, a rigid cube, a SeattleLab table, and a shifted ground plane below the table. The scene is assembled in _setup_scene, which registers the Newton contact callback, spawns the robot and cube, adds the table and ground, clones the per-environment copies, and adds a dome light.
import isaaclab.sim as sim_utils
from isaaclab.assets import Articulation, RigidObject
from isaaclab.sim.spawners.from_files import GroundPlaneCfg, spawn_ground_plane
from isaaclab.utils.assets import ISAAC_NUCLEUS_DIR
def _setup_scene(self):
self._register_newton_contact_callback()
self.robot = Articulation(self.cfg.robot_cfg)
self.cube = RigidObject(self.cfg.cube)
spawn_ground_plane(prim_path="/World/ground", cfg=GroundPlaneCfg(), translation=(0.0, 0.0, -1.05))
table_cfg = sim_utils.UsdFileCfg(usd_path=f"{ISAAC_NUCLEUS_DIR}/Props/Mounts/SeattleLabTable/table_instanceable.usd")
table_cfg.func(
"/World/envs/env_.*/Table",
table_cfg,
translation=(0.5, 0.0, 0.0),
orientation=(0.0, 0.0, 0.70711, 0.70711),
)
self.scene.clone_environments(copy_from_source=False)
if self.device == "cpu":
self.scene.filter_collisions(global_prim_paths=[])
self.scene.articulations["robot"] = self.robot
self.scene.rigid_objects["cube"] = self.cube
light_cfg = sim_utils.DomeLightCfg(intensity=2000.0, color=(0.75, 0.75, 0.75))
light_cfg.func("/World/Light", light_cfg)
The call to clone_environments is what makes Isaac Lab fast: it replicates the single scene into many parallel environments on the GPU, which is essential for RL where we train across hundreds or thousands of environments at once.
Part 3: Setting Up the Simulation#
The key to running Isaac Lab with Newton is a three-layer physics configuration: MJWarpSolverCfg (the solver itself), wrapped by NewtonCfg (the physics engine), wrapped by SimulationCfg (top-level simulation parameters).
Parameter |
Value |
Description |
|---|---|---|
|
|
Uses the Newton contact solver |
|
|
Integration method ( |
|
|
Maximum number of constraints per world |
|
|
Maximum number of contact points per world |
|
|
Frictional-to-normal constraint impedance ratio |
|
|
Contact friction cone ( |
|
|
Number of solver iterations |
|
|
Number of line-search iterations |
|
|
Extra continuous-collision passes for difficult contacts |
|
|
Enable parallel line search in MuJoCo |
|
|
Keep Newton’s global contact defaults in control |
import isaaclab.sim as sim_utils
from isaaclab_newton.physics import MJWarpSolverCfg, NewtonCfg
from isaaclab.sim import SimulationCfg
notebook_env_cfg.decimation = 2
notebook_env_cfg.solver_cfg = MJWarpSolverCfg(
solver="newton",
integrator="implicitfast",
njmax=2000,
nconmax=1000,
impratio=100.0,
cone="elliptic",
update_data_interval=2,
iterations=20,
ls_iterations=100,
ccd_iterations=80,
ls_parallel=True,
use_mujoco_contacts=False,
)
notebook_env_cfg.newton_cfg = NewtonCfg(
solver_cfg=notebook_env_cfg.solver_cfg,
num_substeps=5,
debug_mode=False,
)
notebook_env_cfg.sim = SimulationCfg(
dt=1 / 120,
render_interval=notebook_env_cfg.decimation,
physics=notebook_env_cfg.newton_cfg,
physics_material=sim_utils.RigidBodyMaterialCfg(
friction_combine_mode="multiply",
restitution_combine_mode="multiply",
static_friction=1.0,
dynamic_friction=1.0,
restitution=0.0,
),
)
Notice how the same solver ideas from Newton Fundamentals (integrator, iterations, cone type, contact limits) reappear here, just wrapped in Isaac Lab’s configuration objects.
Quick Test: Step the Environment#
With the configuration in place, we build the environment through the gym API and run it with zero actions so the robot holds its default pose. Building the environment takes a few minutes the first time while kernels compile.
env_cfg = FrankaCubeEnvCfg()
env_cfg.scene.num_envs = 32
env = gym.make("Template-Franka-Cube-Direct-v0", cfg=env_cfg)
obs, info = env.reset()
# Run with zero actions so the robot holds its default pose
for i in range(1000):
with torch.inference_mode():
actions = torch.zeros(
(env.unwrapped.num_envs, env.unwrapped.cfg.action_space),
device=env.unwrapped.device,
)
obs, reward, terminated, truncated, info = env.step(actions)
print("Done! The scene is at rest with the robot in its default pose.")
Running It End to End#
The canonical, runnable version of everything above lives in the franka_cube extension. Its scripts use launch_simulation to own startup and shutdown. To watch the untrained scene step with a random agent, run this from a JupyterLab terminal:
python scripts/random_agent.py \
--task Template-Franka-Cube-Direct-v0 --num_envs 32 --viz kit
For a bounded headless smoke test, replace --viz kit with --viz none --max_steps 200.
Key Takeaways#
You bootstrapped the notebook with AppLauncher, related that flow to the scripts’ launch_simulation context, saw how the Franka cube scene is assembled and cloned, and configured Newton through the three-layer MJWarpSolverCfg → NewtonCfg → SimulationCfg stack. With a live environment stepping, we’re ready to define what the agent actually senses, does, and is rewarded for.