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:
1 parent
8d40ebaf89
commit
57954b5c8d
8 files changed
+238
-23
No files matched your search
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user