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>
This commit is contained in:
Adriano Dal PastroandClaude Opus 4.7 committed 2026-05-21 15:44:48 +02:00
1 parent 8d40ebaf89
commit 57954b5c8d
8 files changed
+238 -23

No files matched your search

+56
View File
@@ -211,6 +211,60 @@ function readPoseFields(prefix) {
};
}
// ---------------- Verifica tag (relativa) ----------------
let verifySnapshots = [];
function norm3(a) { return Math.sqrt(a[0]*a[0] + a[1]*a[1] + a[2]*a[2]); }
function sub3(a, b) { return [a[0]-b[0], a[1]-b[1], a[2]-b[2]]; }
function renderVerifyTable() {
const n = verifySnapshots.length;
$('raVerifyCount').textContent = `${n} snapshot`;
if (n === 0) {
$('raVerifyResult').textContent = '— nessuno snapshot';
$('raVerifyResult').classList.add('dim');
return;
}
$('raVerifyResult').classList.remove('dim');
let out = '';
for (let i = 0; i < n; i++) {
const s = verifySnapshots[i];
out += `#${i+1} wrist=(${s.wrist_position_m.map(v=>(v*1000).toFixed(0)).join(',')})mm ` +
`tag=(${s.tag_position_m_in_front_cam.map(v=>(v*1000).toFixed(0)).join(',')})mm\n`;
}
if (n >= 2) {
out += '\nConfronti consecutivi (Δ in mm):\n';
for (let i = 1; i < n; i++) {
const dw = sub3(verifySnapshots[i].wrist_position_m,
verifySnapshots[i-1].wrist_position_m);
const dt = sub3(verifySnapshots[i].tag_position_m_in_front_cam,
verifySnapshots[i-1].tag_position_m_in_front_cam);
const nw = norm3(dw) * 1000, nt = norm3(dt) * 1000;
const err = Math.abs(nw - nt);
const pct = nw > 0 ? (err / nw * 100) : 0;
out += ` #${i}→#${i+1} ‖Δpolso‖=${nw.toFixed(1)} ‖Δtag‖=${nt.toFixed(1)} ` +
`err=${err.toFixed(1)} (${pct.toFixed(1)}%)\n`;
}
}
$('raVerifyResult').textContent = out;
}
async function onVerifySnap() {
try {
const res = await jsonFetch('/api/right_arm/verify_tag', { method: 'POST' });
verifySnapshots.push(res);
renderVerifyTable();
} catch (e) {
alert(`Verifica fallita: ${e.message}`);
}
}
function onVerifyReset() {
verifySnapshots = [];
renderVerifyTable();
}
// ---------------- Offset save ----------------
async function onSaveOffset() {
@@ -348,6 +402,8 @@ function init() {
$('raWristDetectBtn').addEventListener('click', onDetectWrist);
$('raMoveBtn').addEventListener('click', onMove);
$('raSaveOffsetBtn').addEventListener('click', onSaveOffset);
$('raVerifySnapBtn').addEventListener('click', onVerifySnap);
$('raVerifyResetBtn').addEventListener('click', onVerifyReset);
$('raHomeBtn').addEventListener('click', onHome);
$('raCustomGoBtn').addEventListener('click', onCustomGo);
$('raCustomSaveBtn').addEventListener('click', onCustomSave);