Skip to main content
Needs: ~1 hour to a moving model, ~2 days to a live twin, 1–2 weeks to a trained policy · advanced · your robot, an edge computer (64-bit Raspberry Pi, Jetson, the robot’s onboard computer, or a Mac for local development), Docker, Python 3.10+, a URDF with meshes · free to start; MuJoCo simulation uses credits This guide is for hardware makers and teams with custom hardware: a custom robot, an in-house prototype, or a niche industrial machine. It takes you in order from “is my robot already supported?” to “my twin moves my robot”. When you finish, anyone with access to your asset can spawn a twin of your robot, simulate it, drive the real machine from the browser or the SDK, record data, and put a trained policy in control. That holds whether the hardware is on the same desk or on the other side of the world. File layouts, upload fields, limits, physics settings and driver config are in the Asset and driver spec.

Check if your robot is already supported

Cyberwave ships 80+ devices in its catalog. Catalog devices like the-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.
A twin is a live instance of the asset inside an environment. Edge Core runs your driver next to the hardware and links it to the twin. Because integration happens at the driver layer, Cyberwave works with ROS 1 / ROS 2, VDA5050, OPC UA, Modbus, gRPC, REST and serial / USB. See Supported protocols.

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

  • 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
The CLI and Edge Core require a 64-bit architecture (arm64/aarch64) on Raspberry Pi.

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.
The full packaging rules (file types, symlinks, size limit) are in Asset package.
Don’t have a URDF yet? Most robots ship one with their ROS package, or you can export one from your CAD tool. For a sensor-only device (like a camera) you can start from a simple placeholder mesh and refine it later.

Start from the sample URDF

Want a concrete reference? Download this sample drone URDF (a DJI Mini 4 Pro). It defines a base_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:
The parser tolerates common URDF quirks (a missing 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.Upload URDF package step
2

Details: describe your asset

Give the asset a clear name (for example, Acme Arm v1) and a short description of what the robot is.Describe your asset stepExpand 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.Advanced asset detailsClick Continue.
3

Access: choose visibility and workspace

Choose who can see and use the asset, then pick the workspace it belongs to.Choose asset access stepClick Create Asset.
Cyberwave unpacks and validates the archive. Once it’s ready, you can spawn twins from the asset in the dashboard, the Python SDK, or the REST API. To upload from a script or CI instead, use 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.
Start Private while you iterate on the URDF and driver, then switch to Organization or Public when it’s ready to share. Visibility can be changed after creation.
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.
The twin isn’t connected to anything yet. Note its UUID (in its properties panel). Your driver receives it at runtime. Done when: every joint moves the right link in the right direction and stops at its limits. You are at L0.

Declare capabilities and sensors

Capabilities decide which UI panels and SDK classes your twin gets. They live in the asset’s universal schema under extensions.cyberwave.capabilities, next to a sensors list.
  • can_actuate enables joint control and the re-calibrate action.
  • can_locomote enables Missions.
  • can_grip and has_joints enable the controller UI.
  • A non-empty sensors list enables sensor windows.
The full table is in the feature-to-capability matrix. Fix them on the asset page’s onboarding checklist, in the JSON editor (Editing a universal schema), or from the SDK:
For each sensor, set its 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

  1. 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.
  2. 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.
  3. In the environment editor, open Simulation readiness → Prepare simulation. It lists missing data and proposes fixes (Simulator compatibility).
  4. Run cw.affect("simulation"). This starts a MuJoCo instance, which is billable (credits).
Done when: MuJoCo starts with your twin and it holds a commanded pose. You are at L1.

Write the driver

The driver bridges your device’s native protocol to the twin. Pick a starting point:
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.
Run the driver with 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 a cw-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:
Each YAML path compiles to a flat MQTT topic. For example 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.
Use the reference manifests as templates: the SO-101 arm for a joint bus plus command topic, or the UGV Beast for continuous locomotion. Copy the namespaces that match your robot and delete the rest.
For ROS 2 drivers, export the combined manifest at build time with 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.
Done when: the teleop overlay and 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 metadata.drivers block and starts one container per linked twin:
Edge Core picks the most specific platform key for the host and falls back to 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.
Done when: on a clean device, 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 raises driver_start_failure and applies its restart policy. run_driver_main exits 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_ms with an on_command_timeout hook. For MQTT, implement the timeout in your driver.
  • Raise alerts operators can see: create_twin_alert(...) or AlertManager from the SDK (Alerts).
  • Calibration: a twin with can_actuate shows a Re-calibrate driver action in Live mode. Test it against your robot, and document any vendor calibration steps on the asset.
Done when: you cut the edge device’s network during teleop, the robot stops safely, and an alert appears on the twin. You are at L3.

Record data and train a policy

  1. 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.
  2. Record teleop episodes and export them (LeRobot is one of the export formats).
  3. Fine-tune a VLA and assign it with twin.policy.assign(...).
Worked example: SO-101 teleop dataset → Train a VLA. Done when: a policy trained on your robot’s data drives the robot. You are at L4.

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.