# reachy > Develop Reachy Mini robot behaviors. Use when writing Python scripts to control the robot, understanding SDK patterns, or debugging motor/sensor issues. Triggers on keywords like "reachy", "robot", "antenna", "head pose", "stewart platform", "goto_target", "daemon". - Author: Ali Madad - Repository: amadad/reachy_mini - Version: 20260104121419 - Stars: 0 - Forks: 0 - Last Updated: 2026-02-07 - Source: https://github.com/amadad/reachy_mini - Web: https://mule.run/skillshub/@@amadad/reachy_mini~reachy:20260104121419 --- --- name: reachy description: Develop Reachy Mini robot behaviors. Use when writing Python scripts to control the robot, understanding SDK patterns, or debugging motor/sensor issues. Triggers on keywords like "reachy", "robot", "antenna", "head pose", "stewart platform", "goto_target", "daemon". user_invocable: false --- # Reachy Mini Development Guide for developing Reachy Mini robot behaviors using the Python SDK. ## Quick Scripts Run these directly for common operations: ```bash uv run python skills/reachy/scripts/reset.py # Home position uv run python skills/reachy/scripts/sleep.py # Sleep (shutdown) uv run python skills/reachy/scripts/wake.py # Wake up uv run python skills/reachy/scripts/demo.py # Demo sequence ``` ## Architecture **Client-Server model:** - **Daemon** (server): Runs on the machine connected to robot, handles hardware I/O, exposes REST API at `localhost:8000` - **SDK** (client): Your Python code connecting to the daemon ## Quick Reference ### Starting the Daemon ```bash # USB-connected robot uv run reachy-mini-daemon # Simulation mode uv run reachy-mini-daemon --sim # macOS simulation (requires mjpython) mjpython -m reachy_mini.daemon.app.main --sim ``` Dashboard: http://localhost:8000 ### Basic Script Template ```python from reachy_mini import ReachyMini from reachy_mini.utils import create_head_pose import numpy as np # IMPORTANT: Use media_backend="no_media" on macOS to avoid camera permission issues with ReachyMini(media_backend="no_media") as mini: # Smooth movement (blocks until complete) mini.goto_target( head=create_head_pose(pitch=20, yaw=30, degrees=True), antennas=[0.5, -0.5], # radians, [right, left] duration=1.0, method="minjerk" # linear, minjerk, ease, cartoon ) # Instant position (for real-time loops) mini.set_target(head=pose, antennas=[0, 0]) # Reset to neutral mini.goto_target(head=np.eye(4), antennas=[0.0, 0.0], duration=1.0) ``` ### Head Pose Creation ```python from reachy_mini.utils import create_head_pose # Using degrees (recommended) pose = create_head_pose(roll=10, pitch=20, yaw=30, degrees=True) # With translation (mm) pose = create_head_pose(x=10, y=5, z=15, mm=True, degrees=True) # Neutral pose = identity matrix neutral = np.eye(4) ``` ### Antenna Control - Values in **radians** - Format: `[right_antenna, left_antenna]` - `0` = straight up - Positive = outward tilt ```python mini.goto_target(antennas=[0.5, -0.5], duration=0.5) # Tilt opposite mini.goto_target(antennas=[0, 0], duration=0.5) # Reset ``` ### Body Rotation ```python mini.goto_target(body_yaw=np.deg2rad(30), duration=1.0) # Turn body 30 deg ``` ## Safety Limits | Joint | Range | |-------|-------| | Head Pitch/Roll | [-40, +40] degrees | | Head Yaw | [-180, +180] degrees | | Body Yaw | [-160, +160] degrees | | Yaw Delta | Max 65 deg between head and body | The SDK auto-clamps to valid ranges. ## Motor Modes ```python mini.enable_motors() # Stiff, holds position mini.disable_motors() # Limp, no power mini.enable_gravity_compensation() # Compliant, stays where placed (requires Placo backend) ``` ## Behaviors ```python mini.goto_sleep() # Head down, antennas folded mini.wake_up() # Return to neutral ``` ## Sensors ### IMU (Wireless version only) ```python imu = mini.imu accel = imu["accelerometer"] # [x, y, z] m/s^2 gyro = imu["gyroscope"] # [x, y, z] rad/s quat = imu["quaternion"] # [w, x, y, z] temp = imu["temperature"] # celsius ``` ### Camera ```python # Requires media_backend="default" (not "no_media") with ReachyMini(media_backend="default") as mini: frame = mini.media.get_frame() # numpy array (H, W, 3) uint8 ``` ### Audio ```python with ReachyMini(media_backend="default") as mini: mini.media.start_recording() samples = mini.media.get_audio_sample() # (samples, 2) float32 @ 16kHz mini.media.push_audio_sample(samples) # non-blocking playback mini.media.stop_recording() ``` ## Recording Moves ```python mini.start_recording() # ... move robot manually or via code ... recorded_data = mini.stop_recording() ``` ## Hardware - **9 motors**: body_rotation (ID 10), stewart_1-6 (IDs 11-16), right_antenna (17), left_antenna (18) - **Stewart platform**: 6-DOF parallel manipulator for head movement - **Camera**: 12MP wide-angle, autofocus - **Mics**: 4-mic array @ 16kHz - **Speaker**: 5W ## Reusable Helpers Import from `reachy_helpers.py` in the repo root: ```python from reachy_helpers import ( connect, home, sleep, wake, nod_yes, shake_no, tilt_curious, oscillate, look_at, look_at_pixel, antennas_deg, ANTENNAS_UP, ANTENNAS_OUT, ANTENNAS_ALERT, play_emotion, play_dance ) ``` ### Connection ```python # Safe connection (no_media by default for macOS) with connect() as mini: ... # With camera/audio with connect(media=True) as mini: frame = mini.media.get_frame() ``` ### State Transitions ```python home(mini) # Return to neutral sleep(mini) # Head down, antennas folded wake(mini) # Wake up animation ``` ### Expressions ```python nod_yes(mini, cycles=2) # Affirmative nod shake_no(mini, cycles=2) # Negative shake tilt_curious(mini) # Head tilt + antenna perk ``` ### Antenna Presets ```python ANTENNAS_UP = [0, 0] # Straight up ANTENNAS_OUT = antennas_deg(45, 45) # Spread outward ANTENNAS_ALERT = antennas_deg(30, -30) # Opposite directions ANTENNAS_SLEEP = [-3.05, 3.05] # Folded down ``` ### Motion Patterns ```python # Real-time oscillation (non-blocking loop) oscillate(mini, duration=5.0, freq=0.5, amplitude=20) # Look at 3D point (meters) look_at(mini, x=0.3, y=0.1, z=0.2, duration=1.0) # Look at camera pixel look_at_pixel(mini, u=320, v=240, duration=0.3) ``` ### Pre-recorded Moves (HuggingFace) ```python play_emotion(mini, "happy") # From emotions library play_dance(mini, "wave") # From dance library ``` ## Common Patterns ### Animation Loop ```python import time with connect() as mini: home(mini) try: while True: t = time.time() pitch = 10 * np.sin(2 * np.pi * 0.5 * t) pose = create_head_pose(pitch=pitch) mini.set_target(head=pose, antennas=ANTENNAS_UP) time.sleep(0.01) except KeyboardInterrupt: home(mini) ``` ### Expression Sequence ```python def nod_yes(mini, cycles=2): for _ in range(cycles): mini.goto_target(head=create_head_pose(pitch=15), duration=0.2) mini.goto_target(head=create_head_pose(pitch=-15), duration=0.2) home(mini, duration=0.2) def shake_no(mini, cycles=2): for _ in range(cycles): mini.goto_target(head=create_head_pose(yaw=20), duration=0.2) mini.goto_target(head=create_head_pose(yaw=-20), duration=0.2) home(mini, duration=0.2) ``` ## Troubleshooting | Issue | Solution | |-------|----------| | Camera error on macOS | Use `media_backend="no_media"` | | Daemon won't start | Check USB: `ls /dev/cu.usb*` | | Robot stuck | Run reset script or restart daemon | | Simulation on macOS | Use `mjpython` instead of `python` | ## API Endpoints When daemon is running: - Dashboard: http://localhost:8000 - API docs: http://localhost:8000/docs - Full state: `GET /api/state/full` - WebSocket: `ws://localhost:8000/api/state/ws/full` ## AI Integration For LLM-powered apps, see [references/llm-integration.md](references/llm-integration.md) covering: - Tool definition pattern - MovementManager (100Hz control loop) - Profile/personality system - Vision pipeline - Audio-reactive motion Conversation app: https://github.com/pollen-robotics/reachy_mini_conversation_app