Check if your robot is already supported
Cyberwave ships 80+ devices in its catalog. Catalog devices likethe-robot-studio/so101 are assets that already exist, and many already have a driver. Check Supported hardware first.
If your robot isn’t there, you can integrate it yourself. Cyberwave connects any device with an API, serial interface or network protocol.
Teams typically bring a brand-new piece of hardware fully online with
Cyberwave in about 2 days, versus the months a bespoke integration
usually takes, because the digital twin, transport, UI, workflows and
data tooling already exist. You only supply the asset and the driver.
How it works
You build two things:- An asset. The reusable definition of your hardware: its 3D meshes and kinematic model (a URDF). Every twin starts from an asset.
- A driver. A small Docker container that bridges your device’s native interface to Cyberwave’s MQTT layer. It publishes telemetry (joint states, odometry, camera frames, sensor data) up to the twin. It turns dashboard, SDK and workflow commands into actions on the device.
Support levels
Pick a target level before you start. Each level builds on the one before it and has a test you can run yourself.
Time budget. These are planning ranges for a team that already has a clean URDF and a working ROS 2 driver: L0 in about an hour, L2 in 1–2 days, L3 in 3–5 days, L4 in 1–2 weeks. Without a ROS 2 driver, add the time it takes you to write one against your vendor SDK.
What you need
- Hardware
- Cyberwave account
- Dev tools
- The device you want to integrate (robot arm, mobile base, sensor, drone, anything with a controllable interface)
- Knowledge of its native interface: ROS 1 / ROS 2, VDA5050, OPC UA, Modbus TCP/RTU, gRPC, REST, or raw serial / USB
- An edge machine to run the driver on: a Raspberry Pi, a Jetson, the robot’s onboard computer, or your Mac for local development
- A working driver or vendor SDK for your robot
Plan your integration
Write a one-paragraph plan: your target level, who maintains the driver (you, Cyberwave, or the community), and whether the driver is open or closed source. Decide early whether the asset will be private to your workspace, shared with your organization, or public. Start private and change it later. For closed-source drivers, see Licensing your driver. Done when: the target level is written down and you know who owns the driver image.Prepare your URDF package
Cyberwave accepts a single ZIP archive with one main.urdf (or .xacro) file and every mesh, texture and material it references. Use relative paths that match the ZIP layout. Include inertials and joint limits now; L1 needs them.
Start from the sample URDF
Want a concrete reference? Download this sample drone URDF (a DJI Mini 4 Pro). It defines abase_link plus four propeller links connected by continuous joints, and references its meshes by path.
Sample URDF: dji-mini-4-pro.zip
A complete single-file URDF (5 links, 4 continuous joints, materials, mesh references). Unzip to read it, add your
meshes/ folder, and re-zip to upload.The downloadable sample references its meshes with
package:// URIs (a ROS
convention). When you build your upload ZIP, switch those to relative paths
that match the archive (for example meshes/body.stl) and include the
referenced .stl files in a meshes/ folder.Validate it locally
The same parser library the platform uses is on PyPI. It has a Python API, not a CLI:type on a joint, say) and records each one in parse_context. Anything under errors means something in your file was discarded. Starting from MuJoCo? cyberwave_robot_format.mjcf.MJCFParser parses MJCF the same way.
Done when: validate() returns no issues and parse_context["errors"] is empty.
Create the asset
Create a private asset in your workspace from the dashboard. Open Add asset from the catalog or the environment editor and choose Upload a 3D file.1
Package: upload your ZIP
On the Package step, drag and drop your ZIP into the URDF Package
(ZIP) drop zone, or click to select it. The archive should contain your
URDF/Xacro plus all referenced meshes. Click Continue.

2
Details: describe your asset
Give the asset a clear name (for example, 
Expand Advanced if you need it. Set Main URDF path only when the ZIP
has more than one URDF, and add an optional Thumbnail. See
Upload form fields.
Click Continue.
Acme Arm v1) and a short
description of what the robot is.

3
Access: choose visibility and workspace
Choose who can see and use the asset, then pick the workspace it belongs to.
Click Create Asset.

POST /api/v1/assets/create-with-urdf. See Upload from the API and the Catalog page.
Note the asset’s slug, for example acme/catalog/my-arm. Your driver and its manifest target it later.
Not a URDF? Other ways to create an asset
Not a URDF? Other ways to create an asset
Add asset offers three choices:
For Describe the object, enter your dimensions and intended interaction, then
follow Describe → Review → Use in the modal header. In Review, edit the
name, build description and dimensions, or request a change with Update design.
Review the assumptions, then continue to Use. Choose Private or Public
and select Build object. Public creation requires confirmation and only
publishes the completed catalog object. Your scene does not become public.You can close the dialog while it builds. Catalog creation saves the object in
your workspace; starting from an environment also adds the completed object to
that scene. The build keeps your reviewed design so later revisions have context.
Review collision geometry, physical properties and robot reach before training.
Spawn a twin and test the model
An asset is a reusable definition. A twin is a live instance of it inside an environment. You can spawn one from the SDK or the dashboard.- SDK
- Dashboard
Declare capabilities and sensors
Capabilities decide which UI panels and SDK classes your twin gets. They live in the asset’s universal schema underextensions.cyberwave.capabilities, next to a sensors list.
can_actuateenables joint control and the re-calibrate action.can_locomoteenables Missions.can_gripandhas_jointsenable the controller UI.- A non-empty
sensorslist enables sensor windows.
id, type (rgb, depth, lidar_3d, imu, …), mount offset, and, for cameras, width, height and FOV. The declared resolution must match the frames your driver actually publishes. If the aspect ratio differs, the object_pose workflow node refuses to deproject (aspect_mismatch). Mimic joints are covered in Mimic joints. Other schema helpers are in Universal schema helpers.
Done when: the twin shows the panels you expect (joint sliders, gripper, sensor windows) and nothing else.
Make it simulate
- Set world physics on the asset, for example
cw.assets.set_physics(asset.uuid, timestep=0.002, ...). All fields, defaults and tuning advice are in Set physics properties. - Enable MuJoCo on the asset under Simulator compatibility. New twins inherit it; existing twins keep their own setting. MuJoCo won’t start if any twin in the environment isn’t marked compatible.
- In the environment editor, open Simulation readiness → Prepare simulation. It lists missing data and proposes fixes (Simulator compatibility).
- Run
cw.affect("simulation"). This starts a MuJoCo instance, which is billable (credits).
Write the driver
The driver bridges your device’s native protocol to the twin. Pick a starting point:- ROS 2 driver
- Python SDK
- AI driver skill
- Fork a reference driver
If your robot already has a ROS 2 driver, subclass
BaseROS2Driver and forward topics with from_ros. You don’t write MQTT code or message conversion:CW_ROS2_AUTO_ACTIVATE=true is recommended during development. The SDK stamps source_type=edge on everything from_ros publishes. Full reference: BaseROS2Driver.CYBERWAVE_API_KEY and CYBERWAVE_TWIN_UUID set. Edge Core injects both in production, along with the other driver environment variables.
If you write listeners, never act on inbound edge* messages. That’s your own feedback (source-type convention).
The full container contract is in Writing compatible drivers.
Done when: the twin mirrors the robot in Live mode. You are at L2.
Declare the interface
Your driver’s interface is acw-driver.yml at the driver repo root, next to the Dockerfile. For ROS 2 drivers it’s the exported manifest.yaml instead. It’s the contract between your hardware bridge, the platform APIs, the web UI and the SDK. It lists which MQTT topics you use and which command strings you accept, so teleop overlays, SDK methods and agents line up with what the hardware actually does. Which file does what: Driver config files.
Point registry_ids at your asset, then declare only the topics and commands your code handles:
mqtt.joint.update becomes cyberwave/joint/{twin_uuid}/update, and mqtt.twin.command becomes cyberwave/twin/{twin_uuid}/command.
Only declare what you actually implement. Arm / joint-bus drivers should omit
the WebRTC topics; camera video flows through child camera twins and the media
service, not WebRTC topics on the arm twin.
python main.py write-manifest.
Register it on your twin
By default the driver registers its own interface when it starts (auto_register_interface = True calls twin.driver.set_schema(...)). To register it without running the driver, or from CI:
set_schema compiles the file on the platform (POST /api/v1/twins/{uuid}/driver-schema), writes metadata.mqtt on the twin, refreshes the catalog cache, and re-binds twin.commands.<name>. Re-run it whenever you change the manifest so teleop, agents and SDK callers stay aligned with your driver. Details: Writing compatible drivers.
set_schema updates this twin’s metadata, so you can iterate without
changing a shared asset definition. When the driver is solid, you can apply the
same metadata.mqtt to the asset so every new twin inherits it.get_supported_commands() list exactly the commands your driver implements.
Package and run the driver
1
Build and test the image locally
Package the driver as a Docker image. Build it for every edge platform you support. For local development, run it with the same environment variables Edge Core uses:
2
Push the image
Push to Docker Hub or to the Cyberwave registry
registry.cyberwave.com (Enterprise; authenticate with docker login registry.cyberwave.com using your API key, see Docker registry). Version tags are immutable there.3
Bind the image to the asset
Edge Core reads the asset’s Edge Core picks the most specific platform key for the host and falls back to
metadata.drivers block and starts one container per linked twin:default. Key rules, multi-container services and env vars: metadata.drivers keys.Set it on the asset from the SDK (read, merge, write), or edit a twin’s metadata in the environment editor under Advanced editing. Changing the asset affects twins created afterwards.4
Pair the edge device
On the machine wired to your hardware, install the CLI and pair:Run
sudo cyberwave pair and select your twin. Edge Core pulls and runs your driver image with the environment variables injected automatically, beside the device, on the robot, in the cloud, or on your laptop. Watch it with cyberwave edge status and cyberwave edge logs -f.Open your environment. The twin should show an online presence indicator,
with joint states or telemetry updating live as the real hardware moves. If it
doesn’t, check
cyberwave edge logs and confirm the driver isn’t exiting on a
hardware-access error.sudo cyberwave pair followed by selecting your twin pulls the image, the container starts, and the twin goes online. More on Edge Core: Cyberwave Edge.
Make it fail safely
Your driver must fail loudly and stop safely.- Exit non-zero when required hardware is missing (a missing
/dev/video*device, a disconnected peripheral). Edge Core then raisesdriver_start_failureand applies its restart policy.run_driver_mainexits with code 1 when the driver raises. - Stop on silence. If commands stop arriving mid-teleop, bring the robot to a safe state. Zenoh command channels support
watchdog_mswith anon_command_timeouthook. For MQTT, implement the timeout in your driver. - Raise alerts operators can see:
create_twin_alert(...)orAlertManagerfrom the SDK (Alerts). - Calibration: a twin with
can_actuateshows a Re-calibrate driver action in Live mode. Test it against your robot, and document any vendor calibration steps on the asset.
Record data and train a policy
- Dock your cameras to the robot as child twins with an asset kit. Edge Core passes child camera twins to the parent driver in
CYBERWAVE_CHILD_TWIN_UUIDS. - Record teleop episodes and export them (LeRobot is one of the export formats).
- Fine-tune a VLA and assign it with
twin.policy.assign(...).
Publish your robot
Give the asset (and kit) a clear description, bill of materials and troubleshooting notes. Then switch the asset’s visibility to Public. Public assets are visible to anyone on the platform. To be listed with a support level, or for closed-source driver distribution, contact Cyberwave or email info@cyberwave.com with your target level and the pass-test results. Done when: the asset is public and you’ve sent your level evidence to Cyberwave.Use every platform feature
With an asset and a driver, your hardware behaves like any catalog device. The same MQTT topics and command surface drive everything below, with no extra integration:Workflows
Chain perception, models, and motion into repeatable automations, low-code or in Python.
Replay & recording
Record episodes, scrub the timeline, and export datasets for training and review.
Teleoperation & remote takeover
Drive your hardware from anywhere and take over from an AI policy with one click.
Controllers & models
Assign keyboard, teleop, or trained AI policies as the controller for your twin.
Simulation
Validate behavior against the digital twin before it ever touches real hardware.
Digital twin
A live, synced virtual mirror of your hardware that the whole platform builds on.
Checklist
Copy this into your tracker.Next steps
Asset and driver spec
ZIP layout, upload fields, physics, driver config files and env vars.
Writing compatible drivers
Container contract, cw-driver.yml, MQTT catalog and sensor output.
UR Sim with a ROS 2 driver
A working BaseROS2Driver against a simulated UR arm.
Supported hardware
Robots that already have a driver.