> For the complete documentation index, see [llms.txt](https://docs.theseus.us/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.theseus.us/cyclops/developers/custom-camera-publisher.md).

# Custom Camera Publisher

Cyclops ships with a `usb-camera` service that auto-detects UVC cameras and publishes frames into the navigation stack. If your camera isn't UVC — for example a MIPI/CSI sensor or an IP camera — you replace that service with your own publisher.

### How Cyclops consumes camera data

Internally, Cyclops uses [Eclipse eCAL 5](https://eclipse-ecal.github.io/ecal/v5.12/index.html) as its pub/sub bus. MapMatcher subscribes to a single eCAL topic and decodes each message as a Cap'n Proto `vkc::Image`:

| Topic     | eCAL type     | Schema                       | Encoding        |
| --------- | ------------- | ---------------------------- | --------------- |
| `S1/cama` | `capnp:Image` | `vkc::Image` (`image.capnp`) | JPEG, grayscale |

Anything that publishes onto `S1/cama` with the right schema is a valid camera source. The bundled `usb-camera` service is one such publisher; your custom publisher is another.

### When you need a custom publisher

| Camera type                                 | Use                                                |
| ------------------------------------------- | -------------------------------------------------- |
| UVC USB camera                              | Bundled `usb-camera.service` — no integration work |
| MIPI / CSI sensor                           | Custom publisher                                   |
| GigE / IP camera                            | Custom publisher                                   |
| Vendor SDK (Allied Vision, FLIR, etc.)      | Custom publisher                                   |
| Any non-UVC source you already have running | Custom publisher                                   |

### Integration kit

We ship a standalone repo with everything needed to write a publisher without pulling in the SDK:

[**cyclops-camera-publisher**](https://github.com/Theseus-Dev/cyclops-camera-publisher)

Inside:

* `cyclops_camera_ecal.py` — Python helper. Build a `CyclopsCameraPublisher`, call `publish_frame(numpy_array, calibration)`.
* `cyclops_camera_ecal.{hpp,cpp}` — C++ helper with the same contract.
* `example_usb_camera.{py,cpp}` — runnable end-to-end examples (OpenCV → helper → eCAL).
* `example_image_subscriber.py` — verification subscriber that decodes `S1/cama` and prints calibration + timing.
* `capnp/` — the Cap'n Proto schemas (`image.capnp` and dependencies), so you can build standalone.
* `camera_params.example.yaml` — calibration template that mirrors the on-device YAML shape.

Read the repo README for the full wire contract, field-by-field requirements, and the steps for replacing the bundled service.

### Minimum your publisher must do

1. Capture frames from your camera however you like.
2. Encode each frame as grayscale JPEG.
3. Stamp `header.stampMonotonic` with the capture time in the Cyclops host clock domain (use `header.clockOffset` if your camera reports timestamps in another clock).
4. Fill `intrinsic.kb4` with calibrated KB4 intrinsics for your lens (`fx, fy, cx, cy, k1..k4`).
5. Set `extrinsic.bodyFrame` to the nadir-mount default `(w=0.00202, x=0.70568, y=0.70853, z=0.00170)` with zero translation.
6. Publish on eCAL topic `S1/cama` with type `capnp:Image`.

The helpers in the integration repo handle steps 2–6 for you. You bring camera bring-up (step 1)

### Verifying

Run the verification subscriber from any host on the same eCAL network:

```bash
python3 example_image_subscriber.py --topic S1/cama
```

A correctly-wired publisher prints `encoding=jpeg`, monotonically increasing `seq`, your expected `width x height`, intrinsics matching your calibration YAML, and `body_frame` matching the nadir-mount default.

### Calibration

External integrators provide camera calibration (intrinsics + the nadir-default extrinsic) and publish it on each frame. Vehicle calibration (`b_T_vb`) is unrelated — it's handled by the SDK and never flows through your publisher. See Camera Calibration for the calibration procedure.
