docs: rewrite README with architecture, USB 2 quirks, dev workflow
This commit is contained in:
1 parent
07d95792e3
commit
739afd465b
1 file changed
+287
-128
@@ -1,168 +1,327 @@
|
|||||||
# Intel RealSense D435 — API Server
|
# RealSense D435 — API Server
|
||||||
|
|
||||||
Server FastAPI per la depth camera Intel RealSense D4xx (testato su D435)
|
Container Docker che espone una Intel RealSense D4xx (testata su D435) via
|
||||||
con accesso remoto via REST/WebSocket. Esecuzione tramite Docker. Mantiene
|
REST + WebSocket, con la **stessa shape API del Nuwa-HP60C**: envelope
|
||||||
la stessa shape API del servizio Nuwa HP60C (envelope `ApiResponse`,
|
`ApiResponse`, endpoint `/api/...`, header `X-Api-Key`, WebSocket `/ws`.
|
||||||
endpoint `/api/...`, header `X-Api-Key`, WebSocket `/ws`) così che i client
|
Pensato come drop-in replacement del container Nuwa nella pipeline del
|
||||||
e il frontend React esistenti funzionano senza modifiche.
|
pestello, così i client esistenti (`pestello-pose-detector`, frontend
|
||||||
|
React, ecc.) consumano frame senza modifiche.
|
||||||
|
|
||||||
## Caratteristiche
|
Gira sul robot **Unitree H1** (Jetson Xavier NX, JetPack 5.1.x). Il repo
|
||||||
|
è su [git.humion.it](https://git.humion.it/Labotics-OnGianni/RealSense-D435-H1).
|
||||||
|
|
||||||
- **RGB**: configurabile (default 640x480) BGR8, allineato al depth
|
---
|
||||||
- **Depth**: 640x480 uint16 in millimetri (allineato al color via `rs.align`)
|
|
||||||
- **Intrinsics**: parametri intrinseci color + depth e estrinseci depth→color
|
|
||||||
- **Discovery**: enumerazione devices via `pyrealsense2`
|
|
||||||
- **API Server**: REST + WebSocket con envelope `ApiResponse` standard
|
|
||||||
- **Sicurezza**: API Key opzionale (`X-Api-Key`) su tutti gli endpoint REST
|
|
||||||
- **NATS**: messaging asincrono opzionale (profilo `nats`)
|
|
||||||
- **Frontend React**: viewer RGB, depth e 3D point cloud (riusato dal Nuwa)
|
|
||||||
- **Swagger**: documentazione interattiva API a `/apidocs`
|
|
||||||
|
|
||||||
## Hardware
|
## Architettura
|
||||||
|
|
||||||
| Parametro | Valore |
|
|
||||||
|-----------|--------|
|
|
||||||
| Camera | Intel RealSense D435 |
|
|
||||||
| Serial number (questo robot) | `933322070696` |
|
|
||||||
| Firmware | `05.16.00.01` |
|
|
||||||
| Range depth | 0.1m – 10m |
|
|
||||||
| Interfaccia | USB 3.0 |
|
|
||||||
| SDK | librealsense 2.55.1 + pyrealsense2 (built from source) |
|
|
||||||
| Host | Jetson Xavier NX, Ubuntu 20.04 (JetPack 5.1.x) |
|
|
||||||
|
|
||||||
## Configurazione
|
|
||||||
|
|
||||||
Crea `.env` (vedi `.env.example`):
|
|
||||||
|
|
||||||
```env
|
|
||||||
API_PORT=8878
|
|
||||||
API_KEY=cambia-questa-chiave-segreta
|
|
||||||
CAMERA_WIDTH=640
|
|
||||||
CAMERA_HEIGHT=480
|
|
||||||
CAMERA_FPS=30
|
|
||||||
CAMERA_AUTO_OPEN=1 # apre la camera al boot, niente /api/open manuale
|
|
||||||
CORS_ORIGINS=* # LAN-only OK
|
|
||||||
```
|
|
||||||
|
|
||||||
## Accesso dalla LAN
|
|
||||||
|
|
||||||
Il container gira sul robot e binda la porta `8878` su tutte le interfacce
|
|
||||||
(`0.0.0.0`). Dal vostro PC sulla stessa LAN raggiungete il servizio via:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
http://<ip-robot>:8878/api/health # health check
|
┌────────────────────┐ RGB JPEG (HTTP) ┌────────────────────────────┐
|
||||||
http://<ip-robot>:8878/apidocs # Swagger UI
|
│ yolo-server │ ◄──────────────────── │ pestello-pose-detector │
|
||||||
http://<ip-robot>:8878/gui # frontend React
|
│ (su harry) │ ──► bbox + conf │ (su harry) │
|
||||||
ws://<ip-robot>:8878/ws # stream WebSocket
|
└────────────────────┘ │ │
|
||||||
|
│ │ │
|
||||||
|
│ │ /api/rgb │
|
||||||
|
│ │ /api/depth │
|
||||||
|
│ │ /api/intrinsics │
|
||||||
|
│ ▼ │
|
||||||
|
┌───────────────────┴────┐ │
|
||||||
|
│ RealSense-D435-H1 ⬅️ │ ← QUESTO REPO │
|
||||||
|
│ (sul robot, port 8878)│ │
|
||||||
|
└────────────────────────┘ │
|
||||||
|
(era: Nuwa-HP60C) │
|
||||||
|
│
|
||||||
```
|
```
|
||||||
|
|
||||||
Il robot ha Avahi attivo, quindi `ubuntu.local:8878` funziona se mDNS
|
Il container fa **solo** acquisizione e serve frame — niente inferenza,
|
||||||
risolve sul vostro PC (`avahi-resolve -n ubuntu.local`). Altrimenti
|
niente pose estimation. Quella logica vive in container separati su harry.
|
||||||
usate l'IP diretto (`ip a` sul robot per scoprirlo).
|
|
||||||
|
|
||||||
> Lo streaming **non richiede internet** — solo la build (~25 min al primo
|
---
|
||||||
> avvio) deve raggiungere registry Docker/apt/PyPI/npm via il tinyproxy
|
|
||||||
> locale del robot.
|
|
||||||
|
|
||||||
## Build & avvio
|
## Hardware constraint importante: D435 su USB 2.0
|
||||||
|
|
||||||
|
Sul robot H1 la D435 è collegata a una porta USB-C frontale che, anche se
|
||||||
|
fisicamente è USB-C, è **cablata USB 2.0** lato Jetson (verificato: anche
|
||||||
|
un adapter ax88179 sullo stesso bus gira a 480 Mbps invece dei suoi 5
|
||||||
|
Gbps nativi). Il controller USB 3 del Jetson esiste ma non è esposto
|
||||||
|
esternamente sulla scocca.
|
||||||
|
|
||||||
|
Per cui il driver, all'apertura del device, controlla
|
||||||
|
`usb_type_descriptor` e si adatta:
|
||||||
|
|
||||||
|
| | **USB 2.x** (situazione attuale) | **USB 3.x** (se mai) |
|
||||||
|
|---|---|---|
|
||||||
|
| Color format | YUYV (l'unico che il D4xx sostiene su USB 2) | BGR8 |
|
||||||
|
| Color resolution | 640x480 @ 15 fps (≈4 fps reali) | 640x480 @ 30 fps |
|
||||||
|
| Depth resolution | 640x480 @ 15 fps | 640x480 @ 30 fps |
|
||||||
|
| Alignment depth↔color | Approximate (resize numpy) | Hardware (rs.align) |
|
||||||
|
| Conversione YUYV→BGR | sì, via `cv2.cvtColor` | non serve |
|
||||||
|
|
||||||
|
I dettagli sui workaround applicati sono in [STATUS.md](STATUS.md).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
### Sul robot (deploy)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Backend (porta 8878)
|
cd ~/Robot_2026/RealSense-D435
|
||||||
docker compose up --build -d
|
|
||||||
|
|
||||||
# Backend + NATS
|
# Build + run (la prima volta build di librealsense da source: ~25 min)
|
||||||
docker compose --profile nats up --build -d
|
sg docker -c "docker compose up -d"
|
||||||
|
|
||||||
|
# Stato
|
||||||
|
curl http://localhost:8878/api/health
|
||||||
|
# → {"success":true,"data":{"status":"ok","sdk_initialized":true,"camera_open":true,...}}
|
||||||
|
|
||||||
|
# Stop
|
||||||
|
sg docker -c "docker compose down"
|
||||||
```
|
```
|
||||||
|
|
||||||
> Il primo build compila i bindings Python di `pyrealsense2` da source —
|
Il container ha `restart: unless-stopped`, quindi resta su dopo reboot
|
||||||
> ~20–30 min su Jetson. I build successivi sono cached.
|
del robot (purché `docker.service` parta — `systemctl enable docker` se
|
||||||
|
non lo è già).
|
||||||
|
|
||||||
Il container:
|
### Dal tuo PC (consumare lo stream)
|
||||||
- non fa unbind UVC (a differenza del Nuwa) — RealSense usa direttamente uvcvideo
|
|
||||||
- monta `/dev/bus/usb` in privileged mode per accesso diretto USB
|
Dall'IP LAN del robot (`192.168.123.99`) o via mDNS (`ubuntu.local`):
|
||||||
- riparte automaticamente (`restart: unless-stopped`)
|
|
||||||
|
```bash
|
||||||
|
# Verifica connettività
|
||||||
|
curl http://192.168.123.99:8878/api/health
|
||||||
|
|
||||||
|
# Frame singoli
|
||||||
|
curl http://192.168.123.99:8878/api/rgb -o rgb.jpg
|
||||||
|
curl http://192.168.123.99:8878/api/depth -o depth.png
|
||||||
|
|
||||||
|
# Frontend interattivo
|
||||||
|
firefox http://192.168.123.99:8878/gui
|
||||||
|
|
||||||
|
# Swagger UI
|
||||||
|
firefox http://192.168.123.99:8878/apidocs
|
||||||
|
```
|
||||||
|
|
||||||
|
Da harry (192.168.123.100) sostituisci nell'`.env` del
|
||||||
|
`pestello-pose-detector` l'URL della camera con
|
||||||
|
`http://192.168.123.99:8878`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Endpoints
|
## Endpoints
|
||||||
|
|
||||||
Identici al Nuwa per drop-in compatibility:
|
|
||||||
|
|
||||||
| Endpoint | Metodo | Descrizione |
|
| Endpoint | Metodo | Descrizione |
|
||||||
|----------|--------|-------------|
|
|---|---|---|
|
||||||
| `/api/health` | GET | Health check (no auth) |
|
| `/api/health` | GET | Health check (no API key) |
|
||||||
| `/api/status` | GET | Stato SDK/camera e calibrazione |
|
| `/api/status` | GET | Stato SDK/camera, `color_available`, `usb_type`, intrinsics |
|
||||||
| `/api/discover` | GET | Rileva camere RealSense su USB |
|
| `/api/discover` | GET | Enumera D4xx su USB |
|
||||||
| `/api/open` | POST | Apre camera per indice (`device_index`) |
|
| `/api/open` | POST | Apre camera per `device_index` (di default partita in auto-open) |
|
||||||
| `/api/close` | POST | Chiude la camera |
|
| `/api/close` | POST | Chiude camera |
|
||||||
| `/api/capture` | GET | Frame RGB+depth (JSON, base64) |
|
| `/api/capture` | GET | RGB+depth in JSON (base64) |
|
||||||
| `/api/rgb` | GET | Frame RGB come JPEG |
|
| `/api/rgb` | GET | RGB come JPEG |
|
||||||
| `/api/depth` | GET | Frame depth come PNG 16-bit (mm) |
|
| `/api/depth` | GET | Depth come PNG 16-bit (mm) |
|
||||||
| `/api/depth/color` | GET | Depth colormap JET come JPEG |
|
| `/api/depth/color` | GET | Depth colormap JET come JPEG |
|
||||||
| `/api/intrinsics` | GET | Calibrazione completa |
|
| `/api/intrinsics` | GET | Calibrazione completa (`ir`+`rgb`+`extrinsics_ir_to_rgb`) |
|
||||||
| `/api/pointcloud` | GET | Point cloud (subsampling `step`) |
|
| `/api/pointcloud` | GET | Point cloud `[x,y,z,r,g,b]` (param `step`, `max_depth_mm`) |
|
||||||
| `/api/pointcloud/roi` | GET | Point cloud su ROI pixel-space |
|
| `/api/pointcloud/roi` | GET | Point cloud su ROI pixel-space |
|
||||||
| `/api/measure` | GET | Backprojection 3D di un pixel |
|
| `/api/measure` | GET | Backprojection 3D di un pixel |
|
||||||
| `/api/snapshot` | POST | Salva snapshot RGB |
|
| `/api/snapshot` | POST | Salva snapshot RGB su disco |
|
||||||
| `/api/recording/{start,stop,status}` | POST/GET | Registrazione continua |
|
| `/api/recording/{start,stop,status}` | POST/GET | Registrazione continua |
|
||||||
| `/ws` | WS | Streaming WebSocket (text msgs: `start`, `stop`, `close`) |
|
| `/ws` | WebSocket | Streaming (text: `start`, `stop`, `close`) |
|
||||||
|
| `/gui` | GET | Frontend React |
|
||||||
|
| `/apidocs` | GET | Swagger UI |
|
||||||
|
|
||||||
#### Payload calibrazione
|
### Header autenticazione
|
||||||
|
|
||||||
|
Tutti gli endpoint sotto `/api/` (eccetto `/api/health`) richiedono
|
||||||
|
header `X-Api-Key: <valore di API_KEY nel .env>`. Per disabilitare l'auth
|
||||||
|
in dev, mettere `API_KEY=` (vuoto) — sconsigliato in produzione.
|
||||||
|
|
||||||
|
### Payload calibrazione
|
||||||
|
|
||||||
`/api/intrinsics` ritorna i campi `ir` e `rgb` per compatibilità con il
|
`/api/intrinsics` ritorna i campi `ir` e `rgb` per compatibilità con il
|
||||||
frontend Nuwa, ma in questo servizio:
|
frontend Nuwa, ma su D4xx significano:
|
||||||
|
|
||||||
- `ir` = intrinseci del **sensore depth** (post-rectification dello stereo IR)
|
- `ir` = intrinseci del **sensore depth** (post-rectification dello stereo IR)
|
||||||
- `rgb` = intrinseci del **sensore color**
|
- `rgb` = intrinseci del **sensore color**
|
||||||
- `extrinsics_ir_to_rgb` = trasformazione **depth → color**
|
- `extrinsics_ir_to_rgb` = trasformazione **depth → color** (translation in mm)
|
||||||
|
|
||||||
```json
|
---
|
||||||
{
|
|
||||||
"ir": { "fx": ..., "fy": ..., "cx": ..., "cy": ...,
|
## Configurazione (`.env`)
|
||||||
"distortion": { "k1":..., "k2":..., "k3":..., "p1":..., "p2":... } },
|
|
||||||
"rgb": { "fx": ..., "fy": ..., "cx": ..., "cy": ...,
|
```env
|
||||||
"distortion": { ... } },
|
API_PORT=8878
|
||||||
"extrinsics_ir_to_rgb": {
|
API_KEY=<chiave-segreta>
|
||||||
"rotation": [r00, r01, r02, r10, r11, r12, r20, r21, r22],
|
CAMERA_WIDTH=640
|
||||||
"translation": [tx, ty, tz]
|
CAMERA_HEIGHT=480
|
||||||
}
|
CAMERA_FPS=30
|
||||||
}
|
CAMERA_AUTO_OPEN=1
|
||||||
|
CORS_ORIGINS=*
|
||||||
```
|
```
|
||||||
|
|
||||||
- Rotation row-major 3x3
|
Note:
|
||||||
- Translation in **millimetri** (la D4xx ritorna `extrinsics.translation` in
|
- `CAMERA_WIDTH/HEIGHT/FPS` sono **ignorati su USB 2** (forziamo 640x480@15
|
||||||
metri; convertito qui per allinearsi alla convenzione Nuwa)
|
YUYV perché è l'unica combinazione che la D4xx sostiene). Su USB 3 invece
|
||||||
- D4xx pubblica tipicamente coefficienti di distorsione tutti zero (immagini
|
vengono rispettati.
|
||||||
già rettificate dall'ASIC)
|
- `.env` è nel `.gitignore` — non viene committato. Tienine una copia di
|
||||||
|
backup; `.env.example` è la struttura di riferimento.
|
||||||
|
|
||||||
### Esempi curl
|
---
|
||||||
|
|
||||||
|
## Modello hardware corrente del robot
|
||||||
|
|
||||||
|
```
|
||||||
|
Jetson Xavier NX
|
||||||
|
├─ Bus 1 (USB 2.0, 480M)
|
||||||
|
│ ├─ Hub interno → Inspire Hands (cdc_acm /dev/ttyACM0) + ch341
|
||||||
|
│ │ ⚠️ Non staccare questi — sono elettronica del robot
|
||||||
|
│ └─ Hub esterno (porta USB-C frontale)
|
||||||
|
│ ├─ Tastiera, mouse, ax88179 (Ethernet)
|
||||||
|
│ └─ D435 ← qui
|
||||||
|
└─ Bus 2 (USB 3.0, 10000M) — VUOTO, non esposto esternamente
|
||||||
|
```
|
||||||
|
|
||||||
|
- D435 serial: `933322070696`, firmware `05.16.00.01`, `usb_type = 2.1`
|
||||||
|
- Robot IP: `192.168.123.99` (eth0), `10.99.99.101` (ZeroTier)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Workflow di sviluppo
|
||||||
|
|
||||||
|
Il codice "live" gira sul robot. Per modifiche:
|
||||||
|
|
||||||
|
### Opzione A — Modifichi sul robot, sync su harry, push da harry
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Discover
|
# 1. Sul robot
|
||||||
curl -H "X-Api-Key: $API_KEY" http://localhost:8878/api/discover
|
cd ~/Robot_2026/RealSense-D435
|
||||||
|
# ...modifiche...
|
||||||
|
sg docker -c "docker compose build backend && docker compose up -d --force-recreate"
|
||||||
|
curl http://localhost:8878/api/health # verifica
|
||||||
|
|
||||||
# Apri (D435 in genere index 0)
|
# 2. Rsync su harry (esclude .env, models/, images/, __pycache__)
|
||||||
curl -X POST -H "X-Api-Key: $API_KEY" \
|
rsync -avz --delete \
|
||||||
"http://localhost:8878/api/open?device_index=0"
|
--exclude='.env' --exclude='__pycache__' --exclude='*.pyc' \
|
||||||
|
--exclude='.pytest_cache' --exclude='.venv' \
|
||||||
|
--exclude='node_modules' --exclude='src/frontend/react/dist' \
|
||||||
|
--exclude='images/*' --exclude='models/*' \
|
||||||
|
--exclude='.claude' --exclude='.omc' \
|
||||||
|
~/Robot_2026/RealSense-D435/ \
|
||||||
|
harry@192.168.123.100:/opt/docker/robotserver/RealSense-D435/
|
||||||
|
|
||||||
# Frame RGB
|
# 3. Push da harry
|
||||||
curl -H "X-Api-Key: $API_KEY" http://localhost:8878/api/rgb -o rgb.jpg
|
ssh harry@192.168.123.100
|
||||||
|
cd /opt/docker/robotserver/RealSense-D435
|
||||||
# Frame depth (PNG 16-bit, valori in mm)
|
git add . && git commit -m "..." && git push
|
||||||
curl -H "X-Api-Key: $API_KEY" http://localhost:8878/api/depth -o depth.png
|
|
||||||
|
|
||||||
# Intrinsics
|
|
||||||
curl -H "X-Api-Key: $API_KEY" http://localhost:8878/api/intrinsics | jq
|
|
||||||
|
|
||||||
# Close
|
|
||||||
curl -X POST -H "X-Api-Key: $API_KEY" http://localhost:8878/api/close
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Note
|
### Opzione B — Modifichi su harry, deploy sul robot
|
||||||
|
|
||||||
- `librealsense2` runtime nel container è installato dal repo apt ufficiale
|
```bash
|
||||||
Intel (pinned a `2.55.1-0~realsense.3337`). I bindings Python sono
|
# 1. Su harry
|
||||||
buildati da `IntelRealSense/librealsense@v2.55.1`.
|
cd /opt/docker/robotserver/RealSense-D435
|
||||||
- Il frontend React originale (`/gui`) referenzia `ir` e `rgb` come label di
|
git pull # o sviluppa direttamente
|
||||||
display — su questo servizio quei nomi mappano depth/color (vedi sopra).
|
# ...modifiche...
|
||||||
- L'autostart è gestito da Docker (`restart: unless-stopped`). Per partire
|
git add . && git commit -m "..." && git push
|
||||||
automaticamente al boot del robot serve `systemctl enable docker`.
|
|
||||||
- Per disabilitare l'auth API setta `API_KEY=` (vuoto). Sconsigliato in produzione.
|
# 2. Sul robot
|
||||||
|
cd ~/Robot_2026/RealSense-D435
|
||||||
|
# ⚠️ Il robot non può push/pull diretto verso git.humion.it (proxy lo blocca).
|
||||||
|
# Sync via rsync nella direzione opposta:
|
||||||
|
rsync -avz --delete \
|
||||||
|
--exclude='.env' --exclude='__pycache__' --exclude='*.pyc' \
|
||||||
|
--exclude='images/*' --exclude='models/*' \
|
||||||
|
--exclude='.claude' --exclude='.omc' \
|
||||||
|
harry@192.168.123.100:/opt/docker/robotserver/RealSense-D435/ \
|
||||||
|
~/Robot_2026/RealSense-D435/
|
||||||
|
|
||||||
|
sg docker -c "docker compose build backend && docker compose up -d --force-recreate"
|
||||||
|
```
|
||||||
|
|
||||||
|
Nota: sul robot l'SSH verso `git.humion.it:222` viene bloccato dal
|
||||||
|
tinyproxy locale. Si può risolvere con una regola in `~/.ssh/config` se
|
||||||
|
in futuro vorrai pushare diretto dal robot.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Risoluzione di problemi noti
|
||||||
|
|
||||||
|
### `pyrealsense2` ha `AttributeError: module ... has no attribute 'context'`
|
||||||
|
Il bug install di `librealsense@v2.55.1` (il `.so` principale non viene
|
||||||
|
installato dal CMake) è risolto nel `Dockerfile`. Se vuoi ricontrollare:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sg docker -c "docker compose exec backend python3 -c \
|
||||||
|
'import pyrealsense2 as rs; print(hasattr(rs, \"context\"))'"
|
||||||
|
# → True
|
||||||
|
```
|
||||||
|
|
||||||
|
Vedi `Dockerfile` righe ~36-46 e il commento.
|
||||||
|
|
||||||
|
### `wait_for_frames failed: Frame didn't arrive within 5000`
|
||||||
|
Il device è su USB 2 e il driver è in modalità errata (es. configurato per
|
||||||
|
BGR8). Verifica:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://localhost:8878/api/status | jq .data.usb_type
|
||||||
|
# → "2.1" → il driver dovrebbe essere in modalità YUYV
|
||||||
|
```
|
||||||
|
|
||||||
|
Se il problema persiste, controlla `docker compose logs backend` per
|
||||||
|
warning con "USB2 profile".
|
||||||
|
|
||||||
|
### Voglio attivare il bottone "Predict" nella GUI
|
||||||
|
Quel bottone è un avanzo del codice copiato dal Nuwa, ma in produzione
|
||||||
|
non viene usato — l'inferenza YOLO gira sul container `yolo-server` su
|
||||||
|
harry (con il modello custom `best.onnx` per il pestello). Vedi
|
||||||
|
[architettura](#architettura).
|
||||||
|
|
||||||
|
Per attivare il detector inline (sconsigliato per la pipeline pestello,
|
||||||
|
ma utile per test):
|
||||||
|
1. Aggiungere `onnxruntime` nel `Dockerfile`
|
||||||
|
2. Copiare un modello in `models/best.onnx`
|
||||||
|
3. Settare `YOLO_*` nel `.env`
|
||||||
|
|
||||||
|
### Posso pushare/pullare git direttamente dal robot?
|
||||||
|
Al momento no — il tinyproxy del robot blocca l'SSH verso `git.humion.it:222`.
|
||||||
|
Workaround: `rsync` da/verso harry e push da lì. Vedi
|
||||||
|
[Workflow di sviluppo](#workflow-di-sviluppo).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Struttura del repo
|
||||||
|
|
||||||
|
```
|
||||||
|
RealSense-D435/
|
||||||
|
├── Dockerfile # multi-stage: librealsense + frontend + runtime
|
||||||
|
├── docker-compose.yml # backend + nats opzionale + frontend-dev
|
||||||
|
├── .env / .env.example # config (NON committare .env)
|
||||||
|
├── pyproject.toml # deps Python (per uv/pip)
|
||||||
|
├── README.md # questo file
|
||||||
|
├── STATUS.md # snapshot ultima sessione di lavoro
|
||||||
|
├── scripts/
|
||||||
|
│ └── entrypoint.sh
|
||||||
|
├── src/backend/
|
||||||
|
│ ├── main.py # FastAPI app
|
||||||
|
│ ├── config.py # pydantic settings
|
||||||
|
│ ├── api/
|
||||||
|
│ │ ├── routes.py # REST endpoints
|
||||||
|
│ │ ├── websocket.py # /ws streaming
|
||||||
|
│ │ └── dependencies.py # API key auth
|
||||||
|
│ └── services/
|
||||||
|
│ ├── camera.py # ⭐ driver RealSense (detection USB 2/3, YUYV, etc.)
|
||||||
|
│ ├── detector.py # wrapper ONNX YOLO (non usato in produzione)
|
||||||
|
│ └── image_saver.py
|
||||||
|
├── src/frontend/react/ # GUI a /gui (built via stage 2 del Dockerfile)
|
||||||
|
├── tests/ # pytest, da rilanciare quando si tocca services/
|
||||||
|
├── models/ # vuoto — modello sta su yolo-server, non qui
|
||||||
|
└── images/ # output snapshot/recording, gitignored
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Riferimenti
|
||||||
|
|
||||||
|
- [librealsense](https://github.com/IntelRealSense/librealsense) — buildato da source perché manca wheel ARM64 (`librealsense@v2.55.1`)
|
||||||
|
- [Nuwa-HP60C](https://git.humion.it/Labotics-gianniact/) — container originale di cui questo è il drop-in equivalent
|
||||||
|
- [yolo-server](https://git.humion.it/Labotics-gianniact/) — microservizio YOLO usato da pestello-pose-detector
|
||||||
|
- [pestello-pose-detector](https://git.humion.it/Labotics-gianniact/pestello-pose-detector) — consumer reale di questo stream
|
||||||
Reference in new issue
Block a user