> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cyberwave.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Drivers

> A Cyberwave driver is a Docker image that interacts with device hardware and the Cyberwave backend.

A Cyberwave driver is a Docker image that interacts with device hardware and the Cyberwave backend.

## How to use drivers

Register a driver by adding its configuration to a twin's metadata (or the catalog twin's metadata if you control the catalog twin). Use the environment view's **Advanced editing** to edit metadata.

Note: changing a catalog twin's metadata affects all subsequently created digital twins derived from that catalog twin.

Example driver metadata (JSON):

```json theme={null}
{
  "drivers": {
    "default": {
      "docker_image": "cyberwaveos/so101-driver",
      "version": "0.0.1",
      "params": ["--network", "local", "--add-host", "host.docker.internal:host-gateway"]
    }
  }
}
```

### Pin cameras and microphones by serial number

When an edge host has multiple cameras or USB microphones of the same model,
set the physical unit's serial at top-level `metadata.serial_number`. Keep it a
JSON string so leading zeroes are preserved:

```json theme={null}
{
  "serial_number": "046322252081",
  "drivers": {
    "default": {
      "docker_image": "cyberwaveos/camera-driver",
      "params": ["--device", "/dev/video0:/dev/video0"]
    }
  }
}
```

`serial_number` names one physical unit. Camera `video_device` and microphone
`audio_device` fields instead name a capture source or selector. A serial takes
precedence, and the driver fails rather than silently substituting different
hardware when the pinned unit is missing.

On Linux, Edge Core automatically bind-mounts `/dev/v4l` into camera-driver
containers when that host directory exists, allowing UVC serials to resolve
through `/dev/v4l/by-id`. It similarly exposes `/dev/snd` to the generic audio
drivers. Custom launchers must provide those mounts themselves.

<Info>
  **stub** — `cyberwave edge install` does not ask you to pick a `/dev/videoN`
  for a camera twin that already sets `serial_number`; it matches the serial
  against the attached cameras and binds them for you. Twins without one are
  still asked, and the camera you pick is saved back as that twin's
  `serial_number`, so the question is asked once per camera rather than on
  every install. When a pinned serial matches no attached camera the installer
  warns and falls back to asking, because substituting another camera would
  stream the wrong footage.
</Info>

<Info>
  **stub** — Cameras that publish no USB serial (the Logitech C920 is one) can
  never be pinned with `serial_number`. Set `metadata.video_device` to a udev
  stable name instead — `/dev/v4l/by-id/...` or `/dev/v4l/by-path/...` — and
  the installer binds the twin without asking, exactly as it does for a serial.
  `by-id` follows the camera across ports; `by-path` follows the port. An
  `rtsp://` or `http://` URL marks a network camera, which is also never asked
  about and takes no local device. A bare index or `/dev/videoN` is positional,
  not identity, so those twins are still prompted.
</Info>

### GPU passthrough

Drivers can opt-in to GPU acceleration by setting `"prefer_gpu": true` in their metadata. When the host has the NVIDIA container runtime available **and** configured as the default in `/etc/docker/daemon.json`, Edge Core passes `--gpus` to the driver container.

The optional `"gpu"` field controls which GPUs are exposed:

| `gpu` value | Docker flag | Use case |
| - | - | - |
| *(not set)* | `--gpus all` | All available GPUs (default) |
| `1` | `--gpus 1` | Limit to 1 GPU |
| `"device=0,2"` | `--gpus "device=0,2"` | Specific GPU devices |

```json theme={null}
{
  "drivers": {
    "default": {
      "docker_image": "cyberwaveos/go2-ros2-driver:humble",
      "prefer_gpu": true,
      "gpu": "all"
    }
  }
}
```

<Tip>
  On NVIDIA Jetson devices, Edge Core auto-detects the platform and tries a `jetson-` prefixed image tag (e.g. `:humble` → `:jetson-humble`), falling back to the original if unavailable. You can also add a `"linux-aarch64-jetson"` driver key in metadata for explicit Jetson-specific configuration.
</Tip>

### Platform-specific drivers

Use platform keys in `metadata.drivers` to provide platform-specific images or params:

```json theme={null}
{
  "drivers": {
    "default": {
      "docker_image": "cyberwaveos/driver:humble"
    },
    "linux-aarch64-jetson": {
      "docker_image": "cyberwaveos/driver:jetson-humble",
      "prefer_gpu": true
    },
    "darwin-arm64": {
      "docker_image": "cyberwaveos/driver:humble",
      "params": ["--add-host", "host.docker.internal:host-gateway"]
    }
  }
}
```

Edge Core resolves drivers in order: `linux-aarch64-jetson` → `linux-aarch64` → `linux` → `default`.

Manage edge driver containers:

| Subcommand | Description |
| - | - |
| `list` | List running driver containers (`--all` includes exited) |
| `start` | Start a stopped driver container |
| `stop` | Stop a running driver container |

## Multi-container drivers

Some robots require multiple cooperating containers — for example a ROS 2 driver, bridge nodes, Nav2, SLAM, and elevation mapping. Use the `services` array in driver metadata to define a multi-container stack that Edge Core launches automatically.

```json theme={null}
{
  "drivers": {
    "linux-aarch64-jetson": {
      "services": [
        { "image": "cyberwaveos/go2-ros2-driver:jetson-humble", "name": "driver",
          "command": ["ros2", "launch", "cyberwave_go2_driver", "robot_driver.launch.py"] },
        { "image": "cyberwaveos/go2-ros2-driver:jetson-humble", "name": "bridges" },
        { "image": "cyberwaveos/ros2-nav2:jetson-humble", "name": "nav2" },
        { "image": "cyberwaveos/ros2-slam:jetson-humble", "name": "slam" },
        { "image": "cyberwaveos/ros2-elevation-mapping:jetson-humble", "name": "elevation",
          "prefer_gpu": true }
      ],
      "shared_env": { "ROS_DOMAIN_ID": "0", "CYBERWAVE_MAP_DIR": "/data" },
      "shared_params": ["--network", "host", "-v", "/data:/data"]
    },
    "default": {
      "docker_image": "cyberwaveos/go2-ros2-driver",
      "prefer_gpu": true
    }
  }
}
```

Key points:

* `services` present → multi-container mode. `docker_image` present → single-container mode (existing behavior, unchanged).
* Each service requires `image` (Docker image) and `name` (used in the container name suffix).
* Optional per-service fields: `command`, `env`, `params`, `prefer_gpu`, `gpu`.
* `shared_env` and `shared_params` apply to all services. Per-service `env` overrides shared values.
* Container naming: `cyberwave-driver-{twin_uuid[:8]}-{service_name}`.
* Edge Core injects standard env vars (`CYBERWAVE_API_KEY`, MQTT, Zenoh, etc.) into every service automatically.

## Data bus

Drivers publish sensor data (frames, depth, joint states) to the **edge data bus** — a Zenoh-backed publish/subscribe system that lets worker containers consume data with zero network overhead (shared memory). See [Writing compatible drivers](/feature-reference/edge/drivers/writing-compatible-drivers) for the channel naming convention and wire format.

## macOS hardware bridge

When Edge Core runs on macOS, Linux `--device` mappings in Docker params cannot
directly expose host camera/serial hardware to driver containers. Use a host
bridge process and forward into Docker via `host.docker.internal`.

* Optional host hook env var:
  * `CYBERWAVE_MACOS_DEVICE_BRIDGE_COMMAND`
* Command template variables:
  * `{host_device}`, `{container_device}`, `{twin_uuid}`, `{container_name}`, `{config_dir}`
* Bridge command can return a resolved source (`resolved_device=...` or JSON) so
  Edge Core can inject `CYBERWAVE_METADATA_VIDEO_DEVICE` automatically.
* Optional macOS behavior:
  * `CYBERWAVE_MACOS_STRIP_VIDEO_DEVICE_PARAMS=true` removes Linux-only
    `--device /dev/video*` mappings before container start when a non-`/dev`
    source is resolved.
* For camera twins, Edge Core can derive default macOS camera bridge candidates
  even without explicit `--device` params, enabling minimal default driver
  metadata to work.
* Use platform-specific driver keys in `metadata.drivers` (for example
  `darwin-arm64`, `darwin`, `macos`) to provide macOS-specific params while
  keeping `default` for Linux.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.