# Kamera

LeRobot menyediakan beberapa opsi untuk perekaman video:

| Kelas             | Kamera yang Didukung                   |
| ----------------- | ----------------------------------- |
| `OpenCVCamera`    | Telepon, laptop bawaan, webcam USB |
| `ZMQCamera`       | Kamera yang terhubung ke jaringan           |
| `RealSenseCamera` | Intel RealSense (dengan kedalaman)        |
| `Reachy2Camera`   | Kamera robot Reachy 2              |

> [!TIP]
> Untuk detail kompatibilitas `OpenCVCamera`, lihat [Ikhtisar I/O Video dengan OpenCV](https://docs.opencv.org/4.x/d0/da7/videoio_overview.html).

### Temukan kamera Anda

Setiap kamera memerlukan pengenal unik untuk diinstansiasi, sehingga Anda dapat membedakan antara beberapa perangkat yang terhubung.

`OpenCVCamera` dan `RealSenseCamera` mendukung auto-discovery. Jalankan perintah di bawah ini untuk menampilkan daftar perangkat yang tersedia beserta identifikatornya. Perhatikan bahwa identifikator ini dapat berubah setelah komputer Anda di-reboot atau kamera dicolok ulang, tergantung pada sistem operasi Anda.

```bash
lerobot-find-cameras opencv # or realsense for Intel Realsense cameras
```

Outputnya akan terlihat seperti ini jika Anda memiliki dua kamera yang terhubung:

```bash
--- Detected Cameras ---
Camera #0:
  Name: OpenCV Camera @ 0
  Type: OpenCV
  Id: 0
  Backend api: AVFOUNDATION
  Default stream profile:
    Format: 16.0
    Width: 1920
    Height: 1080
    Fps: 15.0
--------------------
(more cameras ...)
```

> [!WARNING]
> Saat menggunakan kamera Intel RealSense di `macOS`, Anda mungkin mendapatkan [error](https://github.com/realsenseai/librealsense/issues/12307) ini: `Error finding RealSense cameras: failed to set power state`. Hal ini dapat diatasi dengan menjalankan perintah yang sama dengan izin `sudo`. Perhatikan bahwa penggunaan kamera RealSense di `macOS` tidak stabil.

`ZMQCamera` dan `Reachy2Camera` tidak mendukung auto-discovery. Keduanya harus dikonfigurasi secara manual dengan menyediakan alamat jaringan dan port atau pengaturan robot SDK.

## Penempatan kamera dan pencahayaan

Gambar kamera adalah hal yang dipelajari oleh kebijakan Anda, sehingga pengaturan kamera yang baik lebih penting daripada resolusi tinggi:

- **Pencahayaan adegan harus merata.** Gunakan cahaya difus yang konsisten dan hindari sinar matahari langsung, pantulan kuat, serta bayangan yang bergerak. Perbedaan pencahayaan antara proses perekaman dan penerapan dapat menyebabkan kebijakan gagal.
- **Perbaiki kamera di tempatnya.** Pasang dengan kaku dan jangan pindahkan kamera antara sesi perekaman, atau antara perekaman dan deployment.
- **Rumuskan tugasnya.** Objek, gripper, dan target harus terlihat di setidaknya satu kamera. Uji yang baik: apakah Anda bisa melakukan tugas tersebut sendiri hanya dengan melihat gambar dari kamera?
- **Jaga resolusi tetap moderat.** 640×480 pada 30 fps sudah cukup untuk sebagian besar tugas dan menjaga proses perekaman serta pelatihan tetap cepat.

## Gunakan kamera

### Mode akses frame

Semua kelas kamera mengimplementasikan tiga mode akses untuk menangkap frame:

| Metode                    | Perilaku                                                                                                                                                   | Blok?        | Paling Cocok Untuk                                 |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | ---------------------------------------- |
| `read()`                  | Menunggu perangkat keras kamera untuk mengembalikan frame. Dapat memblokir untuk waktu yang lama tergantung pada kamera dan SDK.                                                | Ya            | Skrip sederhana, penangkapan berurutan       |
| `async_read(timeout_ms)`  | Mengembalikan frame terbaru yang belum dikonsumsi dari thread latar. Memblok hanya jika buffer kosong, hingga `timeout_ms`. Mengangkat `TimeoutError` jika tidak ada frame yang tiba. | Dengan batas waktu | Loop kontrol yang disinkronkan dengan FPS kamera |
| `read_latest(max_age_ms)` | Melihat frame terbaru di buffer (mungkin sudah kedaluwarsa). Mengangkat `TimeoutError` jika frame lebih tua dari `max_age_ms`.                                        | Tidak             | Visualisasi UI, pencatatan log, pemantauan    |

### Contoh penggunaan

Contoh berikut menunjukkan cara menggunakan API kamera untuk mengonfigurasi dan menangkap frame dari berbagai jenis kamera.

- **Pengambilan frame yang memblokir dan tidak memblokir** menggunakan kamera berbasis OpenCV
- **Pengambilan warna dan kedalaman** menggunakan kamera Intel RealSense

> [!WARNING]
> Gagal memutuskan koneksi kamera dengan bersih dapat menyebabkan kebocoran sumber daya. Gunakan protokol context manager untuk memastikan pembersihan otomatis:
>
> ```python
> with OpenCVCamera(config) as camera:
>     ...
> ```
>
> Anda juga dapat memanggil `connect()` dan `disconnect()` secara manual, tetapi selalu gunakan blok `finally` untuk yang terakhir.

```python
from lerobot.cameras.opencv import OpenCVCamera, OpenCVCameraConfig
from lerobot.cameras import ColorMode, Cv2Rotation

# Construct an `OpenCVCameraConfig` with your desired FPS, resolution, color mode, and rotation.
config = OpenCVCameraConfig(
    index_or_path=0,
    fps=15,
    width=1920,
    height=1080,
    color_mode=ColorMode.RGB,
    rotation=Cv2Rotation.NO_ROTATION
)

# Instantiate and connect an `OpenCVCamera`, performing a warm-up read (default).
with OpenCVCamera(config) as camera:

    # Read a frame synchronously — blocks until hardware delivers a new frame
    frame = camera.read()
    print(f"read() call returned frame with shape:", frame.shape)

    # Read a frame asynchronously with a timeout — returns the latest unconsumed frame or waits up to timeout_ms for a new one
    try:
        for i in range(10):
            frame = camera.async_read(timeout_ms=200)
            print(f"async_read call returned frame {i} with shape:", frame.shape)
    except TimeoutError as e:
        print(f"No frame received within timeout: {e}")

    # Instantly return a frame - returns the most recent frame captured by the camera
    try:
        initial_frame = camera.read_latest(max_age_ms=1000)
        for i in range(10):
            frame = camera.read_latest(max_age_ms=1000)
            print(f"read_latest call returned frame {i} with shape:", frame.shape)
            print(f"Was a new frame received by the camera? {not (initial_frame == frame).any()}")
    except TimeoutError as e:
        print(f"Frame too old: {e}")

```

```python
from lerobot.cameras.realsense import RealSenseCamera, RealSenseCameraConfig
from lerobot.cameras import ColorMode, Cv2Rotation

# Create a `RealSenseCameraConfig` specifying your camera’s serial number and enabling depth.
config = RealSenseCameraConfig(
    serial_number_or_name="233522074606",
    fps=15,
    width=640,
    height=480,
    color_mode=ColorMode.RGB,
    use_depth=True,
    # Optional fixed color controls. Omit them to leave the current sensor settings unchanged.
    exposure=120,
    gain=64,
    white_balance=4600,
    rotation=Cv2Rotation.NO_ROTATION
)

# Instantiate and connect a `RealSenseCamera` with warm-up read (default).
camera = RealSenseCamera(config)
camera.connect()

# Capture a color frame via `read()` and a depth map via `read_depth()`.
try:
    color_frame = camera.read()
    depth_map = camera.read_depth()
    print("Color frame shape:", color_frame.shape)
    print("Depth map shape:", depth_map.shape)
finally:
    camera.disconnect()
```

Kontrol warna manual menonaktifkan mode paparan otomatis atau keseimbangan putih otomatis yang sesuai. Rentang yang didukung bervariasi tergantung model kamera; nilai yang tidak valid akan memicu error saat koneksi yang mencakup rentang yang dilaporkan oleh sensor. Meminta kontrol yang tidak didukung juga memicu error. Kontrol yang diabaikan akan membiarkan pengaturan otomatis atau manual yang ada pada sensor tetap tidak berubah. Opsi ini memerlukan `use_rgb=True`.

Kontrol warna manual memerlukan modul RGB khusus. Kamera yang tidak memiliki modul tersebut, seperti RealSense D405, tidak mendukungnya dan akan memicu error saat koneksi.

### Bekerja dengan kedalaman

Kamera Intel RealSense dan Reachy 2 dapat menangkap warna dan kedalaman secara serempak. Memanggil `read()` mengembalikan frame **warna** sebagai `(H, W, 3)` `uint8`. Memanggil `read_depth()` mengembalikan **peta kedalaman** sebagai `(H, W, 1)` `uint16`, di mana setiap nilai piksel adalah jarak dari sensor yang dinyatakan dalam **milimeter**. Nilai piksel `0` biasanya berarti "tidak ada pengukuran yang tersedia" (di luar jangkauan, terhalang, atau kepercayaan rendah).

Selama perekaman, loop kontrol memeriksa frame terbaru yang dibuffer secara non-blocking melalui `read_latest()` (warna) dan `read_latest_depth()` (kedalaman), lalu menambahkan peta kedalaman sebagai fitur saudara (misalnya `front_depth` di samping `front`).

Untuk cara stream kedalaman disimpan dan dikodekan saat merekam dataset, lihat bagian [Depth streams](./video_encoding_parameters#depth-streams) pada panduan pengkodean video.

## Gunakan kamera ponsel Anda

Untuk menggunakan iPhone Anda sebagai kamera di macOS, aktifkan fitur Continuity Camera:

- Pastikan Mac Anda menjalankan macOS 13 atau lebih baru, dan iPhone Anda menggunakan iOS 16 atau lebih baru.
- Masuk ke kedua perangkat dengan Apple ID yang sama.
- Hubungkan perangkat Anda dengan kabel USB atau nyalakan Wi-Fi dan Bluetooth untuk koneksi nirkabel.

Untuk detail lebih lanjut, kunjungi [dukungan Apple](https://support.apple.com/en-gb/guide/mac-help/mchl77879b8a/mac).

Jika Anda ingin menggunakan ponsel Anda sebagai kamera dengan OBS, ikuti langkah-langkah berikut untuk mengatur kamera virtual.

1. _(Hanya Linux) Instal `v4l2loopback-dkms` dan `v4l-utils`_. Paket-paket ini membuat perangkat kamera virtual dan memverifikasi pengaturannya. Instal dengan:

```bash
sudo apt install v4l2loopback-dkms v4l-utils
```

2. _Instal [aplikasi DroidCam](https://droidcam.app) di ponsel Anda_. Aplikasi ini tersedia untuk iOS dan Android.
3. _Unduh dan instal [OBS Studio](https://obsproject.com)_.
4. _Unduh dan instal [plugin DroidCam OBS](https://droidcam.app/obs)_.
5. _Mulai OBS Studio_.

6. _Tambahkan ponsel Anda sebagai sumber_. Ikuti instruksi [di sini](https://droidcam.app/obs/usage). Pastikan untuk mengatur resolusi ke `640x480` untuk menghindari watermark.
7. _Sesuaikan pengaturan resolusi_. Di OBS Studio, buka `File > Settings > Video` atau `OBS > Preferences... > Video`. Ubah `Base(Canvas) Resolution` dan `Output(Scaled) Resolution` menjadi `640x480` dengan mengetiknya secara manual.
8. _Mulai kamera virtual_. Di OBS Studio, ikuti instruksi [di sini](https://obsproject.com/kb/virtual-camera-guide).
9. _Verifikasi pengaturan kamera virtual dan resolusi_.
   - **Linux**: Gunakan `v4l2-ctl` untuk mendaftar perangkat dan memeriksa resolusi:
     ```bash
     v4l2-ctl --list-devices  # find VirtualCam and note its /dev/videoX path
     v4l2-ctl -d /dev/videoX --get-fmt-video  # replace with your VirtualCam path
     ```
     Anda harus melihat `VirtualCam` terdaftar dengan resolusi `640x480`.
   - **macOS**: Buka Photo Booth atau FaceTime dan pilih "OBS Virtual Camera" sebagai input.
   - **Windows**: Aplikasi Kamera bawaan tidak mendukung kamera virtual. Gunakan aplikasi konferensi video (Zoom, Teams) atau jalankan `lerobot-find-cameras opencv` secara langsung untuk memverifikasi.

Pemecahan Masalah

> Resolusi kamera virtual tidak benar.

Hapus sumber kamera virtual dan buat ulang. Resolusi tidak dapat diubah setelah dibuat.

> Error saat membaca frame di thread latar belakang untuk OpenCVCamera(X): lebar frame OpenCVCamera(X)=640 atau tinggi=480 tidak cocok dengan lebar yang dikonfigurasi=1920 atau tinggi=1080.

Kesalahan ini disebabkan oleh OBS Virtual Camera yang mengiklankan resolusi `1920x1080` meskipun telah dilakukan penskalaan ulang. Satu-satunya perbaikan untuk saat ini adalah mengomentari pemeriksaan lebar dan tinggi di `_postprocess_image()`.

Jika semuanya diatur dengan benar, ponsel Anda akan muncul sebagai kamera OpenCV standar dan dapat digunakan dengan `OpenCVCamera`.

