Prerequisites

Install FastSim and the Isaac Lab provider in one Python environment. The Run uses Isaac Lab 3.0 / Isaac Sim 6.0 with a visible window.

Configuration, key by key

yaml
schema: fastsim/2                    # FastSim vNext Run schema.
name: demo-control-generic-articulation
backend: isaaclab                    # Resolve the door's Isaac Lab USD variant.

runtime:
  launch_profile: visible            # Show the real simulator window.
  physics_hz: 60                     # Physics integration frequency.
  control_hz: 60                     # Control-frame admission frequency.
  seed: 37                           # Reproducible reset seed.

scenario:
  scene:
    articulations:                   # Jointed assets that are not robots.
      door:                          # Alias passed to the control API.
        use: articulation://fastsim/demo-door
        pose:
          xyz_m: [0.0, 0.0, 0.0]    # Root position in world metres.
          quat_xyzw: [0.0, 0.0, 0.0, 1.0]
        initial_state:
          joints:
            door_hinge: 0.0          # Initial angle in radians.

The door component declares resource group door and maps it to physical axis door_hinge. Application code selects the group; it does not depend on USD prim paths.

Python, line by line

  1. The imports provide an async event loop, finite-number checks, a reliable path to run.yaml, and the public fastsim package.
  2. The constants locate the Run, keep the final pose visible, and define the exact three-frame result plus the 0.20 +/- 0.08 rad acceptance band.
  3. main() is asynchronous because control waits must not block FastSim's event loop.
  4. fastsim.app(..., planning_reads=True) creates the direct-development facade and enables the scene-state read performed at the end.
  5. async with gives this block exclusive application ownership and guarantees cleanup.
  6. start() starts the real backend; the first one-second sleep makes the initial door pose visible before motion begins.
  7. control.targets() asks FastSim which physical entities and resource groups are actually controllable in the compiled Run.
  8. next(...) selects the descriptor whose canonical ID is articulations.door; printing it makes the resolved binding explicit.
  9. control.joints(...) submits one ordered chunk and asynchronously waits for its terminal result.
  10. actor="door" uses the Scenario alias. FastSim resolves it to articulations.door without exposing the backend path.
  11. group="door" selects the one-axis resource group declared by the component.
  12. path=[[0.0], [0.75], [0.20]] starts closed, opens to 0.75 rad, and returns to 0.20 rad. Each row must match the group's declared axis order.
  13. dt=0.75 places adjacent path frames 0.75 simulated seconds apart.
  14. timeout=20.0 bounds the caller's wait; it is not a sleep or a physics duration.
  15. pause() preserves the final world while establishing a stable read boundary.
  16. scene.state() obtains portable live state; next(...) selects the door's articulation state.
  17. The validation block requires succeeded, exactly 3/3 frames, one radian joint, a finite angle, and error no greater than 0.08 rad; failure raises and makes the process exit non-zero.
  18. The three prints report terminal status, applied/planned frames, and measured angle, error, and tolerance.
  19. The final sleep holds the paused door on screen for three seconds.
  20. asyncio.run(main()) starts the program when the file is run directly.

Acceptance gates

  • Terminal status must be succeeded and frame counts must be exactly 3/3.
  • Final state must contain exactly one finite radian joint.
  • The measured angle must be within 0.20 +/- 0.08 rad. The explicit band covers the controller's terminal tolerance without accepting a visibly wrong pose.
  • The visible Isaac Lab acceptance run on 2026-08-25 measured 0.236 rad, an error of 0.036 rad, and exited with code 0.

Run it

From this case directory:

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

The visible door should open and return partway. The program itself enforces the gates above; printed output alone is not treated as a pass.

Verification level

REAL VISIBLE ISAAC PASS. The native run completed all 3/3 frames, measured 0.236 rad against the 0.20 +/- 0.08 rad gate, exited normally, and left no Isaac worker process behind.

Why there is no open_door() API

“Open” is task semantics. FastSim core only needs to know that an ordered physical joint chunk targets one declared resource group. A rule-based plugin, model, teleoperation source, or direct application may decide what 0.75 rad means.

Common errors

  • NO_RESOURCE_GROUP: use control.targets() to inspect valid groups instead of guessing from an asset filename.
  • PATH_WIDTH_MISMATCH: every path row must contain one value for this one-axis door.
  • A window that closes immediately after an exception: read the terminal error; the async with block intentionally performs cleanup on failure.