What is an online controller?
An online controller is a controller policy that runs in its own controller-host cloud node — separate from the simulation. The controller host communicates with a plant (thecyberwave-sim physics worker or a live robot) over MQTT and WebRTC. The plant only steps physics and publishes state; it never runs the controller logic in its own loop.
This split is the defining property of online controllers: the control loop and the physics loop live in different processes, connected by a wire. Because that wire is the same whether the plant is a simulator or a real robot, an online controller can target either with no code changes.
Cyberwave supports basic mjlab today — online controllers run against both basic MuJoCo and vectorized mjlab backends over the same wire. We’re planning to release a richer Cyberwave mjlab extension with useful helpers in the future.
Online controller types
Three policy types run on the online-controller host path:Code
A custom Python controller you write — a
control() function or a stateful controller class — optionally carrying named model weights.Random
A random policy, optionally shaped by weights. Useful for smoke-testing a plant or establishing a baseline.
RL Task
A trained RL checkpoint exported from an RL Task, evaluated closed-loop against the plant.
teleop, navigation, motion, and mlmodel/vla — do not use the online-controller host path. They run on their own command-triggered or cloud inference paths.
How controllers are routed
Routing is decided by the explicit policy type plus a structured controller family — never by keyword or name matching. When you start a run, the backend resolves the assigned policy and dispatches it to the matching controller host.Runtime interfaces
Each online controller interacts with its plant through a sim-shaped interface, so your controller code reads state and writes commands without knowing whether the plant is simulated or live.codeand code + weights controllers see a MuJoCo-shaped sim view — a familiarsim.data/sim.modelsurface for reading joint state and writing controls.rltask(RL) policies use aSimulationLikeinterface — the same observation/action contract an RL policy expects during training.
Authoring code controllers
Code controllers support two authoring modes.Function mode (default)
Define acontrol function. The host calls it each control step.
sim— the MuJoCo-shaped sim view (read state, writectrl).sim_time— current simulation time in seconds.artifacts— a dict of named weights/files (present only for code + weights controllers).
Class mode (entrypoint_type="class")
For stateful controllers that load weights once and keep state across steps, use class mode. The host instantiates the class once, then calls it each step.
entrypoint_type="class" on the policy to opt into class mode. Use it whenever your controller needs to load model weights or maintain internal state between steps.
Named artifacts and weights
A code + weights controller attaches one or more named binary files — typically.pt, .onnx, or .safetensors. Each artifact carries:
The artifacts reach your code differently per authoring mode:
- Function mode — delivered as the third positional argument, the
artifactsdict. - Class mode — delivered to
__init__as theartifactsargument, so you can load them once.
CPU vs GPU compute
Controller policies that carry a model —mlmodel/vla, random, or code-with-weights — accept an inference device. This choice selects where the controller host runs inference and is independent of the simulation’s physics device.
Key rules:
cpuis the default. It runs on an inexpensive CPU host.- The saved
deviceis just the default. You can override it per-run at deploy time without changing the saved policy. deviceis rejected for policies that carry no model — for example a plaincodecontroller or ateleoppolicy. Those have nothing to run inference on.
The
device choice is purely about controller inference. It does not affect which device the plant uses to step physics.Live mode
Because the controller host talks to its plant purely over MQTT and WebRTC, the samecode, random, or rltask controller can target a live robot plant instead of cyberwave-sim — with no controller code changes. The controller reads state and writes commands exactly as it does in simulation; only the plant on the other end of the wire changes.
Simulation backends
Online controllers run against two simulation backends over the same wire:- Basic MuJoCo — a single
MjModel/MjDataplant. - Vectorized mjlab — a manager-based, GPU-capable plant.
Quick example
Create a code controller policy, then run it against a twin.1
Create the controller policy
Create a
code policy with your control function (or class).2
Run it on a twin
Execute the policy against a robot twin. The backend dispatches the controller to its host, which drives the plant.
3
Stop the run
Stop a single policy run, or stop every online controller in an environment at once.
Deploy a trained RL policy
Anrltask controller is created by publishing a trained checkpoint, then assigned to a twin like any other controller. Using the OpenArm pick-up policy from the RL task walkthrough:
API reference
Where to go next
RL Tasks
Train and export RL policies to run as
rltask online controllers.Uploading Policies
Bring your own code and weights as a controller policy.
Simulation
How the simulation plant steps physics and publishes state.