# presa-mano Microservizio Python (FastAPI) che orchestra: 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 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 + 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 robot attivo è scelto da `config.yaml > robot.active` (`g1` | `h1`); l'orchestrator fa routing automatico verso il bridge corrispondente. ## Quick start ```bash docker compose up -d presa-mano # Apri http://localhost:8890 ``` ## GUI Tre tab: - **Calibrazione**: muovi il polso in varie pose, *Acquisisci sample*, poi *Risolvi*. Salva `data/calibration_.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_.json`, `workspace_.png`, `samples_.json`, `calibration_.yaml`. ## Configurazione `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).