Marker error +110

This commit is contained in:
chk
2026-06-14 22:13:13 +02:00
parent d56ccd8094
commit 42f042c9d0
2 changed files with 71 additions and 11 deletions

View File

@@ -1160,7 +1160,10 @@ window.addEventListener('message', async (e) => {
await loadData(e.data.runDir);
}
if (e.data?.type === 'homing-state' && IS_HOMING) {
_homingAngles = e.data.state;
// Gefundene Winkel über Default-Position mergen, damit noch nicht erkannte
// Gelenke nicht auf 0 zusammenfallen, sondern sinnvoll stehen bleiben.
const base = _currentRobot?.defaultPosition ?? {};
_homingAngles = { ...base, ...e.data.state };
if (_currentRobot) buildSkeletonFK(_currentRobot, _homingAngles);
}
});

View File

@@ -10,23 +10,80 @@ import path from 'path';
import fs from 'fs';
import fsPromises from 'fs/promises';
/**
* Modell-Welt-x eines Markers bei slider=0, durch Aufsummieren der origin.x
* entlang der Kette Link→…→Base. Das Ergebnis ist winkel-unabhängig (und damit
* exakt) genau dann, wenn alle revolute-Gelenke der Kette um die x-Achse drehen
* (Rotation um x erhält die x-Koordinate). Andernfalls xSafe=false.
*
* @param {object} links robot.json links
* @param {string} linkName
* @param {number[]} localPos Marker-Position im lokalen Link-Frame [x,y,z]
* @returns {{ worldX: number, xSafe: boolean }}
*/
function modelWorldXAtSliderZero(links, linkName, localPos) {
let xOffset = 0;
let xSafe = true;
let cur = linkName;
const seen = new Set();
while (cur && links[cur]?.jointToParent && !seen.has(cur)) {
seen.add(cur);
const jtp = links[cur].jointToParent;
xOffset += jtp.origin?.[0] ?? 0;
const axis = jtp.axis ?? [0, 0, 0];
const isXAxis = Math.abs(axis[0]) === 1 && axis[1] === 0 && axis[2] === 0;
if (jtp.type === 'revolute' && !isXAxis) xSafe = false;
cur = links[cur].parent;
}
return { worldX: xOffset + (localPos?.[0] ?? 0), xSafe };
}
/**
* Schätzt die Slider-X-Position aus den triangulierten Marker-Positionen
* (aruco_marker_poses.json). Nutzt den Durchschnitt der x_mm aller
* Nicht-Board-Marker. Fallback: 0.0 wenn keine Arm-Marker sichtbar.
* (aruco_marker_poses.json).
*
* Für jeden beobachteten Arm-Marker wird der implizierte Slider-Wert berechnet:
* slider_i = beobachtetes_world_x Modell_world_x(slider=0)
* und über alle x-zuverlässigen Marker gemittelt. So wird der Gelenk-Offset
* (z.B. Arm1.origin.x = 110 mm) korrekt herausgerechnet.
*
* Fallback (kein robot.json oder keine zuverlässigen Marker): alter Mittelwert
* der rohen world-x nur als Notlösung.
*
* @param {string} arucoJsonPath
* @param {string} [robotJsonPath]
* @returns {number} x_mm
*/
export function estimateXFromMarkers(arucoJsonPath) {
export function estimateXFromMarkers(arucoJsonPath, robotJsonPath) {
try {
const data = JSON.parse(fs.readFileSync(arucoJsonPath, 'utf8'));
const armMarkers = (data.markers ?? []).filter(
m => m.link && m.link !== 'Board',
);
const data = JSON.parse(fs.readFileSync(arucoJsonPath, 'utf8'));
const links = robotJsonPath
? (JSON.parse(fs.readFileSync(robotJsonPath, 'utf8')).links ?? {})
: {};
const samples = [];
for (const obs of (data.markers ?? [])) {
if (!obs.link || obs.link === 'Board') continue;
const modelMarker = links[obs.link]?.markers?.find(m => m.id === obs.marker_id);
if (!modelMarker?.position) continue;
const { worldX, xSafe } = modelWorldXAtSliderZero(links, obs.link, modelMarker.position);
if (!xSafe) continue;
const obsX = obs.position_mm?.[0];
if (obsX == null) continue;
samples.push(obsX - worldX);
}
if (samples.length > 0) {
return samples.reduce((a, b) => a + b, 0) / samples.length;
}
// ── Fallback: alter, geometrisch ungenauer Mittelwert ──
const armMarkers = (data.markers ?? []).filter(m => m.link && m.link !== 'Board');
if (armMarkers.length === 0) return 0.0;
const sumX = armMarkers.reduce((s, m) => s + (m.position_mm?.[0] ?? 0), 0);
return sumX / armMarkers.length;
return armMarkers.reduce((s, m) => s + (m.position_mm?.[0] ?? 0), 0) / armMarkers.length;
} catch {
return 0.0;
}
@@ -78,7 +135,7 @@ export async function runHoming({
// ── Schritt 2: X-Position bestimmen ─────────────────────────────────────
send({ type: 'step', step: 2, total: 6, text: 'X-Position bestimmen …' });
const xMm = estimateXFromMarkers(arucoJson);
const xMm = estimateXFromMarkers(arucoJson, robotJsonPath);
send({ type: 'log', text: `▶ Geschätzte X-Position: ${xMm.toFixed(1)} mm` });
send({ type: 'analysis', key: 'x_mm', value: xMm });