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

# CameraConfig

> Declaring a camera, naming it for the dataset, and finding a handle that survives a reboot.

One per camera, passed to the follower. Each camera is sent as its own track and
labelled separately in the dataset.

```python theme={null}
import zeroruntime.teleops as teleop

follower = MyArm(MEETING_ID, cameras=[
    teleop.CameraConfig("platform-3610000.usb-usb-0:2.2:1.0-video-index0", label="wrist"),
    teleop.CameraConfig("platform-3610000.usb-usb-0:2.4:1.0-video-index0", label="front")])
```

## Fields

<ParamField path="handle" type="str" required>
  Which camera to open. Only Linux opens it. On macOS and Windows, see
  [below](#finding-a-camera).
</ParamField>

<ParamField path="label" type="str">
  What to call it: `wrist`, `front`, `left`. The dataset uses this name, as
  `observation.images.<label>`.
</ParamField>

<ParamField path="width" type="int" default="640">
  Capture width in pixels.
</ParamField>

<ParamField path="height" type="int" default="480">
  Capture height in pixels.
</ParamField>

<ParamField path="fps" type="int" default="30">
  Capture rate. Frames are captured at this rate whatever the observation rate
  is, and the one nearest each observation is the one recorded.
</ParamField>

<ParamField path="pixel_format" type="str" default="mjpeg">
  Capture format. Linux only. On macOS the camera negotiates its own and this
  is ignored.
</ParamField>

<Warning>
  Keep `pixel_format="mjpeg"` on any host with more than one camera. Uncompressed
  video needs about 18 MB per second per camera, and two of those do not fit on
  one USB bus.
</Warning>

## Finding a camera

On Linux, the handle is the camera's device name or path. On macOS and
Windows, a camera passed in `cameras=` is not opened: it streams a test pattern.

<Tabs>
  <Tab title="Linux">
    ```bash theme={null}
    python -m zeroruntime.teleops.devices
    ```

    That lists every camera and serial device with its `by-path` name, which is
    the handle to put in your config. Or leave `cameras=` out: the follower then
    streams every USB camera, or the ones `ZERORUNTIME_CAMERAS` names.

    ```python theme={null}
    teleop.CameraConfig("platform-3610000.usb-usb-0:2.2:1.0-video-index0",
                        label="wrist")
    ```

    ```python theme={null}
    from zeroruntime.teleops import (list_cameras, list_serial,
                                 resolve_camera, resolve_serial)

    list_cameras()             # every camera, with its by-path name
    list_serial()              # every serial device, for servo buses
    resolve_camera(handle)     # by-path name to a /dev/video node
    resolve_serial(handle)     # by-path name to a /dev/ttyACM node
    ```

    <Warning>
      Use the `by-path` name, never `/dev/video0` or `/dev/ttyACM0`. Those
      numbers change across reboots, so two identical cameras can swap places
      between runs.
    </Warning>

    <Tip>
      Tired of long names? Register your own short ones once, then use those
      anywhere a handle is accepted.

      ```python theme={null}
      from zeroruntime.teleops import devices

      devices.CAMERA_ALIASES["wrist"] = "platform-3610000.usb-...-video-index0"
      ```
    </Tip>
  </Tab>

  <Tab title="macOS">
    Leave `cameras=` out, and the follower streams every camera on the Mac. To
    choose, set `ZERORUNTIME_CAMERAS` to their numbers. You need OpenCV:

    ```bash theme={null}
    pip install opencv-python
    export ZERORUNTIME_CAMERAS=0,1
    ```

    List the numbers with:

    ```bash theme={null}
    python -m zeroruntime.teleops.devices
    ```

    The numbers change when you plug a camera in or out, so run it again after.
    The alias table is Linux only.
  </Tab>

  <Tab title="Windows">
    The SDK doesn't open cameras on Windows. To send video, open the camera in
    your own code, declare it in `push_camera_configs()`, and return its frames
    from `read_images()`. See
    [Follower](/robotics/api-reference/python/follower#you-implement).
  </Tab>
</Tabs>

<Warning>
  Camera numbers on macOS are not stable the way a `by-path` name is.
  On a machine with more than one camera, confirm which is which before a
  session rather than during one.
</Warning>

## Related

<CardGroup cols={2}>
  <Card title="Follower" icon="robot" href="/robotics/api-reference/python/follower">
    Where cameras are passed, and everything else in its constructor.
  </Card>

  <Card title="Observation" icon="eye" href="/robotics/api-reference/python/observation">
    How a frame is paired with the joints from the same instant.
  </Card>
</CardGroup>


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