Verification level

Visible native Isaac. The window shows the two-joint arm visiting four targets in order, while the terminal verifies the one terminal ChunkResult.

Prerequisites

  • FastSim 0.1.0a6, UniRoboSim Core 0.10.0, and unirobosim-isaaclab==0.10.1 in one Python 3.12 environment.
  • Isaac Lab 3.0 / Isaac Sim 6.0, an NVIDIA GPU, and a working display.

Configuration

The robot manifest declares joints joint_1, joint_2 and group arm. The Scenario alias is also arm, but these names mean different things:

  • actor="arm" selects scenario.scene.robots.arm.
  • group="arm" selects the manifest's actuator group containing both joints.

physics_hz and control_hz are both 60 Hz. The configured joint initial state is zero, matching the first target in the path.

Every control argument

python
await simulation.pause()                         # Freeze one fresh control boundary.
operation = await simulation.control.submit_joints(
    actor="arm",           # Which Scenario robot to command.
    group="arm",           # Which actuator resource group to lease.
    path=[                  # Rows are ordered [joint_1, joint_2] targets.
        [0.0, 0.0],
        [1.0, -0.7],
        [-0.9, 0.8],
        [0.5, -0.4],
    ],
    dt=0.35,               # Simulated seconds between adjacent target rows.
    timeout=10.0,          # Upper bound for admission plus terminal completion.
)
await simulation.resume()                        # Let physics consume the path.
result = await operation.result(timeout=10.0)    # Block until one terminal result.
await operation.release()                        # Drop the completed record.

The application still blocks before moving to its next action, but submission and waiting are split around resume(). This is the reliable public pattern for an asynchronous backend: create the chunk from a fresh paused observation, resume physics, then wait for its terminal ChunkResult. A simple await simulation.control.joints(...) is useful while physics is already running at a paced rate; it would deadlock while paused because frames cannot be consumed.

The path uses radians because both manifest joints declare unit rad. FastSim checks axis count, units, finite values, target scope, session authority, and generation before commands reach the backend.

Run it

bash
cd demo/fundamentals/04_blocking_joint_path
fastsim config validate run.yaml --json
python main.py

Expected result: the native Isaac window opens and the arm moves through all four targets in order. The terminal prints Chunk status: succeeded and Applied frames: 4/4. This is a control-execution result; it does not claim that a semantic task such as pick succeeded.

Common errors

  • NO_TARGET: the actor alias does not resolve to a controllable articulation.
  • NO_JOINT_POSITION_SPACE: the provider did not publish joint.position@1.
  • Axis-count error: every path row must contain exactly two values for this group.
  • chunk observation exceeds session freshness window: submit at the explicit paused boundary as shown; an unthrottled backend may outrun an observe-then-submit round trip.
  • Timeout: the operation is cancelled so an unseen chunk cannot continue driving the robot after the caller has given up.

Next

Continue with 05 — Servo preemption.