Commit Graph
106 Commits
Author SHA1 Message Date
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