Y-Axis checks
This commit is contained in:
@@ -488,3 +488,124 @@ export async function adoptXAxis(robotPath, { direction }) {
|
||||
angleXZdeg: Math.round(Math.atan2(nz, nx) * 18000 / Math.PI) / 100,
|
||||
};
|
||||
}
|
||||
|
||||
// ── Aktion 6: Fixe Marker einem Link zuordnen ─────────────────────────────────
|
||||
|
||||
/**
|
||||
* Ordnet Marker, die sich bei einer Gelenk-Rotation kaum bewegen, dem angegebenen
|
||||
* Link zu. Typischer Anwendungsfall: Marker auf dem Basis-Körper werden als
|
||||
* "Base"-Marker in robot.json registriert.
|
||||
*
|
||||
* - markerIds: Array von Marker-IDs (number[])
|
||||
* - targetLink: Ziel-Link-Name (z. B. 'Base')
|
||||
* - measuredPositions: Array von { id, position_mm:[x,y,z] } aus Pos A
|
||||
*
|
||||
* Gibt { numAdded, numAlreadyPresent, changes[] } zurück.
|
||||
* Bestehende Einträge werden NICHT verschoben (überschreiben wäre destruktiv).
|
||||
*/
|
||||
export async function assignFixedMarkersToLink(robotPath, { markerIds, targetLink, measuredPositions = [] }) {
|
||||
if (!targetLink) throw new Error('targetLink muss angegeben werden.');
|
||||
|
||||
const robot = await readRobot(robotPath);
|
||||
const links = robot.links ?? {};
|
||||
|
||||
// Index: markerId → aktueller Link
|
||||
const existingMap = new Map();
|
||||
for (const [linkName, linkData] of Object.entries(links)) {
|
||||
for (const m of (linkData.markers ?? [])) {
|
||||
existingMap.set(Number(m.id), linkName);
|
||||
}
|
||||
}
|
||||
|
||||
// Pos-A-Positionen indizieren
|
||||
const posMap = new Map();
|
||||
for (const p of measuredPositions) {
|
||||
posMap.set(Number(p.id), p.position_mm);
|
||||
}
|
||||
|
||||
if (!links[targetLink]) links[targetLink] = { markers: [] };
|
||||
if (!links[targetLink].markers) links[targetLink].markers = [];
|
||||
|
||||
const changes = [];
|
||||
let numAdded = 0, numAlreadyPresent = 0;
|
||||
|
||||
for (const rawId of markerIds) {
|
||||
const id = Number(rawId);
|
||||
if (existingMap.has(id)) {
|
||||
numAlreadyPresent++;
|
||||
changes.push({ action: 'already-present', markerId: id, existingLink: existingMap.get(id) });
|
||||
continue;
|
||||
}
|
||||
|
||||
const pos = posMap.get(id);
|
||||
if (!pos || pos.length < 3) {
|
||||
changes.push({ action: 'skipped-no-position', markerId: id });
|
||||
continue;
|
||||
}
|
||||
|
||||
links[targetLink].markers.push({
|
||||
id,
|
||||
position: pos.map(v => Math.round(Number(v) * 10) / 10), // 1 Dezimalstelle (mm)
|
||||
positionSource: 'calibration-fixed-detection',
|
||||
});
|
||||
numAdded++;
|
||||
changes.push({ action: 'added', markerId: id, targetLink });
|
||||
}
|
||||
|
||||
if (numAdded > 0) {
|
||||
robot.links = links;
|
||||
await writeRobot(robotPath, robot);
|
||||
}
|
||||
|
||||
return { numAdded, numAlreadyPresent, changes };
|
||||
}
|
||||
|
||||
// ── Aktion 7: Joint-Origin Y/Z aus Drehachse übernehmen ──────────────────────
|
||||
|
||||
/**
|
||||
* Setzt die Y- und Z-Koordinaten des jointToParent.origin eines Links.
|
||||
*
|
||||
* Der Ursprung der Drehachse (axisPoint_mm) liegt im Board-Koordinatensystem.
|
||||
* Y und Z sind davon direkt auf den Joint-Origin übertragbar (X wird vom
|
||||
* Slider bestimmt und bleibt unverändert).
|
||||
*
|
||||
* - linkName: Name des Links, dessen Joint aktualisiert wird (z. B. 'Arm1')
|
||||
* - y: Neuer Y-Wert des Joint-Origins (mm)
|
||||
* - z: Neuer Z-Wert des Joint-Origins (mm)
|
||||
*
|
||||
* Gibt { changed, linkName, oldOrigin, newOrigin } zurück.
|
||||
*/
|
||||
export async function setJointOriginYZ(robotPath, { linkName, y, z }) {
|
||||
if (!linkName) throw new Error('linkName muss angegeben werden.');
|
||||
|
||||
const robot = await readRobot(robotPath);
|
||||
const link = (robot.links ?? {})[linkName];
|
||||
if (!link) return { changed: false, error: `Link '${linkName}' nicht in robot.json gefunden.` };
|
||||
|
||||
const joint = link.jointToParent;
|
||||
if (!joint) return { changed: false, error: `Link '${linkName}' hat kein jointToParent.` };
|
||||
|
||||
const oldOrigin = Array.isArray(joint.origin) ? [...joint.origin] : [null, null, null];
|
||||
|
||||
if (!Array.isArray(joint.origin) || joint.origin.length < 3) {
|
||||
joint.origin = [oldOrigin[0] ?? 0, 0, 0];
|
||||
}
|
||||
|
||||
joint.origin[1] = Math.round(Number(y) * 10) / 10; // Y (1 Dezimalstelle)
|
||||
joint.origin[2] = Math.round(Number(z) * 10) / 10; // Z
|
||||
|
||||
// Quelle dokumentieren
|
||||
if (!joint.originSource) joint.originSource = [null, null, null];
|
||||
while (joint.originSource.length < 3) joint.originSource.push(null);
|
||||
joint.originSource[1] = 'calibration-yaxis';
|
||||
joint.originSource[2] = 'calibration-yaxis';
|
||||
|
||||
await writeRobot(robotPath, robot);
|
||||
|
||||
return {
|
||||
changed: true,
|
||||
linkName,
|
||||
oldOrigin,
|
||||
newOrigin: [...joint.origin],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import { fileURLToPath } from 'url';
|
||||
import process from 'process';
|
||||
import { spawn } from 'child_process';
|
||||
import { WebcamClient } from './webcamClient.js';
|
||||
import { assignByZRange, removeMarkerAssignment, alignSetToMeasured, assignMarkerId, adoptXAxis } from './editRobot.js';
|
||||
import { assignByZRange, removeMarkerAssignment, alignSetToMeasured, assignMarkerId, adoptXAxis, assignFixedMarkersToLink, setJointOriginYZ } from './editRobot.js';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
@@ -889,6 +889,61 @@ app.post('/api/robot/adopt-x-axis', async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* POST /api/robot/assign-fixed-markers
|
||||
* Ordnet Marker, die sich bei einer Gelenk-Rotation kaum bewegen, dem
|
||||
* angegebenen Link zu (typisch: 'Base').
|
||||
* Body: { markerIds: number[], targetLink: string, measuredPositions: [{id, position_mm}] }
|
||||
*/
|
||||
app.post('/api/robot/assign-fixed-markers', async (req, res) => {
|
||||
try {
|
||||
const { markerIds, targetLink, measuredPositions = [] } = req.body ?? {};
|
||||
if (!Array.isArray(markerIds) || markerIds.length === 0) {
|
||||
return res.status(400).json({ error: '"markerIds" muss ein nicht-leeres Array sein.' });
|
||||
}
|
||||
if (!targetLink) {
|
||||
return res.status(400).json({ error: '"targetLink" muss angegeben werden.' });
|
||||
}
|
||||
const result = await assignFixedMarkersToLink(ROBOT_JSON, { markerIds, targetLink, measuredPositions });
|
||||
console.log(
|
||||
`robot/assign-fixed-markers [${markerIds.join(',')}] → ${targetLink}` +
|
||||
` added=${result.numAdded} alreadyPresent=${result.numAlreadyPresent}`,
|
||||
);
|
||||
return res.json(result);
|
||||
} catch (err) {
|
||||
console.error('robot/assign-fixed-markers error:', err);
|
||||
return res.status(500).json({ error: String(err) });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* POST /api/robot/set-joint-origin
|
||||
* Setzt Y und Z des jointToParent.origin eines Links aus der berechneten
|
||||
* Drehachsen-Position.
|
||||
* Body: { linkName: string, y: number, z: number }
|
||||
*/
|
||||
app.post('/api/robot/set-joint-origin', async (req, res) => {
|
||||
try {
|
||||
const { linkName, y, z } = req.body ?? {};
|
||||
if (!linkName) return res.status(400).json({ error: '"linkName" muss angegeben werden.' });
|
||||
if (!Number.isFinite(Number(y)) || !Number.isFinite(Number(z))) {
|
||||
return res.status(400).json({ error: '"y" und "z" müssen Zahlen sein.' });
|
||||
}
|
||||
const result = await setJointOriginYZ(ROBOT_JSON, { linkName, y: Number(y), z: Number(z) });
|
||||
if (!result.changed) {
|
||||
return res.status(400).json({ error: result.error });
|
||||
}
|
||||
console.log(
|
||||
`robot/set-joint-origin ${linkName}: ` +
|
||||
`[${result.oldOrigin.join(', ')}] → [${result.newOrigin.join(', ')}]`,
|
||||
);
|
||||
return res.json(result);
|
||||
} catch (err) {
|
||||
console.error('robot/set-joint-origin error:', err);
|
||||
return res.status(500).json({ error: String(err) });
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* POST /api/calibration/upload-npz
|
||||
* Liest {camera}_calibration.npz aus der aktuellen Session und
|
||||
|
||||
Reference in New Issue
Block a user