Marker error +110
This commit is contained in:
@@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -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 });
|
||||
|
||||
|
||||
Reference in New Issue
Block a user