100 Commits
Author SHA1 Message Date
Adriano Dal PastroandClaude Opus 4.7 ae8e609b7e docs: aggiorna README.md e CLAUDE.md con tab Braccio DX, Pose 3D, cloud, diagnostics
Allineati alla rimozione del modulo agent e alle nuove funzionalità:
- Tab Braccio DX e Pose 3D documentate in GUI
- Servizi front_camera (D435i) e G1 /diagnostics nella tabella upstream
- Endpoint right_arm/* e pose_3d/* nella lista API
- Convenzioni Pose 3D (graceful offline, clouds, joints mirroring) in CLAUDE.md
- Router list e _deps aggiornati (front_camera(), 12 router modules)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 18:01:28 +02:00
Adriano Dal PastroandClaude Opus 4.7 6c2452fe20 refactor(pose_3d): rimuovi agent/chat, aggiungi cloud+diagnostics+camera polso
Rimosso il modulo agent (LLM chat) e la relativa config OpenRouter.
La tab Pose 3D ora: espone i giunti reali via G1 /diagnostics per
specchiare l'URDF senza IK; acquisisce point cloud Nuwa+D435i
(/api/pose_3d/clouds); mostra il modello 3D della camera sul polso;
degrada gracefully a 200 (wrist=null) quando il robot è offline.
Il vecchio renderer canvas-2D (app.js view3d + diagnostic3d.js) è
stato consolidato nel viewport Three.js di pose_3d.js.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 17:34:42 +02:00
Adriano Dal Pastro 9d30073d57 fix(pose_3d): zero scena al centro robot (pelvi), griglia sotto i piedi a Z=-0.793 2026-05-21 18:06:38 +02:00
Adriano Dal Pastro 38848ad53c feat(pose_3d): IK 2-bone su URDF dopo Apply/Jog/GoPose (polso modello segue il target) 2026-05-21 17:47:12 +02:00
Adriano Dal Pastro 7f60238be9 fix(pose_3d): URDF feet a terra (+0.793m) + sfere polso a zero-pose (Z=0.45) 2026-05-21 17:41:31 +02:00
Adriano Dal Pastro bfd4cc13fb fix(pose_3d): URDFLoader path resolution (rimuovi doppio prefisso /static/vendor/g1/) 2026-05-21 17:37:25 +02:00
Adriano Dal Pastro d5bb9cebd3 feat(pose_3d): workspace check client-side (ghost verde/rosso) + SHOULDER da URDF 2026-05-21 17:21:09 +02:00
Adriano Dal Pastro 8c09d79505 feat(pose_3d): modello reale G1 (URDF + STL meshes) al posto della silhouette finta
Sostituisce torso/head/hips/gambe/spalle primitive in tab Pose 3D con il
modello URDF G1 (g1_body29_hand14), caricato via urdf-loader 0.12.6.

Vendor:
- web/vendor/g1/g1.urdf + 64 mesh STL (~52 MB, copiati da
  G1_API_Server/assets/g1/)
- web/vendor/three/addons/loaders/URDFLoader.js (npm urdf-loader@0.12.6),
  import path adattato a 'three/addons/loaders/STLLoader.js' (importmap
  del sito) e ColladaLoader stubbato (G1 URDF è solo STL)
- web/vendor/three/addons/loaders/URDFClasses.js (companion del loader)

pose_3d.js:
- Aggiunge loadG1Urdf(scene) async che configura loader.loadMeshCb per
  servire le STL dal mount /static/vendor/g1/meshes/
- Best-effort: in caso di errore di parsing/fetch il body non viene
  aggiunto ma la tab continua a funzionare (polsi, UCS, gizmo)
2026-05-21 17:14:16 +02:00
Adriano Dal Pastro 18dce0d951 feat(pose_3d): bottone Sincronizza con robot (refetch state + reset target) 2026-05-21 17:08:09 +02:00
Adriano Dal Pastro b852976a4a feat(pose_3d): readout XYZ/RPY editabili (input number, drive il ghost) 2026-05-21 17:01:03 +02:00
Adriano Dal Pastro 8b722ca729 feat(pose_3d): silhouette robot completa (testa+gambe+spalle) + FRONT come marker terra 2026-05-21 16:46:44 +02:00
Adriano Dal Pastro d4cd82551e fix(pose_3d): ghost fallback alla posa dell'arm quando /state e' offline 2026-05-21 16:44:57 +02:00
Adriano Dal Pastro fd506dff9b feat(pose_3d): etichette DX/SX sulle sfere e FRONT al base 2026-05-21 16:41:08 +02:00
Adriano Dal Pastro 25c94d3861 fix(pose_3d): gizmo visibility (use getHelper for r160) + larger wrist hitbox + diagnostics 2026-05-21 16:36:09 +02:00
Adriano Dal Pastro 0a3ee61007 chore: ignore tmp/ (scratch directory) 2026-05-21 16:15:48 +02:00
Adriano Dal Pastro 71baf829e6 feat(pose_3d): bottone Sblocca braccia 2026-05-21 16:06:43 +02:00
Adriano Dal Pastro bb6796bfe3 feat(pose_3d): save/load/delete named poses 2026-05-21 16:03:38 +02:00
Adriano Dal Pastro a81fc9acf9 feat(pose_3d): Jog mode auto-apply + safety + Precise toggle 2026-05-21 16:01:56 +02:00
Adriano Dal Pastro 5b2239e307 feat(pose_3d): Editor mode Apply + Cancel 2026-05-21 16:00:15 +02:00
Adriano Dal Pastro 64500944d6 feat(pose_3d): selezione polso + gizmo translate/rotate sul ghost 2026-05-21 15:58:41 +02:00
Adriano Dal Pastro 7a561cfa67 feat(pose_3d): polling /state + readout sidebar 2026-05-21 15:56:34 +02:00
Adriano Dal Pastro f161894d53 feat(pose_3d): scene Three.js base (torso, polsi, UCS, grid) 2026-05-21 15:54:29 +02:00
Adriano Dal Pastro c4124a2983 feat(pose_3d): markup HTML + CSS della tab 2026-05-21 15:50:49 +02:00
Adriano Dal Pastro 433edc0974 chore(web): vendor TransformControls (per tab Pose 3D) 2026-05-21 15:48:01 +02:00
Adriano Dal Pastro 0ab0e5691c feat(pose_3d): POST /unlock proxy + non-regression check 2026-05-21 15:46:24 +02:00
Adriano Dal PastroandClaude Opus 4.7 feaab2aae7 docs(pose_3d): implementation plan
Plan dettagliato per la tab "Pose 3D" (writing-plans skill),
basato sullo spec del 2026-05-21. 15 task suddivisi in backend
(routes + tests TDD) e frontend (Three.js viewport + gizmo +
mode toggle Editor/Jog).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 15:44:55 +02:00
Adriano Dal PastroandClaude Opus 4.7 57954b5c8d feat(right_arm): perm assi cam->polso, precise=true default, verify_tag UI
Lavoro accumulato nella sessione 2026-05-21 prima del brainstorming
della tab Pose 3D:

- compute_delta_wrist generalizzato con cam_to_wrist_perm: la mappa
  cam->polso non e' solo sign-flip ma una permutazione (default
  identita' per backward compat). DeltaOversize ora espone X/Y/Z
  nella stringa d'errore. Test aggiornati.

- G1Client.wrist_absolute / wrist_relative: precise=True di default
  (era False). Stessa cosa per wrist_routes.AbsoluteReq Pydantic
  e per agent.tools move_wrist_*. Movimenti reali ora chiedono
  controllo accurato salvo override esplicito.

- Tab Braccio DX:
  - /verify_tag endpoint: snapshot wrist FK + tag id=1 dalla front
    camera. Per verifica relativa moveto vs marker (no calibrazione).
  - GUI: pannello "Verifica tag id=1" + campi camera_offset_wrist_mm.
  - markUserTouchedOnInput esteso a raOff/raSgn/raCamOff.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 15:44:48 +02:00
Adriano Dal PastroandClaude Opus 4.7 8d40ebaf89 feat(pose_3d): POST /poses/{name}/go
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 15:43:50 +02:00
Adriano Dal Pastro d124a7c896 refactor(config): add set_config_value for non-merge replacement 2026-05-21 15:42:14 +02:00
Adriano Dal PastroandClaude Opus 4.7 fb05409403 feat(pose_3d): named poses GET/PUT/DELETE
Adds CRUD for named wrist poses persisted in config.yaml under
pose_3d.named_poses. PUT validates the name against ^[A-Za-z0-9_-]{1,40}$
and normalizes the quaternion. DELETE returns 404 if the pose is missing.

Bypasses update_config's deep-merge for wholesale named_poses replacement
(deep-merge cannot remove nested keys) via a small helper that mutates
the in-memory singleton then persists with an empty patch.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 15:39:37 +02:00
Adriano Dal Pastro df949c6989 refactor(pose_3d): move normalize_quaternion to geometry module 2026-05-21 15:37:14 +02:00
Adriano Dal Pastro 40c3fff755 feat(pose_3d): POST /apply + quaternion normalization 2026-05-21 15:33:47 +02:00
Adriano Dal Pastro 71f2ef596e feat(pose_3d): router skeleton + GET /state 2026-05-21 15:27:43 +02:00
Adriano Dal PastroandClaude Opus 4.7 19fba42876 docs: spec design tab "Pose 3D" (editor visuale + jog dei polsi)
Specifica per nuova tab GUI con viewport Three.js, gizmo
translate/rotate sui polsi DX e SX, modalita' Editor (preview) /
Jog (auto-move al mouseup), safety guard sui movimenti grandi,
checkbox precise toggle, save/load named poses in config.yaml.

Brainstorming nella sessione 2026-05-21.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 15:14:46 +02:00
Adriano Dal PastroandClaude Opus 4.7 360755144c chore(config): valori iniziali per camera_offset_wrist_mm e cluster window
Tuning da prima sessione live: move_offset_camera_mm.x=100 (lateral
verso il pestello), camera_offset_wrist_mm.z=100 (mounting verticale
della Nuwa sopra il TCP destro), cluster_depth_window_m=0.20.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 12:18:29 +02:00
Adriano Dal PastroandClaude Opus 4.7 1fa7d12ad7 feat(right_arm): force, camera↔polso offset, cluster filter sul centroide
Tre miglioramenti al move-toward dopo il primo uso live:

1. checkbox "force" accanto a "Muovi": bypassa max_step_m quando
   l'utente sa che il delta richiesto e' grande ma corretto (es. primo
   avvicinamento all'oggetto).

2. camera_offset_wrist_mm: il modello assumeva camera e TCP coincidenti
   (sole sign flips). La camera Nuwa e' invece montata con traslazione
   costante rispetto al polso. La formula diventa:
       delta_wrist = sign * (centroid_cam - offset_cam) + t_wrist_cam
   Esposto in config (default 0,0,0), GUI (3 input "Camera rispetto a
   polso (mm)") e in /state. Il termine compensa il fatto che muovere
   il polso porta la camera, non il TCP, sul punto di presa.

3. filter_nearest_cluster: il centroide era media di tutti i punti
   SAM21 della mask. In presenza di sfondo lontano visibile attraverso
   buchi della depth del primo piano la media veniva trascinata a
   metri di distanza. Ora si tiene il cluster piu' vicino:
       z_near = p5(Z)
       keep   = punti con Z <= z_near + cluster_depth_window_m
   Default window 0.20 m, configurabile. La risposta di /detect/wrist
   espone n_sam21_points, n_centroid_points e z_near/z_cutoff per
   diagnosi.

Aggiornata anche la persistenza: /offset accetta camera_offset_wrist_mm.
GUI: i campi Offset/Sign/CamOff rispettano "user touched" (refresh non
li cancella mentre l'utente digita).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 12:18:24 +02:00
Adriano Dal PastroandClaude Opus 4.7 fcd921ff32 chore(config): seleziona G1 right come robot attivo
YAML riformattato (block style) dal side-effect di update_config —
contenuto invariato a parte robot.{active,wrist_side}.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 11:43:14 +02:00
Adriano Dal PastroandClaude Opus 4.7 2f6444c0a5 fix(right_arm): bbox dict, image_size da /api/status, tab non seleziona robot
Tre problemi della tab Braccio DX dopo il primo rodaggio:

1. /detect/front e /detect/wrist ritornavano bbox raw dal YOLO server,
   che lo manda come lista [x1,y1,x2,y2]; la GUI legge bbox.x1 e mostra
   NaN. Ora il router normalizza il payload via perception/detector
   ._normalize, allineandosi al resto del codice. Aggiunta regressione
   con payload reale del server.

2. La tab gateava su robot.active==g1 && wrist_side==right con banner
   "Attiva G1 right" e POST /activate. Confonde: la selezione del
   robot e' globale e non si flippa per-feature. Rimossi banner,
   bottone, endpoint /activate e _guard_g1_right(); gli endpoint
   operano sul polso destro del robot attivo qualunque esso sia.

3. image_size: [0,0] perche' Nuwa /api/intrinsics non include
   width/height; vivono in /api/status > data.resolution. Aggiunto
   NuwaClient.image_size() e usato in detect_front. Aggiornato
   docstring di intrinsics() per coerenza con il payload reale.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 11:43:05 +02:00
Adriano Dal PastroandClaude Opus 4.7 3284cd0424 feat(home): aggiungi 'Camera fronte robot' a Stato dispositivi
Ping anche services.front_camera in /api/home/status. Etichetta nuwa
rinominata in 'Nuwa-HP60C (camera polso)' per chiarezza ora che ci sono
due camere distinte.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 16:04:56 +02:00
Adriano Dal PastroandClaude Opus 4.7 848cd962c4 fix(gui): conferma esplicita su Muovi quando dry-run off
Coerente con le conferme di Home e Custom: gesto fisico richiede consenso.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 12:47:34 +02:00
Adriano Dal Pastro 8297abb61d feat(gui): right_arm.js — auto-refresh, detect, move, home, custom 2026-05-20 12:43:55 +02:00
Adriano Dal PastroandClaude Opus 4.7 03ecbbae4e fix(gui): allinea CSS tab Braccio DX al tema dark esistente
- Sostituisce colori hardcoded con CSS variables (--bg/--panel/--border/--dim/--warn/--ok/--danger)
- Scope .dim a #tab-right-arm per non alterare altre tab che usano la classe
- Aggiunge white-space pre-wrap a .ra-result per testi multi-riga

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 12:40:55 +02:00
Adriano Dal Pastro 2f8c7006ba feat(gui): markup + CSS tab Braccio DX 2026-05-20 12:38:01 +02:00
Adriano Dal Pastro 59f7f66d77 feat(right_arm): /home, /custom_pose, PUT /custom_pose, PUT /offset + fixture conftest 2026-05-20 12:33:03 +02:00
Adriano Dal Pastro afbfd55bca feat(right_arm): /move/toward con sign flips, max-step e z-floor 2026-05-20 12:27:38 +02:00
Adriano Dal Pastro bd4eb8b929 feat(right_arm): /detect/wrist con YOLO + SAM21 + centroide camera 2026-05-20 12:23:10 +02:00
Adriano Dal Pastro 3e4e8055db feat(right_arm): /detect/front con proxy fallback per YOLO 2026-05-20 12:20:02 +02:00
Adriano Dal Pastro 22e13435b1 feat(right_arm): endpoint /snapshot/{front,wrist} 2026-05-20 12:16:33 +02:00
Adriano Dal PastroandClaude Opus 4.7 dd2053cc47 feat(right_arm): router skeleton con /state e /activate
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 12:13:33 +02:00
Adriano Dal Pastro 55e84778d8 feat(right_arm): math puro per delta-toward (sign flips + z-floor) 2026-05-20 12:09:35 +02:00
Adriano Dal Pastro 757eb01200 feat(deps): aggiungi front_camera() e tab_right_arm_cfg() 2026-05-20 12:07:11 +02:00
Adriano Dal Pastro 04cc5fc345 feat(geometry): aggiungi conversioni RPY (deg) ↔ quaternion xyzw 2026-05-20 12:04:39 +02:00
Adriano Dal Pastro 64742479b1 feat(config): aggiungi services.front_camera e blocco tab_right_arm 2026-05-20 12:01:14 +02:00
Adriano Dal PastroandClaude Opus 4.7 779f506701 docs(plan): implementation plan tab Braccio DX
13 task TDD per il nuovo tab: config, geometry, math puro, 6 endpoint
router /api/right_arm/*, markup HTML + CSS, JS module. Spec:
docs/superpowers/specs/2026-05-20-right-arm-tab-design.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 11:33:06 +02:00
Adriano Dal PastroandClaude Opus 4.7 53c0e03219 docs(spec): design tab Braccio DX (G1 right, front + wrist Nuwa)
Design del nuovo tab "Braccio DX": fronte (depth cam fissa sul robot)
+ polso (Nuwa eye-in-hand) + controlli move/home/custom-pose. Router
/api/right_arm/*, JS dedicato, persistenza in config tab_right_arm.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 11:04:08 +02:00
Adriano Dal PastroandClaude Opus 4.7 491d1b60aa revert(find_model): drop plane filter — pass full SAM21 cluster to Open3DModel
The pre-SAM21 depth filter and post-SAM21 partition_by_plane were
fighting each other and drowning the actual object cluster. Per
operator request, send Open3DModel the raw SAM21 cluster and let
RANSAC handle outliers itself. The accepted/excluded/SAM21 overlays
in the GUI continue to work; excluded is now always empty and
accepted == SAM21 cluster.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 11:59:15 +02:00
Adriano Dal PastroandClaude Opus 4.7 b0a2d7141d feat(find_model gui): toggle to overlay work plane as a violet polygon
The find_model response now returns plane_polygon_px (4 corners of a
30 cm square anchored at the work plane centroid, projected to RGB
pixels via the same K used for the SAM21 cloud). The GUI gains a
'Piano (viola)' checkbox that draws the polygon as a translucent
violet quad with an outline, helping the operator see whether the
plane sits where expected relative to the object.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 11:53:16 +02:00
Adriano Dal PastroandClaude Opus 4.7 f1f9d8f638 feat(find_model): zero below-plane depth before SAM21 segmentation
Previously SAM21 ran on the raw aligned depth and frequently leaked the
mask onto the table around the object: ~88% of segmented points (2136
of 2440 in a sample run) were table pixels filtered away by the post
partition_by_plane step. Open3DModel got a noisy cluster mostly off
the object.

New pipeline: with a calibrated work plane, depth pixels whose 3D
back-projection sits below the plane are zeroed BEFORE SAM21 sees the
depth PNG. SAM21 cannot back-project zero-depth pixels, so only true
above-plane points end up in the cloud regardless of mask outline.

Same sample run after the change: 513 SAM21 -> 513 accepted, 0 excluded.

The post-partition still runs (now a no-op on a calibrated plane), so
the find_model response shape is unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 11:50:01 +02:00
Adriano Dal PastroandClaude Opus 4.7 2fe7a7a7fa feat(find_model gui): toggle to overlay full SAM21 cluster (yellow)
Adds a 4th checkbox 'Punti SAM21 (gialli)' that draws the full SAM21
segmentation (input to both the plane partition and Open3DModel) on
the RGB result canvas. The backend now returns sam21_points_px and
n_sam21 alongside the existing accepted/excluded splits.

Useful as a sanity check: visualise what was actually segmented vs
what the plane filter kept/rejected vs where the STL got placed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 11:40:24 +02:00
Adriano Dal PastroandClaude Opus 4.7 767d91acdc feat(work_plane gui): show fit inliers as blue scatter in 3D, drop wrong plane mesh
The 0.4x0.4 PlaneGeometry square was a fixed-size proxy that did not
reflect the actual ROI extent — visually misleading. Replace it with
an explicit blue point cloud of the inliers fed to fit_plane_svd, so
the user can see *exactly* which depth pixels the plane was fit on.

- Backend: fit response now returns fit_points_camera (CV frame) instead
  of the (parallax-shifted) RGB pixel projection.
- Frontend: drop the purple plane mesh; new three.setFitInliers paints
  the inliers in blue. The RGB overlay no longer carries blue dots.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 11:20:03 +02:00
Adriano Dal PastroandClaude Opus 4.7 4a83305b5e fix(work_plane): project fit inliers from CV-frame pts_cv (not raw pc)
NuwaClient.pointcloud_roi's docstring claims OpenCV frame, but in
practice the raw payload arrives in Nuwa native frame (Z<0 forward).
nuwa_to_cv_frame is what actually flips it. Using `pts_cv` (post-flip
+ post-outlier-mask) makes the projection drop none of the inliers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 11:13:20 +02:00
Adriano Dal PastroandClaude Opus 4.7 ae510e4387 feat(work_plane gui): overlay inliers used for fit as blue dots on RGB
The fit endpoint now returns fit_points_px (the post-outlier-filter
inliers projected to RGB pixels via Nuwa's RGB intrinsics). The GUI
draws them on the same overlay as the ROI rectangle so the user can
visually verify which depth pixels were fed to fit_plane_svd.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 11:10:25 +02:00
Adriano Dal PastroandClaude Opus 4.7 76e0739620 fix(work_plane): allow negative offset_mm + readable validation errors
- Drop the ge=0 constraint on FitReq.offset_mm (negative values are a
  documented usage: aggressive noise cull above the plane).
- HTML input min lowered to -200 to match.
- Render FastAPI 422 validation arrays as a human-readable string in the
  status chip (was showing "[object Object]").

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 11:03:36 +02:00
Adriano Dal PastroandClaude Opus 4.7 92506d62c6 fix(work_plane gui): preserve ROI overlay across RGB live-refresh
Setting canvas.width/height clears its bitmap; the live RGB tick was
firing the img.load handler every second, wiping the ROI rectangle and
breaking the two-click flow (third click was interpreted as restart).

- Only mutate canvas size when image resolution actually changes.
- Re-paint the overlay after each load so the ROI persists.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 10:58:41 +02:00
Adriano Dal PastroandClaude Opus 4.7 1bdf407072 chore(config): set wrist_side=left to match calibrated H1 arm
Right side has no calibration in data/calibration_right.yaml;
the H1 left arm is the one with samples + solved hand-eye.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 10:17:48 +02:00
Adriano Dal PastroandClaude Opus 4.7 cb940dc1cd fix(open3dmodel): unwrap {success,data,error} envelope from /api/recipes
Open3DModel returns the same envelope for /api/recipes as for /api/pose;
the bare-list code path stays as a fallback for older mocks.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 10:17:48 +02:00
Adriano Dal PastroandClaude Opus 4.7 33d66019ee feat(web): Cerca modello — model picker + find_model overlay handlers
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 10:12:46 +02:00
Adriano Dal PastroandClaude Opus 4.7 af8d4d6fc4 feat(web): rebuild Cerca modello tab — model picker + result canvas
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 10:10:35 +02:00
Adriano Dal PastroandClaude Opus 4.7 3857ef533a feat(api): POST /api/grasp/find_model with pose-fit + overlay projection
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 10:09:47 +02:00
Adriano Dal PastroandClaude Opus 4.7 5d9166ed77 feat(api): GET /api/models/recipes proxy to Open3DModel
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 10:08:11 +02:00
Adriano Dal PastroandClaude Opus 4.7 430e342c48 feat(api): _deps factories for Open3DModel client + recipe cache
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 10:07:18 +02:00
Adriano Dal PastroandClaude Opus 4.7 87abe26476 refactor(sam21_bridge): extract segment_with_sam21 (no plane filter)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 10:06:41 +02:00
Adriano Dal PastroandClaude Opus 4.7 684bd2de5e feat(clients): LRU mesh cache for Open3DModel recipes (etag-validated)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 10:05:05 +02:00
Adriano Dal PastroandClaude Opus 4.7 16ffe6ac20 feat(clients): Open3DModel client (list_recipes, estimate_pose, get_stl_bytes)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 10:03:41 +02:00
Adriano Dal PastroandClaude Opus 4.7 b85f4b9a48 feat(perception): project camera-frame 3D points to image pixels
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 10:02:20 +02:00
Adriano Dal PastroandClaude Opus 4.7 d1b27433d5 feat(perception): parse STL + uniform surface sampling
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 10:01:25 +02:00
Adriano Dal PastroandClaude Opus 4.7 876224a71d feat(perception): partition_by_plane returns accepted + excluded sets
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 10:00:09 +02:00
Adriano Dal PastroandClaude Opus 4.7 9ae3e00f65 build: add numpy-stl + Open3DModel config block for find_model
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 09:57:52 +02:00
Adriano Dal PastroandClaude Opus 4.7 edbd5b5136 docs: implementation plan for Cerca modello 3D pose-fit overlay
13 bite-sized TDD tasks covering: numpy-stl dep + config, partition_by_plane,
stl_sampler, projection, Open3DModel client + LRU mesh cache, sam21_bridge
refactor, _deps factories, GET /api/models/recipes proxy, POST
/api/grasp/find_model handler, GUI rebuild, manual integration smoke test.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 18:42:33 +02:00
Adriano Dal PastroandClaude Opus 4.7 ba5be511d2 docs: design spec for Cerca modello 3D pose-fit overlay
Brainstorming → approved spec for the GUI/backend redesign of tab "Cerca
modello": YOLO+SAM21 cluster feeds Open3DModel /api/pose, presa-mano
samples the recipe STL, projects onto a snapshot RGB with togglable
overlays for accepted/excluded points and the fitted model points.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 18:35:53 +02:00
Adriano Dal PastroandClaude Opus 4.7 8f7b52cc20 docs: update README for SAM21 + work-plane features
- Add SAM21 (NuwaSeg :8002) to the upstream services table.
- New "Calibrazione Piano" tab documented: 2-click ROI, fit preview, 3D
  camera-POV viewer with red = excluded points, offset_mm semantics
  (positive = permissive buffer below, negative = aggressive cut above for
  depth noise), save persists to data/work_plane.json.
- "TrovaUtensile" tab renamed to "Cerca modello".
- New section "Pipeline cloud-from-bbox" describing the SAM21-first flow
  with bbox fallback and the work-plane filter, plus the response meta
  fields (source, plane_applied, n_points_before_plane,
  sam21_fallback_reason).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:54:30 +02:00
Adriano Dal PastroandClaude Opus 4.7 f75b9626be fix(work_plane): /fit returns full-scene cloud, not just ROI
The 3D viewer was only seeing points inside the ROI rectangle used for
the plane fit. Now /fit also fetches nuwa.pointcloud (step=4, full frame),
flips to CV frame, and returns it as points_camera (downsampled to
max_preview_points). The user sees the entire scene with red = excluded
by the below-plane filter, cyan = kept.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:45:54 +02:00
Adriano Dal PastroandClaude Opus 4.7 56f8888217 fix(gui): work_plane 3D view = camera POV + red = excluded points
- Camera at origin (CV frame) looking at +Z with screen-up = CV −Y, so
  the rendered scene matches the camera's vantage point. OrbitControls
  retargets to the plane centroid on fit so rotation feels natural.
- Simplify scatter coloring to two tones: red for filter-excluded points
  (signed_distance < −offset_mm/1000), cyan-white for everything kept.
  Matches the backend filter contract exactly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:41:03 +02:00
Adriano Dal PastroandClaude Opus 4.7 652fa4b912 fix(gui): two-click ROI on Calibrazione Piano (was shift+drag)
User asked for "2 punti" — replace the drag-to-rectangle interaction with
two discrete clicks: first click places corner A (cross marker), second
click defines the rectangle, third click starts a new selection.
Rectangles smaller than 10×10 px are rejected. Status chip guides the
flow.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:38:43 +02:00
Adriano Dal PastroandClaude Opus 4.7 b4db712cd0 fix(gui): work_plane RGB feed via same-origin proxy
Direct fetch to http://localhost:8877/api/rgb fails from the browser due
to CORS (page is served from :8890). Switch to /api/calibration/rgb.jpg
which presa-mano already proxies same-origin.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:36:56 +02:00
Adriano Dal Pastro 6f1649b384 Merge feat/work-plane-filter: work-plane calibration + below-plane filter
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.
2026-05-11 17:27:15 +02:00
Adriano Dal PastroandClaude Opus 4.7 57bd252375 fix(gui+api): cleanup before merge
- Rename "TrovaUtensile" tab → "Cerca modello".
- Remove the "Precisione (ultime 5 detection)" stats panel and the
  "Dettagli" JSON dump from the grasp tab; keep hidden stubs so the
  existing app.js continuous-loop code doesn't null-deref.
- Add work_plane_routes to api/__init__.py imports + __all__ (consistency
  with the other routers).
- Trim the misleading "drag = pan · wheel = zoom · doppio click = reset"
  hint from the Calibrazione Piano RGB label — pan/zoom isn't wired.
- Disable wpClearBtn initially so it doesn't flash clickable before
  fetchSaved() resolves.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:23:29 +02:00
Adriano Dal PastroandClaude Opus 4.7 ae84739c64 feat(gui): Calibrazione Piano tab (ROI + fit preview + 3D viewer)
New tab replaces the removed Servo Visuale. Shift+drag on the RGB image
defines a rectangle, 'Calcola piano' calls POST /api/work_plane/fit and
renders the plane + a colored scatter in 3D. Adjusting the offset slider
re-colors the scatter client-side. 'Salva piano' persists; 'Rimuovi piano
salvato' clears.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:08:32 +02:00
Adriano Dal PastroandClaude Opus 4.7 eb53f30e23 refactor: remove visual-servo feature
The marker-relative servo (endpoints /api/grasp/visual_servo/{plan,step,
plane/*}, helpers in grasp_routes.py, the bulk of grasp/visual_servo.py,
web/servo.js, and the Servo Visuale GUI tab) is gone. Plane fitting now
lives in /api/work_plane/* and perception/work_plane.py; Task 5 wires the
new Calibrazione Piano tab.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:04:00 +02:00
Adriano Dal PastroandClaude Opus 4.7 565c3df2f4 feat(api): /api/work_plane/{fit,save,get,delete} endpoints
POST /fit returns a candidate WorkPlane + a downsampled CV-frame cloud
preview, without writing to disk. POST /save persists the plane. GET
returns the current saved plane (or null). DELETE clears it.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 17:00:24 +02:00
Adriano Dal PastroandClaude Opus 4.7 2478e9201c fix(grasp): sync visual-servo plane writes into perception singleton
Until Task 4 removes the duplicate WorkPlane code in grasp/visual_servo.py,
the visual-servo plane endpoints must also update perception.work_plane's
singleton so the below-plane filter (which reads from the perception side)
sees the newly-calibrated plane within the same process lifetime.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 16:59:01 +02:00
Adriano Dal PastroandClaude Opus 4.7 3b0a65554a feat: apply work-plane filter at all three cloud sites
points_via_sam21, _points_via_bbox, and _object_cloud_cv (bbox branch)
now call apply_below_plane_filter on the CV-frame cloud before the
<10-points guard. Responses carry plane_applied + n_points_before_plane.
Without a saved plane the filter is a no-op (plane_applied=false).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 16:52:17 +02:00
Adriano Dal PastroandClaude Opus 4.7 28ba0dd9f2 test(work_plane): drop unused imports
tempfile, Path, and unittest.mock.patch were imported but unused.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 16:50:05 +02:00
Adriano Dal PastroandClaude Opus 4.7 16e32bf1c1 feat(perception): work_plane module with below-plane filter
Owns WorkPlane (with new offset_mm field), fit_plane_svd, disk-backed
get/set, and the apply_below_plane_filter helper. WorkPlane.normal lives
in OpenCV RGB-camera frame and is oriented toward the camera. The filter
keeps points where signed_distance >= -offset_mm/1000.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 16:41:35 +02:00
Adriano Dal PastroandClaude Opus 4.7 2338ee7ea2 docs: implementation plan for work-plane filter
6 task TDD-first: perception/work_plane.py + 8 unit tests, filter wiring
ai 3 call sites con plane_applied/n_points_before_plane nelle response,
nuovi endpoint /api/work_plane/{fit,save,get,delete}, rimozione totale
del visual-servo (backend + GUI), nuova tab Calibrazione Piano con
work_plane.js (ROI + fit preview + 3D viewer con scatter colorato +
offset live-recolor), verifica live end-to-end.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 16:34:12 +02:00
Adriano Dal PastroandClaude Opus 4.7 f7661a782a docs: design work-plane calibration + below-plane filter
Repurpose the "Servo Visuale" tab into "Calibrazione Piano". Reuses the
existing WorkPlane + fit_plane_svd infrastructure (moved out of
grasp/visual_servo.py into perception/work_plane.py), extends WorkPlane
with offset_mm, splits fit (preview) from save (commit), and applies a
below-plane + offset filter to every object cloud (sam21_bridge,
_points_via_bbox, _object_cloud_cv bbox branch). Visual-servo feature
removed entirely; the only survivors are the plane bits.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 16:27:39 +02:00
Adriano Dal PastroandClaude Opus 4.7 3b96589bf8 feat(perception): extend SAM21 to /scan and /object_points
Extract the SAM21 wiring out of grasp_routes.py into a shared module
perception/sam21_bridge.py (Sam21Fallback + points_via_sam21). Both
/api/perception/scan and /api/perception/object_points now try SAM21
first and fall back to the bbox ROI path on any Sam21Fallback. Response
now carries 'source' (sam21 | bbox_roi) and optional 'sam21_fallback_reason'.

Side-effect: 'points_camera' on both endpoints is now in OpenCV
RGB-camera frame (same as 'points_base' minus the T_base_camera
transform), regardless of which path produced the cloud. Previously the
bbox path stored points in Nuwa-native frame here. The web GUI plots
points_base when available, so the scatter views automatically pick up
the SAM21-segmented cloud.

Verified live: /scan → source=sam21 n=2414 sam21=111ms;
/object_points → source=sam21 n=2347 sam21=118ms;
/grasp/plan regression → source=sam21 n=2390 sam21=119ms;
/scan with SAM21 down → source=bbox_roi fallback='unreachable: ...'

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 16:06:00 +02:00
Adriano Dal PastroandClaude Opus 4.7 ba0259aa90 feat(gui): surface SAM21 source + n_points in TrovaUtensile status bar
Status line on "Pianifica grasp" now shows source=sam21 / source=bbox_roi
(with fallback reason if any) plus n_points, so SAM21 vs fallback path is
visible at a glance without opening DevTools.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 15:52:04 +02:00
Adriano Dal Pastro 002d462da4 Merge feat/sam21-segmentation: SAM21 segmentation in grasp pipeline
12 commits — spec, plan, implementation, fixes, live integration.

- New: Sam21Client (clients/sam21.py), align_depth_to_rgb
  (perception/depth_align.py), _points_via_sam21 helper in
  grasp_routes.py, services.sam21 + grasp.use_sam21 config keys, pytest
  scaffold + 11 unit tests.
- _object_points_in_base: try SAM21 first (default on), fall back to the
  legacy bbox path on any non-fatal failure. Nuwa failures during prep
  raise 502 immediately. Single-log discipline.
- Verified live: source=sam21 with ~2200 segmented points at 128 ms GPU
  inference; SAM21 down → automatic bbox_roi fallback; class filter +
  recovery on restart all work.
2026-05-11 15:50:01 +02:00
Adriano Dal PastroandClaude Opus 4.7 7624327487 docs: update CLAUDE.md for SAM21 + fix httpx import order
- Note that tests now exist and run with uv run pytest.
- Add SAM21 to the upstream services table.
- Add sam21() to the _deps factory list.
- Add a convention bullet about the SAM21 vs bbox frame asymmetry so
  future contributors don't add nuwa_to_cv_frame to the SAM21 branch.
- Move 'import httpx' into the third-party imports block.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 15:49:11 +02:00