Reachy Mini documentation

Custom Media Manager

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Custom Media Manager

This example demonstrates how to deactivate the built-in media manager and access the camera and microphone directly using OpenCV and sounddevice.

Why? The daemon normally owns the camera and audio hardware. If you need raw access (e.g. custom OpenCV pipelines, sounddevice recording, or a third-party vision library), you must first tell the daemon to release the hardware. See Media Architecture - Disabling Media for details.

How it works:

  1. Connects with media_backend="no_media" — this automatically tells the daemon to release camera and audio hardware
  2. Uses OpenCV to capture a frame directly from the camera
  3. Uses sounddevice to record audio from the microphone
  4. On exit, the daemon automatically re-acquires the hardware

💡 Tip: Robot control (head, antennas, body) keeps working normally while media is released. Only camera and audio are affected.

Requirements:

pip install opencv-python sounddevice soundfile

Usage:

python custom_media_manager.py

import sys
import time

try:
    import cv2
except ImportError:
    print("Error: OpenCV is required. Install with: pip install opencv-python")
    sys.exit(1)

try:
    import sounddevice as sd
    import soundfile as sf
except ImportError:
    print("Error: sounddevice + soundfile are required.")
    print("Install with: pip install sounddevice soundfile")
    sys.exit(1)

import numpy as np

from reachy_mini import ReachyMini


def main() -> None:
    """Capture a frame with OpenCV and record audio with sounddevice."""
    # media_backend="no_media" automatically releases daemon media hardware
    with ReachyMini(media_backend="no_media") as mini:
        print(f"Connected. media_released={mini.media_released}")

        # --- OpenCV camera capture ---
        print("\nOpening camera with OpenCV...")
        cap = cv2.VideoCapture(0)
        if not cap.isOpened():
            print("Could not open camera — is it plugged in?")
        else:
            # Let the camera auto-adjust
            for _ in range(10):
                cap.read()

            ret, frame = cap.read()
            if ret:
                cv2.imwrite("release_media_frame.jpg", frame)
                print(f"Saved frame: release_media_frame.jpg ({frame.shape})")
            else:
                print("Failed to capture frame.")
            cap.release()

        # --- sounddevice audio recording ---
        duration = 2.0  # seconds
        samplerate = 44100
        print(f"\nRecording {duration}s of audio at {samplerate} Hz...")
        try:
            audio = sd.rec(
                int(duration * samplerate),
                samplerate=samplerate,
                channels=1,
                dtype=np.int16,
            )
            sd.wait()
            sf.write("release_media_audio.wav", audio, samplerate)
            print("Saved audio: release_media_audio.wav")
        except Exception as e:
            print(f"Audio recording failed: {e}")

        # The robot is still controllable while media is released
        print("\nWiggling antennas to prove robot control still works...")
        mini.goto_target(antennas=[0.3, -0.3], duration=0.5)
        time.sleep(0.2)
        mini.goto_target(antennas=[0.0, 0.0], duration=0.5)

    # __exit__ automatically calls acquire_media() → daemon reclaims hardware
    print("\nDone. Daemon media re-acquired on exit.")


if __name__ == "__main__":
    main()
Update on GitHub