Skip to main content
This walkthrough builds one concrete task from an empty workspace to a deployed policy: an OpenArm learning to pick up a cube off a table, with a wrist depth camera. It uses the Python SDK throughout so you can run it as a reproducible setup script. It ties together the four RL surfaces:

RL Tasks

The entity and editor tabs this script automates.

Scene Sensors

Wiring the wrist depth camera and contact sensors.

Uploading Policies

Upload the trained checkpoint and run it.

Online Controllers

Deploy the policy against a simulated or live robot.

The scene

Four twins make up the task. Each maps to one mjlab scene entity:
The catalog assets (enactic/openarm, cyberwave/generic_cube, intel/realsensed455) must already exist in your workspace’s catalog. On a local stack they are added by make seed.

Prerequisites

Step 1 — Scaffold workspace, project, and environment

Step 2 — Compose the scene

Add the four twins to the environment. The arm is fixed-base, the cube is free, and the camera is docked to the arm’s wrist link.
add_twin places a twin by its link origin; add_twin_centered places it by its visual centre and scales it to dimensions (metres) using the asset’s asset_bounds. Use the centred helper whenever you scale a generic primitive to a real-world size.

Step 3 — Create the RL task

Link the task to the environment and declare the entrypoint files Cyberwave will generate or expect.

Step 4 — Assign scene entities

Tell Cyberwave which twin is which mjlab entity, whether it is articulated, and which actuators the arm exposes. The wrist depth camera is attached as a sensor on the robot entity.
Call rl.get_orchestration_hints(task_uuid) to confirm the robot entity, its actuated joint names, and the camera sensor name (here robot__wrist_cam) before authoring specs against them.

Step 5 — Author actions, observations, and the network

This walkthrough uses PPO with a small shared MLP to stay readable. For a vision policy you would author a CNN backbone that consumes the wrist_depth term — the network builder supports graph topologies for exactly this. See the Network builder section.

Step 6 — Generate files and export

Your task-local Python — the reward function, resets, and terminations — lives in the user-written env_cfg.py inside the export. Cyberwave generates everything else (scene_cfg.py, scene_bindings.py, the spec wrappers, the MuJoCo assets).

Step 7 — Train

Drop the exported folder into cyberwave-rl/tasks/ and train it like any other task:
Training writes checkpoints to logs/<task>/<run>/checkpoints/. The best one is typically best_agent.pt.

Step 8 — Upload the trained policy

See Uploading Policies for the external-URL alternative and upload limits.

Step 9 — Deploy the policy

Publish the checkpoint as an rltask online controller, then assign it to the arm twin and run it. The controller runs in its own controller host and drives the plant over MQTT, so the same policy works against a simulated or a live OpenArm.
Now assign controller_uuid to the openarm twin and start a simulation — see Online Controllers for assigning and running it, including the CPU/GPU compute choice. Alternatively, run a quick cloud inference loop without publishing a controller:

What you authored vs what Cyberwave generated

Where to go next

RL Tasks

Full reference for the editor tabs and export contract.

Uploading Policies

Checkpoint upload, publish, and inference in depth.

Online Controllers

Run the deployed policy against a simulated or live robot.