File size: 10,982 Bytes
60b0537
 
 
 
 
 
 
 
cb39be8
 
c8d7c71
898dc3e
2c740fd
ceedcc7
60b0537
 
 
 
 
5ecb3ec
 
 
 
cb39be8
 
 
 
 
 
 
 
 
 
 
 
 
 
0a14fcd
 
cb39be8
 
 
5ecb3ec
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0a14fcd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5ecb3ec
 
 
 
 
 
 
 
 
 
 
 
 
0a14fcd
 
5ecb3ec
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cb39be8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5ecb3ec
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
---
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