| | --- |
| | title: Reachy Mini Remote Control App |
| | emoji: π€ |
| | colorFrom: red |
| | colorTo: blue |
| | sdk: static |
| | pinned: false |
| | short_description: Remote control Reachy Mini ! |
| | hf_oauth: true |
| | hf_oauth_expiration_minutes: 480 |
| | hf_oauth_scopes: |
| | - contribute-repos |
| | - manage-repos |
| | - write-repos |
| | tags: |
| | - reachy_mini |
| | - reachy_mini_python_app |
| | --- |
| | |
| | # Reachy Mini Remote Control App |
| |
|
| | A standalone app that connects Reachy Mini robot to a remote server for WebSocket-based control. The robot acts as a WebSocket **client** connecting to a remote server (e.g., Hugging Face Space), enabling remote control, video streaming, and bidirectional audio. |
| |
|
| | ## π Quick Start - Setup Your Control Space |
| |
|
| | This Space provides a beautiful web interface for setting up remote control: |
| |
|
| | ### Option 1: Public Shared Space (Instant) |
| | Just copy this URI and configure it on your robot: |
| | ``` |
| | wss://huggingfacem4-reachy-mini-remote-control.hf.space |
| | ``` |
| |
|
| | ### Option 2: Private Space (Recommended) |
| | 1. Click "Sign in with Hugging Face" below |
| | 2. Clone your own private control space |
| | 3. Get your custom URI: `wss://your-username-reachy-mini-remote-control.hf.space` |
| | 4. Create a Hugging Face access token with `read` permissions at https://huggingface.co/settings/tokens |
| | 5. Configure both the URI and token on your robot (see "Connecting to Private Spaces" below) |
| |
|
| | **π Visit the web interface above to get started!** |
| |
|
| | ## Features |
| |
|
| | - **WebSocket Client Architecture**: Robot connects to remote server (works behind NAT/firewalls) |
| | - **Profile-Based Configuration**: Easily switch between different remote servers |
| | - **Bidirectional Streaming**: Video (robot β server) and Audio (robot β server) |
| | - **Movement Control**: Receive movement commands from remote server |
| | - **Connection Monitoring**: Track latency, frames, and connection health |
| | - **Optional REST API**: Query status and manage profiles via HTTP endpoints |
| |
|
| | ## Architecture |
| |
|
| | ``` |
| | Remote Server Robot (this app) Reachy Mini Daemon |
| | (Hugging Face Space) |
| | |
| | WebSocket Server βββββββ WebSocket Clients βββββββ ReachyMini SDK |
| | - /robot - robot_control.py (Zenoh protocol) |
| | - /video_stream - video_stream.py |
| | - /audio_stream - audio_stream.py |
| | ``` |
| |
|
| | The app connects TO a remote server as a client, not the other way around. This simplifies network setup since the robot only needs outbound connections. |
| |
|
| | ## Installation |
| |
|
| | ### From Source |
| |
|
| | ```bash |
| | cd reachy_mini_remote_control_app |
| | pip install -e . |
| | ``` |
| |
|
| | ### Requirements |
| |
|
| | - Python >= 3.10 |
| | - Reachy Mini daemon running (`reachy-mini-daemon`) |
| | - Remote server running (e.g., [reachy_mini_remote_control/app.py](../reachy_mini_remote_control/app.py)) |
| |
|
| | ## Usage |
| |
|
| | ### 1. Start the Remote Server |
| |
|
| | First, start the remote server that the robot will connect to: |
| |
|
| | ```bash |
| | cd ../reachy_mini_remote_control |
| | python app.py |
| | # Server starts on ws://localhost:8000 |
| | ``` |
| |
|
| | ### 2. Start the Reachy Mini Daemon |
| |
|
| | ```bash |
| | reachy-mini-daemon --mockup-sim |
| | ``` |
| |
|
| | ### 3. Start the Remote Control App |
| |
|
| | ```bash |
| | reachy-mini-remote-control-app --profile default |
| | ``` |
| |
|
| | The app will: |
| | - Connect to the remote server at `ws://localhost:8000` |
| | - Stream video and audio |
| | - Receive and execute movement commands |
| |
|
| | ### Command Line Options |
| |
|
| | ```bash |
| | reachy-mini-remote-control-app [OPTIONS] |
| | |
| | Options: |
| | --profile PROFILE Profile to use (default: from .env) |
| | --websocket-uri URI WebSocket URI to connect to (overrides profile) |
| | --robot-name NAME Robot name (default: reachy_mini) |
| | --log-level LEVEL Logging level (DEBUG, INFO, WARNING, ERROR) |
| | --no-rest-api Disable REST API for status endpoints |
| | ``` |
| |
|
| | ## Configuration |
| |
|
| | ### Profiles |
| |
|
| | Profiles are stored in `src/reachy_mini_remote_control_app/profiles/`. Each profile is a directory with a `config.txt` file. |
| |
|
| | **Default Profile** (`profiles/default/config.txt`): |
| | ``` |
| | WEBSOCKET_URI=ws://localhost:8000 |
| | VIDEO_JPEG_QUALITY=80 |
| | VIDEO_WITH_TIMESTAMP=false |
| | VIDEO_FPS=25 |
| | AUDIO_WITH_TIMESTAMP=false |
| | AUDIO_BATCH_SIZE=4096 |
| | ENABLE_METRICS_LOGGING=true |
| | METRICS_LOG_INTERVAL_SEC=5 |
| | ``` |
| |
|
| | **Example Remote Profile** (`profiles/example_remote/config.txt`): |
| | ``` |
| | WEBSOCKET_URI=wss://YOUR-SPACE.hf.space |
| | VIDEO_JPEG_QUALITY=75 |
| | VIDEO_WITH_TIMESTAMP=true |
| | VIDEO_FPS=25 |
| | AUDIO_WITH_TIMESTAMP=true |
| | AUDIO_BATCH_SIZE=4096 |
| | ENABLE_METRICS_LOGGING=true |
| | METRICS_LOG_INTERVAL_SEC=10 |
| | ``` |
| |
|
| | ### Connecting to Private Spaces |
| |
|
| | If you're using a private Hugging Face Space, you need to authenticate with a Hugging Face token: |
| |
|
| | 1. **Create a Hugging Face Access Token**: |
| | - Go to https://huggingface.co/settings/tokens |
| | - Create a new token with `read` permissions |
| | - Copy the token |
| |
|
| | 2. **Configure the Token**: |
| |
|
| | **Option A: Via Profile Configuration** (Recommended) |
| |
|
| | Add the token to your profile's `config.txt`: |
| | ``` |
| | WEBSOCKET_URI=wss://your-username-reachy-mini-remote-control.hf.space |
| | HF_TOKEN=hf_your_token_here |
| | ``` |
| |
|
| | **Option B: Via Environment Variable** |
| |
|
| | Add to your `.env` file: |
| | ``` |
| | HF_TOKEN=hf_your_token_here |
| | ``` |
| |
|
| | 3. **Run the app** - it will automatically use the token for authentication when connecting to the private space. |
| |
|
| | ### Environment Variables |
| |
|
| | Create a `.env` file (copy from `.env.example`): |
| |
|
| | ```bash |
| | REMOTE_CONTROL_PROFILE=default |
| | ROBOT_NAME=reachy_mini |
| | LOG_LEVEL=INFO |
| | VIDEO_JPEG_QUALITY=80 |
| | LATENCY_WARNING_MS=200 |
| | ENABLE_REST_API=true |
| | REST_API_HOST=0.0.0.0 |
| | REST_API_PORT=7860 |
| | # Optional: HF_TOKEN for private Hugging Face Spaces |
| | # HF_TOKEN=hf_your_token_here |
| | ``` |
| |
|
| | ## REST API (Optional) |
| |
|
| | If `ENABLE_REST_API=true`, the app provides HTTP endpoints: |
| |
|
| | ### Get Status |
| |
|
| | ```bash |
| | curl http://localhost:7860/status |
| | ``` |
| |
|
| | Response: |
| | ```json |
| | { |
| | "robot_connected": true, |
| | "control": { |
| | "connected": true, |
| | "commands_received": 42, |
| | "last_command_type": "movement", |
| | "last_activity": 1705123456.78 |
| | }, |
| | "video": { |
| | "connected": true, |
| | "frames_sent": 1234, |
| | "frames_dropped": 5, |
| | "fps": 24.8, |
| | "latency_ms": 45.2, |
| | "latency_avg_ms": 42.1, |
| | "latency_min_ms": 38.5, |
| | "latency_max_ms": 52.3, |
| | "last_activity": 1705123456.78 |
| | }, |
| | "audio": { |
| | "connected": true, |
| | "chunks_sent": 567, |
| | "chunks_received": 234, |
| | "latency_avg_ms": 38.5, |
| | "last_activity": 1705123456.78 |
| | } |
| | } |
| | ``` |
| |
|
| | ### List Profiles |
| |
|
| | ```bash |
| | curl http://localhost:7860/profiles |
| | ``` |
| |
|
| | Response: |
| | ```json |
| | { |
| | "profiles": ["default", "example_remote"], |
| | "current": "default" |
| | } |
| | ``` |
| |
|
| | ### Switch Profile |
| |
|
| | ```bash |
| | curl -X POST http://localhost:7860/profile/example_remote |
| | ``` |
| |
|
| | **Note**: Requires app restart to take effect. |
| |
|
| | ### Health Check |
| |
|
| | ```bash |
| | curl http://localhost:7860/health |
| | ``` |
| |
|
| | ## Integration with Reachy Mini Dashboard |
| |
|
| | This app integrates with the Reachy Mini dashboard as a `ReachyMiniApp`: |
| |
|
| | 1. Install the app: `pip install -e reachy_mini_remote_control_app` |
| | 2. The app will appear in the dashboard |
| | 3. Start from the dashboard UI |
| | 4. The dashboard provides the `ReachyMini` instance and `stop_event` |
| |
|
| | ## HuggingFace OAuth |
| |
|
| | This Space uses OAuth for seamless authentication. The metadata above enables OAuth with: |
| | - `hf_oauth: true` - Enables OAuth flow |
| | - `hf_oauth_expiration_minutes: 480` - Tokens valid for 8 hours |
| | - `hf_oauth_scopes: openid, profile` - Access to user info |
| |
|
| | ### How OAuth Works |
| |
|
| | 1. **User clicks "Sign in with Hugging Face"** in the web interface |
| | 2. **HuggingFace OAuth flow** - User authorizes the app |
| | 3. **Access token returned** - Stored securely in session storage |
| | 4. **Space cloning** - User can duplicate the remote control server to their account |
| | 5. **Private URI generated** - Custom WebSocket URI for their private space |
| |
|
| | The OAuth implementation uses the `@huggingface/hub` JavaScript library for client-side authentication. See [hf-auth.js](hf-auth.js) for implementation details. |
| |
|
| | ### For Robot Users |
| |
|
| | The robot doesn't need OAuth - it just connects to the WebSocket URI. OAuth is only used in the web interface for space management. |
| |
|
| | ## Deployment to Production |
| |
|
| | ### Hugging Face Space Setup |
| |
|
| | 1. Deploy the remote server ([reachy_mini_remote_control/app.py](../reachy_mini_remote_control/app.py)) to Hugging Face Space |
| | 2. Note the Space URL: `wss://YOUR-SPACE.hf.space` |
| | 3. Create a new profile: |
| |
|
| | ```bash |
| | mkdir -p src/reachy_mini_remote_control_app/profiles/production |
| | ``` |
| |
|
| | Edit `profiles/production/config.txt`: |
| | ``` |
| | WEBSOCKET_URI=wss://YOUR-SPACE.hf.space |
| | VIDEO_JPEG_QUALITY=75 |
| | VIDEO_WITH_TIMESTAMP=true |
| | VIDEO_FPS=25 |
| | AUDIO_WITH_TIMESTAMP=true |
| | AUDIO_BATCH_SIZE=4096 |
| | ENABLE_METRICS_LOGGING=true |
| | METRICS_LOG_INTERVAL_SEC=10 |
| | ``` |
| |
|
| | 4. Set environment variable: |
| | ```bash |
| | export REMOTE_CONTROL_PROFILE=production |
| | ``` |
| |
|
| | 5. Run the app: |
| | ```bash |
| | reachy-mini-remote-control-app --profile production |
| | ``` |
| |
|
| | ### Network Requirements |
| |
|
| | - **Robot side**: Only **outbound** connections needed (no port forwarding required) |
| | - **Server side**: WebSocket server must be publicly accessible |
| | - **Protocol**: Use WSS (WebSocket Secure) for production |
| |
|
| | ### Security Considerations |
| |
|
| | - Use WSS (not WS) for encrypted connections |
| | - Consider implementing authentication tokens |
| | - Monitor connection logs for suspicious activity |
| | - Rate limiting on the server side |
| |
|
| | ## Troubleshooting |
| |
|
| | ### Robot fails to connect to daemon |
| |
|
| | ``` |
| | Failed to connect to robot: Connection timeout |
| | ``` |
| |
|
| | **Solution**: Make sure the daemon is running: |
| | ```bash |
| | reachy-mini-daemon --mockup-sim |
| | ``` |
| |
|
| | ### WebSocket connection fails |
| |
|
| | ``` |
| | [Robot Control] Connection failed: Cannot connect to host |
| | ``` |
| |
|
| | **Solutions**: |
| | 1. Verify the remote server is running and accessible |
| | 2. Check the `WEBSOCKET_URI` in your profile |
| | 3. Test connectivity: `curl http://YOUR-SERVER:8000/health` (if server has health endpoint) |
| | 4. Check firewall rules |
| |
|
| | ### No video/audio streaming |
| |
|
| | **Solutions**: |
| | 1. Ensure media is started: check daemon logs |
| | 2. Verify WebSocket connections are established: check `/status` endpoint |
| | 3. Check frame/audio publisher threads are running (look for log messages) |
| |
|
| | ### High latency |
| |
|
| | Check the `/status` endpoint for latency metrics: |
| | ```bash |
| | curl http://localhost:7860/status | jq '.video.latency_avg_ms' |
| | ``` |
| |
|
| | **Solutions**: |
| | - Reduce `VIDEO_JPEG_QUALITY` in profile (e.g., from 80 to 60) |
| | - Lower `VIDEO_FPS` (e.g., from 25 to 15) |
| | - Use a server geographically closer to the robot |
| | - Check network bandwidth |
| |
|
| | ## Development |
| |
|
| | ### Running Tests |
| |
|
| | ```bash |
| | pytest tests/ |
| | ``` |
| |
|
| | ### Code Structure |
| |
|
| | - `config.py` - Configuration management and profile loading |
| | - `monitoring/` - Metrics tracking and connection monitoring |
| | - `websocket_clients/` - WebSocket client implementations |
| | - `robot_control.py` - Receive movement commands |
| | - `video_stream.py` - Send video frames |
| | - `audio_stream.py` - Bidirectional audio |
| | - `app.py` - Optional REST API for status |
| | - `main.py` - Entry point and ReachyMiniApp implementation |
| |
|
| | ## License |
| |
|
| | Same as Reachy Mini SDK. |
| |
|
| | ## Support |
| |
|
| | For issues and questions: |
| | - GitHub Issues: [pollen-robotics/reachy_mini](https://github.com/pollen-robotics/reachy_mini/issues) |
| | - Email: contact@pollen-robotics.com |
| |
|