Isaac Sim Franka Reach

Run a GPU simulator in its own container and evaluate a Franka reach task through RLMesh.

The Isaac Sim example serves a Franka Panda reaching a random target. It runs Isaac Sim 6.1 in a container with an RTX camera and exposes a Gymnasium vector environment through an EnvFactory. A separate Python client connects to the endpoint; it does not import Isaac Sim.

The example needs an RTX GPU with a driver supported by Isaac Sim 6.1, about 11 GB of RAM, and network access to download NVIDIA assets at startup. Its image declares a 16 GiB memory resource for managed runs.

Run locally

From the RLMesh repository root, build the image and start four simulator lanes:

docker build -t franka-reach:dev examples/python/isaacsim
docker run --rm --gpus all --memory=16g -p 127.0.0.1:50051:50051 \
  -e 'RLMESH_MAKE_KWARGS={"lanes":4}' franka-reach:dev

Startup can take around 45 seconds while Isaac Sim loads the scene and assets. In another terminal, with rlmesh[numpy] installed, run the scripted policy:

python examples/python/isaacsim/run_local.py

The policy moves the hand toward target_pos using eef_pos. It evaluates four episodes and prints the episode count, total steps, and success rate. The environment also emits a 224 × 224 RGB image and joint positions, so a model with a matching spec can use the camera instead. The 3D action is a hand-position delta capped at 5 cm; the environment solves the arm inverse kinematics.

Omit RLMESH_MAKE_KWARGS to run the default single lane. The factory still returns a batched environment, but RLMesh serves its one lane as a scalar endpoint. For two or more lanes, the simulator steps them together on the GPU as a lockstep vector environment. Each lane that finishes resets on its next step (NEXT_STEP autoreset). The environment applies its own max_steps limit; multi-lane runs use episodes= rather than per-episode seeds= or max_episode_steps=. The single-lane endpoint accepts all three.

How the container serves the simulator

FrankaReach uses prepare() to start SimulationApp once, then make(lanes=1, image_size=224, max_steps=100) to build the scene. The image runs python -m rlmesh.serve --env franka_reach:FrankaReach under Isaac Sim’s Python. Blocking serving keeps prepare(), make(), reset(), step(), and close() on the same thread. Isaac Sim requires that thread affinity; use the blocking entrypoint for this environment.

If you are adapting an Isaac Lab environment, keep its batched observation and action spaces even when num_envs=1. Return the real terminal observation and reset a finished lane on its next step. RLMesh refuses SAME_STEP autoreset for a one-lane vector environment because the terminal observation has already been replaced. A model receives one lane’s observation in predict(); implement predict_batch() to group model inference across lanes. See Serve an Environment and Performance and Scaling for the serving and batching contracts.

Run on RLMesh Managed

The example Dockerfile pins rlmesh==0.1.0 and includes a dev.rlmesh.package label with the gpu tag. After signing in and selecting your registry namespace, push the same image:

rlmesh login
rlmesh registry login
docker tag franka-reach:dev registry.rlmesh.dev/your-namespace/franka-reach:v1
docker push registry.rlmesh.dev/your-namespace/franka-reach:v1

When the image shows ready in Registry, select it for a new evaluation. Use the SDK version required by your managed deployment if it differs from the Dockerfile default; see Version pinning.