feat: calibration helper scripts + DANIILIDIS solver default + dual-robot README

- scripts/: explore_and_calibrate.py (probe envelope from actual + random sampling),
  extend_calibration.py (loop fino a n_used >= TARGET_GOOD), repeatability.py
  (diagnostica bias vs noise sul marker-finder)
- config.yaml: calibration.method TSAI → DANIILIDIS (sweep su 49 sample H1 sx
  mostra 4× meno residuo di TSAI per via del bias intrinsics-dipendente di
  marker-finder)
- README: dual-robot G1/H1, scripts dir, caveat noti (wrist passthrough,
  marker-finder intrinsics floor, H1 4 DoF, /api/arms/go_neutral non proxato)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Adriano Dal PastroandClaude Opus 4.7 committed 2026-05-08 18:34:59 +02:00
1 parent f6197488f9
commit 4981306062
5 files changed
+790 -16

No files matched your search

+55 -15
View File
@@ -2,21 +2,24 @@
Microservizio Python (FastAPI) che orchestra:
1. **Calibrazione hand-eye** (eye-to-hand) tra la **Nuwa depth camera** (montata in alto,
a sinistra del robot) e la **base del G1**, usando un **ArUco sul polso destro**.
1. **Calibrazione hand-eye** (eye-to-hand) tra la **Nuwa depth camera** (fissa) e la
**base del robot**, usando un **ArUco sul polso**. Supporta **G1** e **H1**.
2. **Riconoscimento oggetto** via YOLO server + point cloud Nuwa.
3. **Pianificazione presa**: asse dell'oggetto (PCA) + posa polso per il G1.
3. **Pianificazione presa**: asse dell'oggetto (PCA) + posa polso per il robot attivo.
## Microservizi usati
| Servizio | URL (default) | Scopo |
|---------------|---------------------------|-------------------------------------|
| Nuwa-HP60C | http://localhost:8877 | RGB, depth, point cloud, intrinsics |
| Marker-finder | http://localhost:8082 | Detection 2D ArUco (corners) |
| YOLO Server | http://localhost:8879 | Bbox oggetto da prendere |
| G1 API Server | http://localhost:8765 | Controllo polso/mano (dry-run se down) |
| Servizio | URL (default) | Scopo |
|-------------------|-----------------------|----------------------------------------------------|
| Nuwa-HP60C | http://localhost:8877 | RGB, depth, point cloud, intrinsics |
| Marker-finder | http://localhost:8082 | Detection 2D ArUco (corners + pose) |
| YOLO Server | http://localhost:8879 | Bbox oggetto da prendere |
| G1 API Server | http://localhost:8765 | Controllo polso/mano G1 (dry-run se down) |
| H1 API Server | http://localhost:8767 | Controllo polso/mano H1 (network host, 4 DoF) |
Il servizio **presa-mano** espone GUI + API su **http://localhost:8890**.
Il servizio **presa-mano** espone GUI + API su **http://localhost:8890**. Il robot attivo
è scelto da `config.yaml > robot.active` (`g1` | `h1`); l'orchestrator fa routing
automatico verso il bridge corrispondente.
## Quick start
@@ -29,13 +32,50 @@ docker compose up -d presa-mano
Tre tab:
- **Calibrazione**: muovi il polso in varie pose, premi *Acquisisci sample* per ognuna,
poi *Risolvi*. Salva `data/calibration.yaml`.
- **Grasp**: rileva oggetto, visualizza bbox + asse, esegui (con toggle dry-run).
- **Calibrazione**: muovi il polso in varie pose, *Acquisisci sample*, poi *Risolvi*.
Salva `data/calibration_<side>.yaml`.
- **Grasp**: rileva oggetto, visualizza bbox + asse, esegui (toggle dry-run).
- **Movimento EE**: lettura pose correnti, invio pose assolute/relative, apri/chiudi mano,
emergency stop.
## Calibrazione automatica via script
In `scripts/`:
| Script | Cosa fa |
|----------------------------|--------------------------------------------------------------------------|
| `explore_and_calibrate.py` | Probe assiale dell'envelope di visibilità tag → workspace JSON + PNG → N sample random nel workspace → solve. |
| `extend_calibration.py` | Estende la calibrazione esistente fino a `n_used >= TARGET_GOOD` (default 30). Riusa il workspace, NON cancella i sample. |
| `repeatability.py` | N detection consecutive a polso fermo per misurare σ del marker-finder (diagnostica bias vs noise). |
Tutti producono file in `data/`: `workspace_<side>.json`, `workspace_<side>.png`,
`samples_<side>.json`, `calibration_<side>.yaml`.
## Configurazione
`config.yaml` contiene i default; l'API espone `GET/PUT /api/config` per override runtime
(es. cambiare ID/size ArUco dalla GUI).
`config.yaml` contiene i default; l'API espone `GET/PUT /api/config` per override
runtime (es. cambiare ID/size ArUco, robot attivo, side di default).
Default rilevanti:
- `calibration.method: DANIILIDIS` — sui dati H1+Nuwa con bias intrinsics di
marker-finder, DANIILIDIS dà ~4× meno residuo di TSAI (default OpenCV).
- `robot.active: h1` / `robot.wrist_side: right`.
## Caveat noti
- **Wrist passthrough**: i campi `speed_mm_s` e `traj_step_mm` non sono nello schema
di `/api/wrist/{absolute,relative}`. Per move "precisi" (closed-loop, slow,
waypoint fitti) bisogna chiamare direttamente il bridge robot, es.
`POST http://localhost:8767/wrist/absolute` su H1.
- **Marker-finder intrinsics**: il sibling service usa intrinsics D435i bakeate che
non corrispondono alla Nuwa → bias sistematico in `T_cam_marker`. È il floor del
residuo hand-eye (~14 mm su H1+Nuwa). Per scendere serve ricalibrare quel servizio.
- **H1 4 DoF**: nessun polso articolato. Si comanda solo posizione; l'orientamento
del polso è output dell'IK e drifta con la posa (fino a ~30° su Y ai bordi
dell'envelope). I solver hand-eye risentono della scarsa diversità rotazionale.
- **`/api/arms/go_neutral`**: il proxy nell'orchestrator non è montato (404). Per
riportare le braccia H1 a home: `POST http://localhost:8767/arms/go_neutral` diretto.
Vedi `CLAUDE.md` per i dettagli di architettura e per le frame conventions
(Nuwa native vs OpenCV vs Nuwa ROI).