Files
RealSense-D435i-G1/STATUS.md
T
robot 07d95792e3 Initial commit: RealSense D435 API server
Drop-in replacement for the Nuwa-HP60C camera container, exposing RGB +
aligned depth + intrinsics via REST/WebSocket so the existing
pestello-pose-detector pipeline can consume frames without changes.

Key adaptations for D4xx on USB 2.0 (this robot has no USB 3 port exposed
externally — see STATUS.md):
- pyrealsense2 built from source; the librealsense v2.55.1 install rule
  doesn't ship the main .so, so we copy it from the build dir and add an
  __init__.py that re-exports the submodule.
- Color stream uses YUYV format on USB 2.x (BGR8/RGB8 time out on this
  bus); converted to BGR via cv2.cvtColor in capture().
- rs.align is skipped on USB 2 (incompatible with YUYV); color is
  cv2-resized to depth shape for approximate per-pixel alignment.
- Driver auto-detects usb_type_descriptor and falls back to the
  full-resolution BGR8 + rs.align pipeline when on USB 3.

Tested: /api/{health,status,discover,rgb,depth,depth/color,capture,
intrinsics} all return 200 with valid payloads at 640x480.
2026-05-19 00:58:23 +02:00

80 lines
4.3 KiB
Markdown

# Stato del progetto RealSense-D435 — 2026-05-19
## TL;DR
- ✅ Driver completo e funzionante su questo robot (Jetson Xavier NX, D435 su USB 2.1)
- ✅ RGB 640x480 + Depth 640x480 simultanei via REST/WebSocket
- ✅ Intrinsics, point cloud, measure, snapshot, recording, WebSocket stream — tutti operativi
- ⚠️ Framerate effettivo ~4 fps (limitato dalla banda USB 2.0). Su porta USB 3 il driver riprende automaticamente 640x480@30.
## Cosa è stato risolto in questa sessione
1. **Bug install di librealsense v2.55.1**: il `.so` principale di `pyrealsense2` non viene installato dal CMake — solo `pyrsutils.so`. Workaround nel `Dockerfile`: si copia il `.so` direttamente da `/src/librealsense/build/Release/` e si aggiunge un `__init__.py` che riesporta il submodule (`from .pyrealsense2 import *`).
2. **D4xx su USB 2 — formato color**: BGR8/RGB8 vanno in timeout su USB 2 anche da soli (firmware D4xx). Solo **YUYV** sostiene il transfer su USB 2. Il driver ora rileva `usb_type_descriptor` e su USB 2.x configura color = YUYV, convertendo in BGR via `cv2.cvtColor` in `capture()`.
3. **`rs.align` incompatibile con YUYV**: il blocco di processing fallisce con "Error occurred during execution of the processing block". Su USB 2 saltiamo l'alignment hardware e facciamo un resize numpy del color per matchare la shape del depth (approximate alignment, OK per use case standard).
4. **Risoluzione massima USB 2**: 640x480@15 (configurato) → ~4 fps reali. Testate tutte le combinazioni; 848x480 dà "Couldn't resolve requests" anche in YUYV.
## Hardware setup (constatato)
```
Jetson Xavier NX
├─ Bus 1 (USB 2.0, 480M)
│ ├─ Hub interno → Inspire Hands (cdc_acm /dev/ttyACM0) + ch341
│ └─ Hub esterno (collegato a porta USB-C frontale)
│ ├─ Tastiera, mouse, ax88179 (Ethernet)
│ └─ D435 ← qui
└─ Bus 2 (USB 3.0, 10000M) — VUOTO, ma probabilmente non esposto esternamente
```
- D435 serial: `933322070696`, fw `05.16.00.01`, USB `8086:0b07`, `usb_type = 2.1`
- La porta USB-C frontale del robot H1 è cablata **USB 2 hardware** (confermato indirettamente: l'ax88179 sullo stesso hub gira a 480M)
- Le Inspire Hands sono su hub interno separato — non vanno toccate
## Endpoints (verificati)
| Endpoint | HTTP | Note |
|---|---|---|
| `/api/health` | 200 | sdk_initialized=true, camera_open=true |
| `/api/status` | 200 | include `color_available`, `usb_type` |
| `/api/discover` | 200 | rileva D435 serial `933322070696` |
| `/api/rgb` | 200 | JPEG 640x480 |
| `/api/depth` | 200 | PNG 16-bit 640x480 |
| `/api/depth/color` | 200 | JPEG colormap JET 640x480 |
| `/api/capture` | 200 | JSON con tutte e tre base64 |
| `/api/intrinsics` | 200 | ir + rgb + extrinsics_ir_to_rgb |
| `/api/pointcloud`, `/api/pointcloud/roi`, `/api/measure`, `/api/snapshot` | 200 | da testare in scenario reale |
## File modificati in questa sessione
- `Dockerfile`: fix install pyrealsense2 (`.so` + `__init__.py`)
- `src/backend/services/camera.py`:
- rileva `usb_type_descriptor` in `open()`
- profilo USB 2 (YUYV 640x480@15 color + Z16 640x480@15 depth)
- conversione YUYV → BGR in `capture()` via `cv2.cvtColor` (manuale, dopo aver ricostruito lo shape (H,W,2))
- skip `rs.align` su USB 2; resize numpy del color per matchare il depth
- nuovi metodi `is_color_available()`, `usb_type()` per diagnostica
- `src/backend/api/routes.py`: `/api/status` espone `color_available` + `usb_type`
## Da fare prossima volta
- Testare `/api/pointcloud` e `/api/measure` in un ambiente reale e verificare che l'approximate alignment (resize) sia accettabile per il caso d'uso. Se no, implementare alignment proprio con `cv2.remap` usando intrinsics + extrinsics.
- Decidere se esporre il flag `usb_type` nel frontend React per warning utente
- Eventualmente: profilo configurabile via `.env` per chi vuole controllare manualmente
## Modifiche al setup ambiente (persistono nei reboot)
1. `/etc/systemd/system/docker.service.d/http-proxy.conf` (proxy daemon)
2. `unitree` nel gruppo `docker`
3. `~/.docker/config.json` con proxy CLI + cli-plugins path
4. `~/.docker/cli-plugins/docker-compose` (plugin v2)
## Avvio rapido
```bash
cd ~/Robot_2026/RealSense-D435
sg docker -c "docker compose up -d" # già buildato
curl -s http://localhost:8878/api/health # check
curl -s http://localhost:8878/api/rgb -o rgb.jpg
curl -s http://localhost:8878/api/depth -o depth.png
```