6f1649b384e815b4d2ebe7d97426e6b9fac149e1
8 commits — perception/work_plane module, filter wiring on 3 sites,
/api/work_plane/* endpoints, visual-servo removal, Calibrazione Piano tab,
GUI cleanup (Cerca modello + Precisione/Dettagli removed).
- New: perception/work_plane.py owns WorkPlane (+offset_mm), fit_plane_svd,
disk persistence, apply_below_plane_filter. 8 unit tests.
- Filter applied at all three cloud sites (sam21_bridge, _points_via_bbox,
_object_cloud_cv bbox branch). Responses carry plane_applied +
n_points_before_plane on /scan, /object_points, /grasp/{plan,execute}.
- Endpoints: POST /api/work_plane/fit (preview, no save), /save, GET,
DELETE. Two-stage fit/save UX.
- Visual-servo feature removed entirely (~1500 lines: endpoints, helpers,
visual_servo.py, servo.js, tab GUI).
- New tab "Calibrazione Piano": shift+drag ROI on RGB, fit preview, 3D
viewer with colored scatter (green/yellow/red/grey by signed distance),
offset slider re-colors client-side, save/clear.
- GUI cleanup: "TrovaUtensile" renamed "Cerca modello"; removed
"Precisione (ultime 5 detection)" stats panel and "Dettagli" JSON dump.
- Verified live: baseline (no plane) → plane_applied:false everywhere;
with saved plane → plane_applied:true on all 3 endpoints + JSON file on
disk; DELETE → file gone + plane_applied:false. Zero ERROR logs.
presa-mano
Microservizio Python (FastAPI) che orchestra:
- 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.
- Riconoscimento oggetto via YOLO server + point cloud Nuwa.
- 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
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_<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, 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_setraj_step_mmnon 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/absolutesu 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_neutraldiretto.
Vedi CLAUDE.md per i dettagli di architettura e per le frame conventions
(Nuwa native vs OpenCV vs Nuwa ROI).
Languages
Python
62.6%
JavaScript
27%
HTML
5.1%
CSS
4.8%
Shell
0.3%
Other
0.2%