Angle Double
This commit is contained in:
@@ -718,9 +718,6 @@ if (typeof window !== "undefined") {
|
|||||||
if (typeof module !== "undefined") {
|
if (typeof module !== "undefined") {
|
||||||
module.exports = {
|
module.exports = {
|
||||||
calculate,
|
calculate,
|
||||||
createAnalysisResult,
|
createAnalysisResult
|
||||||
calculateAngleFromPosition,
|
|
||||||
calculateAngleFromRollColumn,
|
|
||||||
calculateAngleFromRelativePosition
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -21,12 +21,16 @@ function appendToAnalysis(line) {
|
|||||||
|
|
||||||
|
|
||||||
function calculateXPos(listIdAndX, jsonRobot){
|
function calculateXPos(listIdAndX, jsonRobot){
|
||||||
appendToAnalysis("Calculate XPos");
|
appendToAnalysis("xPos");
|
||||||
|
|
||||||
const partsMovingFixedX = new Set(['Base', 'Arm1', 'Joint1']);
|
const partsMovingFixedX = new Set(['Base', 'Arm1', 'Joint1']);
|
||||||
const markersMovingFixedX = jsonRobot.Marker.filter(m => partsMovingFixedX.has(m.on));
|
const markersMovingFixedX = jsonRobot.Marker.filter(m => partsMovingFixedX.has(m.on));
|
||||||
|
|
||||||
|
appendToAnalysis(`xPos found ${markersMovingFixedX.length} Markers`);
|
||||||
// Join: Robot-Marker ↔ Found-Marker
|
// Join: Robot-Marker ↔ Found-Marker
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const markersListeWithRobotInfo = jsonRobot.Marker
|
const markersListeWithRobotInfo = jsonRobot.Marker
|
||||||
.filter(m => partsMovingFixedX.has(m.on)) // nur relevante Teile
|
.filter(m => partsMovingFixedX.has(m.on)) // nur relevante Teile
|
||||||
.map(m => {
|
.map(m => {
|
||||||
@@ -48,6 +52,8 @@ function calculateXPos(listIdAndX, jsonRobot){
|
|||||||
const variancePx = pxValues.reduce((sum, x) => sum + Math.pow(x - meanPx, 2), 0) / pxValues.length;
|
const variancePx = pxValues.reduce((sum, x) => sum + Math.pow(x - meanPx, 2), 0) / pxValues.length;
|
||||||
const stdDevPx = Math.sqrt(variancePx);
|
const stdDevPx = Math.sqrt(variancePx);
|
||||||
|
|
||||||
|
|
||||||
|
appendToAnalysis(`xPos > ${meanPx.toFixed(2)} ± ${stdDevPx.toFixed(2)}`)
|
||||||
return { meanPx, stdDevPx };
|
return { meanPx, stdDevPx };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +123,63 @@ function optimizeRobot(listFoundMarkers, jsonRobot) {
|
|||||||
return withStats;
|
return withStats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function calculateRotationAngleByTwoMarkers(listIdAndX, jsonRobot, jointName){
|
||||||
|
|
||||||
|
// Achse finden
|
||||||
|
const jointInfo = jsonRobot.Joints[jointName];
|
||||||
|
if(!jointInfo){return null, null; }
|
||||||
|
if(jointInfo.type !== 'revolute'){ return null, null; }
|
||||||
|
|
||||||
|
if(!(jointInfo.axis)){ return null, null; }
|
||||||
|
if(!(jointInfo.child)){ return null, null; }
|
||||||
|
|
||||||
|
var a = 1;
|
||||||
|
var b = 2;
|
||||||
|
if(jointInfo.axis == [1,0,0]){a=1, b=2}
|
||||||
|
if(jointInfo.axis == [0,1,0]){a=0, b=2}
|
||||||
|
if(jointInfo.axis == [0,0,1]){a=0, b=1}
|
||||||
|
|
||||||
|
const achsisName = (jointName == "jointB") ? "y" : (jointName == "jointC") ? "z" : "a"
|
||||||
|
|
||||||
|
|
||||||
|
appendToAnalysis(`${achsisName}Ang - Double Started with on dir [${a}, ${b}]`)
|
||||||
|
|
||||||
|
markerUsed = jsonRobot.Marker.filter(m => m.on === jointInfo.child)
|
||||||
|
if(markerUsed.length === 0){
|
||||||
|
appendToAnalysis(`${achsisName}Ang - Double no Markers found`)
|
||||||
|
return null, null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const markerFound = markerUsed
|
||||||
|
.map(m => [m.id, listIdAndX.get(m.id)])
|
||||||
|
.filter(v => v !== undefined && v[1] !== undefined);
|
||||||
|
|
||||||
|
|
||||||
|
const pairs = [];
|
||||||
|
for (let i = 0; i < markerFound.length; i++) {
|
||||||
|
for (let j = i + 1; j < markerFound.length; j++) {
|
||||||
|
const [idA, posA] = markerFound[i];
|
||||||
|
const [idB, posB] = markerFound[j];
|
||||||
|
|
||||||
|
if (posA[a] === posB[a] && posA[b] === posB[b]) {
|
||||||
|
pairs.push([idA, idB]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pairs == []){ appendToAnalysis(`${achsisName}Ang - Double not found`); return; }
|
||||||
|
|
||||||
|
|
||||||
|
for(i in pairs){
|
||||||
|
m0 = listIdAndX.get(i[0]);
|
||||||
|
m1 = listIdAndX.get(i[1]);
|
||||||
|
|
||||||
|
appendToAnalysis(`${achsisName}Ang - Double ${JSON.stringify(m0)} and ${JSON.stringify(m1)} -- ${i}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function calculateRotationAngle(listIdAndX, jsonRobot, jointName, method = "tan") {
|
function calculateRotationAngle(listIdAndX, jsonRobot, jointName, method = "tan") {
|
||||||
|
|
||||||
// Achse finden
|
// Achse finden
|
||||||
const jointInfo = jsonRobot.Joints[jointName];
|
const jointInfo = jsonRobot.Joints[jointName];
|
||||||
if(!jointInfo){return null, null; }
|
if(!jointInfo){return null, null; }
|
||||||
@@ -143,19 +205,25 @@ function calculateRotationAngle(listIdAndX, jsonRobot, jointName, method = "tan"
|
|||||||
b = 1;
|
b = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const achsisName = (jointName == "jointB") ? "y" : (jointName == "jointC") ? "z" : "a"
|
||||||
|
appendToAnalysis(`${achsisName}Ang - Started with ${method} on dir [${a}, ${b}]`)
|
||||||
|
|
||||||
const jointA = jointInfo.origin[a];
|
const jointA = jointInfo.origin[a];
|
||||||
const jointB = jointInfo.origin[b];
|
const jointB = jointInfo.origin[b];
|
||||||
|
|
||||||
|
appendToAnalysis(`${achsisName}Ang - Axis: (${jointA.toFixed(2)}, ${jointB.toFixed(2)})`);
|
||||||
|
|
||||||
markerUsed = jsonRobot.Marker.filter(m => m.on === jointInfo.child)
|
markerUsed = jsonRobot.Marker.filter(m => m.on === jointInfo.child)
|
||||||
if(markerUsed.length === 0){ return null, null; }
|
if(markerUsed.length === 0){ return null, null; }
|
||||||
|
|
||||||
|
|
||||||
const markerFound = markerUsed
|
const markerFound = markerUsed
|
||||||
.map(m => [m.id, listIdAndX.get(m.id)])
|
.map(m => [m.id, listIdAndX.get(m.id)])
|
||||||
.filter(v => v !== undefined && v[1] !== undefined); // Nur Marker, die gefunden wurden
|
.filter(v => v !== undefined && v[1] !== undefined); // Nur Marker, die gefunden wurden
|
||||||
|
|
||||||
var angles = [];
|
appendToAnalysis(`${achsisName}Ang found ${markerFound.length} markers`);
|
||||||
|
|
||||||
|
var angles = [];
|
||||||
for(const pos of markerFound) {
|
for(const pos of markerFound) {
|
||||||
const id = pos[0];
|
const id = pos[0];
|
||||||
const mRobot = jsonRobot.Marker.filter(m => m.id === id)[0];
|
const mRobot = jsonRobot.Marker.filter(m => m.id === id)[0];
|
||||||
@@ -168,6 +236,8 @@ const markerFound = markerUsed
|
|||||||
const angleOne = Math.atan2(db, da) * (180 / Math.PI);
|
const angleOne = Math.atan2(db, da) * (180 / Math.PI);
|
||||||
const deltaAngleTan = angleOne - angleZero;
|
const deltaAngleTan = angleOne - angleZero;
|
||||||
angles.push(deltaAngleTan);
|
angles.push(deltaAngleTan);
|
||||||
|
|
||||||
|
appendToAnalysis(`${achsisName}Ang tan: ${mRobot.id} Pos=(${pos[1][a].toFixed(2)}, ${pos[1][b].toFixed(2)}) Δ=(${da.toFixed(2)},${db.toFixed(2)}) α°=${angleZero.toFixed(2)} ${achsisName}=${deltaAngleTan.toFixed(2)}`);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
const hypotenuse = Math.sqrt(mRobot.relPos[a]**2 + mRobot.relPos[b]**2);
|
const hypotenuse = Math.sqrt(mRobot.relPos[a]**2 + mRobot.relPos[b]**2);
|
||||||
@@ -176,15 +246,17 @@ const markerFound = markerUsed
|
|||||||
if(method === "sin"){
|
if(method === "sin"){
|
||||||
const db = pos[1][b] - jointB;
|
const db = pos[1][b] - jointB;
|
||||||
var angleOneSin;
|
var angleOneSin;
|
||||||
if(Math.abs(db) > hypotenuse && db < 1.3 * hypotenuse){angleOneSin = 180}
|
if(Math.abs(db) > hypotenuse && db < 1.3 * hypotenuse){angleOneSin = -180}
|
||||||
else if(Math.abs(db) < hypotenuse && -1*Math.abs(db) > -hypotenuse){
|
else if(Math.abs(db) < hypotenuse && -1*Math.abs(db) > -hypotenuse){
|
||||||
angleOneSin = Math.asin(db / hypotenuse) * (180 / Math.PI);
|
angleOneSin = Math.asin(db / hypotenuse) * (180 / Math.PI);
|
||||||
}
|
}
|
||||||
else if(Math.abs(db) < -1*hypotenuse && Math.abs(db) > 1.3*Math.abs(db)){angleOneSin = -180}
|
else if(Math.abs(db) < -1*hypotenuse && Math.abs(db) > 1.3*Math.abs(db)){angleOneSin = 180}
|
||||||
else angleOneSin = NaN;
|
else angleOneSin = NaN;
|
||||||
|
|
||||||
const deltaAngleSin = angleOneSin - angleZero;
|
const deltaAngleSin = angleOneSin - angleZero;
|
||||||
angles.push(deltaAngleSin);
|
angles.push(deltaAngleSin);
|
||||||
|
|
||||||
|
appendToAnalysis(`${achsisName}Ang sin: ${mRobot.id} Pos=(${pos[1][a].toFixed(2)}, ${pos[1][b].toFixed(2)}) Δ=${db.toFixed(2)} hyp=${hypotenuse.toFixed(2)} α°=${angleOneSin.toFixed(2)} ${achsisName}=${deltaAngleSin.toFixed(2)}`);
|
||||||
}
|
}
|
||||||
// Arbeiten mit cos und hypotenuse
|
// Arbeiten mit cos und hypotenuse
|
||||||
else{
|
else{
|
||||||
@@ -192,10 +264,11 @@ const markerFound = markerUsed
|
|||||||
const angleOneCos = Math.acos(db / hypotenuse) * (180 / Math.PI);
|
const angleOneCos = Math.acos(db / hypotenuse) * (180 / Math.PI);
|
||||||
const deltaAngleCos = -(angleOneCos - angleZero);
|
const deltaAngleCos = -(angleOneCos - angleZero);
|
||||||
angles.push(deltaAngleCos);
|
angles.push(deltaAngleCos);
|
||||||
|
|
||||||
|
appendToAnalysis(`${achsisName}Ang cos: ${mRobot.id} Pos=(${pos[1][a].toFixed(2)}, ${pos[1][b].toFixed(2)}) Δ=${db.toFixed(2)} hyp=${hypotenuse.toFixed(2)} α°=${angleOneCos.toFixed(2)} ${achsisName}=${deltaAngleCos.toFixed(2)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const n = angles.length;
|
const n = angles.length;
|
||||||
if(n === 0){ return null, null; }
|
if(n === 0){ return null, null; }
|
||||||
@@ -203,25 +276,39 @@ const markerFound = markerUsed
|
|||||||
const average = angles.reduce((a, b) => a + b, 0) / n;
|
const average = angles.reduce((a, b) => a + b, 0) / n;
|
||||||
const deviation = Math.sqrt(angles.reduce((sum, x) => sum + Math.pow(x - average, 2), 0) / n);
|
const deviation = Math.sqrt(angles.reduce((sum, x) => sum + Math.pow(x - average, 2), 0) / n);
|
||||||
|
|
||||||
|
appendToAnalysis(`${achsisName}Ang ${achsisName}=${average.toFixed(2)} ± ${deviation.toFixed(2)}`)
|
||||||
return {average, deviation};
|
return {average, deviation};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function calculate(foundMarkers, jsonRobot) {
|
async function calculate(foundMarkers, jsonRobot) {
|
||||||
|
|
||||||
|
if(foundMarkers == undefined || jsonRobot == undefined){console.warn("calculateAngles mit falschen Parametern aufgerufen.");}
|
||||||
|
|
||||||
const foundById = new Map(foundMarkers.markers.map(f => [f.id, f.position_mm ]));
|
const foundById = new Map(foundMarkers.markers.map(f => [f.id, f.position_mm ]));
|
||||||
const { meanPx: x, stdDevPx: varx } = calculateXPos(foundById, jsonRobot);
|
const { meanPx: x, stdDevPx: varx } = calculateXPos(foundById, jsonRobot);
|
||||||
|
|
||||||
jsonRobot.recognized.x = x;
|
jsonRobot.recognized.x = x;
|
||||||
|
|
||||||
const { average: y, deviation: vary } = calculateRotationAngle(foundById, jsonRobot, "jointB", "tan");
|
const { average: y, deviation: vary } = calculateRotationAngle(foundById, jsonRobot, "jointB", "tan");
|
||||||
|
|
||||||
|
try{
|
||||||
|
calculateRotationAngleByTwoMarkers(foundById, jsonRobot, "jointB");
|
||||||
|
}
|
||||||
|
catch(e){
|
||||||
|
appendToAnalysis(e);
|
||||||
|
}
|
||||||
jsonRobot.recognized.y = y;
|
jsonRobot.recognized.y = y;
|
||||||
|
// ToDo ! callibration
|
||||||
jsonRobot.Joints["jointD"].origin[0] = x;
|
jsonRobot.Joints["jointD"].origin[0] = x;
|
||||||
jsonRobot.Joints["jointD"].origin[1] = -jsonRobot.ElementLength["Arm1"]*Math.cos(y*Math.PI/180)
|
jsonRobot.Joints["jointD"].origin[1] = -jsonRobot.ElementLength["Arm1"]*Math.cos(y*Math.PI/180)
|
||||||
jsonRobot.Joints["jointD"].origin[2] = jsonRobot.ElementLength["Arm1"]*Math.sin(y*Math.PI/180)
|
jsonRobot.Joints["jointD"].origin[2] = jsonRobot.ElementLength["Arm1"]*Math.sin(y*Math.PI/180)
|
||||||
|
|
||||||
const { average: a, deviation: vara } = calculateRotationAngle(foundById, jsonRobot, "jointD", "sin");
|
const { average: a, deviation: vara } = calculateRotationAngle(foundById, jsonRobot, "jointD", "sin");
|
||||||
|
|
||||||
|
jsonRobot.Joints["jointC"].origin[0] = x;
|
||||||
|
jsonRobot.Joints["jointC"].origin[1] = -jsonRobot.ElementLength["Arm1"]*Math.cos(y*Math.PI/180)
|
||||||
|
jsonRobot.Joints["jointC"].origin[2] = jsonRobot.ElementLength["Arm1"]*Math.sin(y*Math.PI/180)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -84,10 +84,33 @@ function renderResult(result) {
|
|||||||
renderTree(treeEl, result, "result", true);
|
renderTree(treeEl, result, "result", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchCSV() {
|
dataCache = null
|
||||||
|
headersCache = null
|
||||||
|
rowsCache = null
|
||||||
|
timeCache = null
|
||||||
|
jsonCache = null
|
||||||
|
|
||||||
|
async function fetchCSV(){
|
||||||
|
if(dataCache == null || headersCache == null || rowsCache == null || timeCache == null){
|
||||||
|
({ data: dataCache, headers: headersCache, rows: rowsCache } = await fetchCSV_fromServer());
|
||||||
|
timeCache = Date.now();
|
||||||
|
}
|
||||||
|
if (Date.now() - timeCache > 1000){
|
||||||
|
|
||||||
|
({ data: dataCache, headers: headersCache, rows: rowsCache } = await fetchCSV_fromServer());
|
||||||
|
timeCache = Date.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {data: dataCache, headers: headersCache, rows: rowsCache}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchCSV_fromServer() {
|
||||||
|
|
||||||
const res = await fetch("/api/latest-snapshot");
|
const res = await fetch("/api/latest-snapshot");
|
||||||
if (!res.ok) throw new Error("Fehler beim Laden des Snapshots");
|
if (!res.ok) throw new Error("Fehler beim Laden des Snapshots");
|
||||||
|
|
||||||
|
|
||||||
let data;
|
let data;
|
||||||
if (res.headers.get("content-type")?.includes("application/json")) {
|
if (res.headers.get("content-type")?.includes("application/json")) {
|
||||||
data = await res.json();
|
data = await res.json();
|
||||||
@@ -99,6 +122,10 @@ async function fetchCSV() {
|
|||||||
content: csvData
|
content: csvData
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!jsonCache && data.jsonFile) {
|
||||||
|
jsonCache = JSON.parse(data.jsonFile.content);
|
||||||
|
}
|
||||||
|
|
||||||
const lines = data.content.trim().split(/\r?\n/).filter(Boolean);
|
const lines = data.content.trim().split(/\r?\n/).filter(Boolean);
|
||||||
if (lines.length < 2) {
|
if (lines.length < 2) {
|
||||||
@@ -199,7 +226,15 @@ async function onCalculateClick() {
|
|||||||
appendLog("Starte Berechnung...");
|
appendLog("Starte Berechnung...");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await window.calculate();
|
const response = await fetch("robot.json");
|
||||||
|
await fetchCSV();
|
||||||
|
|
||||||
|
//console.log("Data:", dataCache);
|
||||||
|
//console.log("json: ", JSON.stringify(jsonCache));
|
||||||
|
//console.log("Keys:", Object.keys(dataCache));
|
||||||
|
|
||||||
|
const robot = await response.json();
|
||||||
|
const result = await window.calculate(jsonCache, robot);
|
||||||
renderResult(result);
|
renderResult(result);
|
||||||
await renderSnapshot();
|
await renderSnapshot();
|
||||||
appendLog("Result angezeigt.");
|
appendLog("Result angezeigt.");
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
GCodeMotor
|
GCodeMotor
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button id="btn-calculate" onclick="fetchAndCalculate()">Calculate Actions</button>
|
<button id="btn-calculate">Calculate Actions</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -86,12 +86,11 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/calculateActions.js"></script>
|
|
||||||
|
<!--<script src="/calculateActions.js"></script> -->
|
||||||
|
<script src="/calculateAngles.js"></script>
|
||||||
<script src="/client.js"></script>
|
<script src="/client.js"></script>
|
||||||
|
|
||||||
<script defer> window.calculateAngles.fetchAndCalculate(); </script>
|
|
||||||
|
|
||||||
<script src="/calculateAngles.js"></script>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
"ElementLength":{"Arm1":250, "Arm2":250, "Finger1":100, "Finger2":100},
|
"ElementLength":{"Arm1":250, "Arm2":250, "Finger1":100, "Finger2":100},
|
||||||
"Joints":{
|
"Joints":{
|
||||||
"jointA":{"name":"Slider", "type":"lninear", "axis":[1,0,0],"parent":"Board","child":"Base"},
|
"jointA":{"name":"Slider", "type":"lninear", "axis":[1,0,0],"parent":"Board","child":"Base"},
|
||||||
"jointB":{"name":"Shoulder","type":"revolute","axis":[1,0,0],"parent":"Base","child":"Arm1","origin":[-89.5, 115, 61], "originSource":[null, "229_198_Foto_5_2026", "Fuson"]},
|
"jointB":{"name":"Shoulder","type":"revolute","axis":[1,0,0],"parent":"Base","child":"Arm1","origin":[-89.5, 115, 52], "originSource":[null, "229_198_Foto_5_2026", "Fuson"]},
|
||||||
"jointC":{"name":"EllbowLift","type":"revolute","axis":[1,0,0],"parent":"Arm1","child":"Joint1", "origin":[null, null, null]},
|
"jointC":{"name":"EllbowLift","type":"revolute","axis":[1,0,0],"parent":"Arm1","child":"Joint1", "origin":[null, null, null]},
|
||||||
"jointD":{"name":"EllbowTwist","type":"revolute","axis":[0,1,0],"parent":"Joint1","child":"Arm2", "origin":[null, null, null]}
|
"jointD":{"name":"EllbowTwist","type":"revolute","axis":[0,1,0],"parent":"Joint1","child":"Arm2", "origin":[null, null, null]}
|
||||||
},
|
},
|
||||||
@@ -32,14 +32,14 @@
|
|||||||
{"id":226,"on":"Joint1", "relPos":[0,0, 35]},
|
{"id":226,"on":"Joint1", "relPos":[0,0, 35]},
|
||||||
|
|
||||||
{"id":228,"on":"Arm2", "relPos":[-24.75, 112, 24.75], "relPosSource":["Fusion","Fusion","Fusion"]},
|
{"id":228,"on":"Arm2", "relPos":[-24.75, 112, 24.75], "relPosSource":["Fusion","Fusion","Fusion"]},
|
||||||
{"id": 0,"on":"Arm2", "relPos":[-24.75, 182, 24.75], "relPosSource":["Fusion","Fusion","Fusion"]},
|
{"id": -1,"on":"Arm2", "relPos":[-24.75, 182, 24.75], "relPosSource":["Fusion","Fusion","Fusion"]},
|
||||||
{"id": 0,"on":"Arm2", "relPos":[-35,112,0], "relPosSource":["Fusion","Fusion","Fusion"]},
|
{"id": -1,"on":"Arm2", "relPos":[-35,112,0], "relPosSource":["Fusion","Fusion","Fusion"]},
|
||||||
{"id": 0,"on":"Arm2", "relPos":[-35,219,0], "relPosSource":["Fusion","Fusion","Fusion"]},
|
{"id": -1,"on":"Arm2", "relPos":[-35,219,0], "relPosSource":["Fusion","Fusion","Fusion"]},
|
||||||
{"id":223,"on":"Arm2", "relPos":[-28.67,112,-20.08], "relPosSource":["Fusion","Fusion","Fusion"]},
|
{"id":223,"on":"Arm2", "relPos":[-28.67,112,-20.08], "relPosSource":["Fusion","Fusion","Fusion"]},
|
||||||
{"id": 0,"on":"Arm2", "relPos":[0,182,-30], "relPosSource":["Fusion","Fusion","Fusion"]},
|
{"id": -1,"on":"Arm2", "relPos":[0,182,-30], "relPosSource":["Fusion","Fusion","Fusion"]},
|
||||||
{"id":218,"on":"Arm2", "relPos":[35,112,0], "relPosSource":["Fusion","Fusion","Fusion"]},
|
{"id":218,"on":"Arm2", "relPos":[35,112,0], "relPosSource":["Fusion","Fusion","Fusion"]},
|
||||||
{"id":219,"on":"Arm2", "relPos":[35,219,0], "relPosSource":["Fusion","Fusion","Fusion"]},
|
{"id":219,"on":"Arm2", "relPos":[35,219,0], "relPosSource":["Fusion","Fusion","Fusion"]},
|
||||||
{"id": 0,"on":"Arm2", "relPos":[24.75, 182, 24.75], "relPosSource":["Fusion","Fusion","Fusion"]},
|
{"id": -1,"on":"Arm2", "relPos":[24.75, 182, 24.75], "relPosSource":["Fusion","Fusion","Fusion"]},
|
||||||
|
|
||||||
{"id":218,"on":"Finger1","name":"A1","relPos":[-1.70,-25.14, 38.04]},
|
{"id":218,"on":"Finger1","name":"A1","relPos":[-1.70,-25.14, 38.04]},
|
||||||
{"id":222,"on":"Finger1","name":"B1","relPos":[-14.55, 0.84, 74.79]}
|
{"id":222,"on":"Finger1","name":"B1","relPos":[-14.55, 0.84, 74.79]}
|
||||||
|
|||||||
@@ -208,11 +208,16 @@ app.get('/api/latest-snapshot', (req, res) => {
|
|||||||
const latestFile = csvFiles[0];
|
const latestFile = csvFiles[0];
|
||||||
const baseName = path.basename(latestFile.name, path.extname(latestFile.name));
|
const baseName = path.basename(latestFile.name, path.extname(latestFile.name));
|
||||||
const jsonFilename = `${baseName}.json`;
|
const jsonFilename = `${baseName}.json`;
|
||||||
|
const jsonPath = path.join(snapshotsDir, jsonFilename);
|
||||||
|
|
||||||
|
console.log("JSON Pfad:", jsonPath);
|
||||||
|
console.log("Existiert JSON:", fs.existsSync(jsonPath));
|
||||||
|
|
||||||
const imageFilename = `${baseName}_annotated.jpg`;
|
const imageFilename = `${baseName}_annotated.jpg`;
|
||||||
const imagePath = path.join(snapshotsDir, imageFilename);
|
const imagePath = path.join(snapshotsDir, imageFilename);
|
||||||
const imatePath2 = imagePath.includes('video0') ? imagePath.replace('video0', 'video1') : imagePath.replace('video1', 'video0');
|
const imatePath2 = imagePath.includes('video0') ? imagePath.replace('video0', 'video1') : imagePath.replace('video1', 'video0');
|
||||||
|
|
||||||
|
//--
|
||||||
fs.readFile(latestFile.path, 'utf8', (err, data) => {
|
fs.readFile(latestFile.path, 'utf8', (err, data) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
return res.status(500).json({ error: 'Fehler beim Lesen der Datei' });
|
return res.status(500).json({ error: 'Fehler beim Lesen der Datei' });
|
||||||
@@ -224,39 +229,45 @@ app.get('/api/latest-snapshot', (req, res) => {
|
|||||||
content: data
|
content: data
|
||||||
};
|
};
|
||||||
|
|
||||||
// Lade JSON wenn vorhanden
|
const jsonPath = path.join(snapshotsDir, jsonFilename);
|
||||||
fs.readFile(jsonFilename, { encoding: 'base64' }, (jpgErr, jpgBase64) => {
|
|
||||||
if (!jpgErr && jpgBase64) {
|
// ✅ JSON FIRST, dann alles andere
|
||||||
response.imageFile = {
|
fs.readFile(jsonPath, 'utf8', (jsonErr, jsonData) => {
|
||||||
|
if (!jsonErr && jsonData) {
|
||||||
|
response.jsonFile = {
|
||||||
filename: jsonFilename,
|
filename: jsonFilename,
|
||||||
mimeType: 'json',
|
content: jsonData
|
||||||
contentBase64: jpgBase64
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Lade beide Bilder
|
|
||||||
fs.readFile(imagePath, { encoding: 'base64' }, (jpgErr, jpgBase64) => {
|
|
||||||
if (!jpgErr && jpgBase64) {
|
|
||||||
response.imageFile = {
|
|
||||||
filename: imageFilename,
|
|
||||||
mimeType: 'image/jpeg',
|
|
||||||
contentBase64: jpgBase64
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.readFile(imatePath2, { encoding: 'base64' }, (jpgErr2, jpgBase642) => {
|
// Bild 1
|
||||||
if (!jpgErr2 && jpgBase642) {
|
fs.readFile(imagePath, { encoding: 'base64' }, (jpgErr, jpgBase64) => {
|
||||||
response.image2 = {
|
if (!jpgErr && jpgBase64) {
|
||||||
filename: path.basename(imatePath2),
|
response.imageFile = {
|
||||||
|
filename: imageFilename,
|
||||||
mimeType: 'image/jpeg',
|
mimeType: 'image/jpeg',
|
||||||
contentBase64: jpgBase642
|
contentBase64: jpgBase64
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
res.json(response);
|
|
||||||
|
// Bild 2
|
||||||
|
fs.readFile(imatePath2, { encoding: 'base64' }, (jpgErr2, jpgBase642) => {
|
||||||
|
if (!jpgErr2 && jpgBase642) {
|
||||||
|
response.image2 = {
|
||||||
|
filename: path.basename(imatePath2),
|
||||||
|
mimeType: 'image/jpeg',
|
||||||
|
contentBase64: jpgBase642
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ jetzt erst senden
|
||||||
|
res.json(response);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//--
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
BIN
test/snapshots/snapshot_video0_1778845508432.jpg
Executable file
BIN
test/snapshots/snapshot_video0_1778845508432.jpg
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 164 KiB |
20
test/snapshots/snapshot_video0_1778845508432_two_cam.csv
Executable file
20
test/snapshots/snapshot_video0_1778845508432_two_cam.csv
Executable file
@@ -0,0 +1,20 @@
|
|||||||
|
id,x_mm,y_mm,z_mm,roll_deg,pitch_deg,yaw_deg,seen_by
|
||||||
|
camera 0,-45.26,-643.92,610.54,-123.820,-3.052,-30.995
|
||||||
|
camera 1,10.55,-438.57,997.81,-160.771,-18.041,-14.950
|
||||||
|
180,419.14,-140.22,418.18,72.800,42.247,-106.109,2
|
||||||
|
189,453.50,-168.57,403.03,88.856,-7.808,-48.251,3
|
||||||
|
196,426.40,-168.29,377.81,16.748,-9.999,-21.351,3
|
||||||
|
197,297.35,-122.58,90.09,95.407,83.104,-83.205,1
|
||||||
|
198,338.69,-34.96,116.45,-10.259,0.249,-1.646,3
|
||||||
|
200,268.46,-18.68,115.06,0.906,-1.063,1.907,3
|
||||||
|
201,232.36,58.93,100.62,48.972,59.258,20.582,3
|
||||||
|
204,268.60,134.65,120.12,-3.903,1.616,-1.027,3
|
||||||
|
205,803.19,-90.66,-0.77,131.746,-47.948,-88.085,3
|
||||||
|
210,-5.27,3.72,-4.15,-1.090,1.598,-1.102,3
|
||||||
|
211,200.22,0.62,-1.19,-1.206,0.232,-1.179,3
|
||||||
|
215,199.19,-89.68,-0.60,-1.626,-0.834,-1.483,3
|
||||||
|
218,410.85,-161.13,200.05,-93.281,-7.490,129.360,3
|
||||||
|
219,418.18,-170.76,306.64,-36.855,-10.153,137.791,3
|
||||||
|
222,453.79,-138.61,61.69,-96.553,-4.102,-175.991,1
|
||||||
|
229,341.88,-124.09,129.35,-7.622,0.840,-0.059,3
|
||||||
|
243,353.63,-145.71,80.99,81.127,1.472,0.651,1
|
||||||
|
267
test/snapshots/snapshot_video0_1778845508432_two_cam.json
Executable file
267
test/snapshots/snapshot_video0_1778845508432_two_cam.json
Executable file
@@ -0,0 +1,267 @@
|
|||||||
|
{
|
||||||
|
"metadata": {
|
||||||
|
"timestamp": "2026-05-15 11:45:08",
|
||||||
|
"reference_markers": [
|
||||||
|
205,
|
||||||
|
210,
|
||||||
|
211,
|
||||||
|
215
|
||||||
|
],
|
||||||
|
"dict": "DICT_4X4_250",
|
||||||
|
"marker_size_mm": 25.0,
|
||||||
|
"rms_refs_px_cam1": 5.39648196111485,
|
||||||
|
"rms_refs_px_cam2": 5.377608516390921,
|
||||||
|
"description": "Two-camera joint optimization with triangulation"
|
||||||
|
},
|
||||||
|
"cameras": [
|
||||||
|
{
|
||||||
|
"id": "camera1",
|
||||||
|
"position_mm": [
|
||||||
|
-45.26291564111129,
|
||||||
|
-643.9152747329521,
|
||||||
|
610.5360477447284
|
||||||
|
],
|
||||||
|
"orientation_deg": {
|
||||||
|
"roll": -123.81983227060897,
|
||||||
|
"pitch": -3.052095021020194,
|
||||||
|
"yaw": -30.994640267051796
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "camera2",
|
||||||
|
"position_mm": [
|
||||||
|
10.553380406378764,
|
||||||
|
-438.5675198007304,
|
||||||
|
997.8097666875392
|
||||||
|
],
|
||||||
|
"orientation_deg": {
|
||||||
|
"roll": -160.77106232170593,
|
||||||
|
"pitch": -18.041298309463212,
|
||||||
|
"yaw": -14.950430767356504
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"markers": [
|
||||||
|
{
|
||||||
|
"id": 180,
|
||||||
|
"position_mm": [
|
||||||
|
419.144582367835,
|
||||||
|
-140.22299366478097,
|
||||||
|
418.1777757275768
|
||||||
|
],
|
||||||
|
"orientation_deg": {
|
||||||
|
"roll": 72.80001565888858,
|
||||||
|
"pitch": 42.24706355578098,
|
||||||
|
"yaw": -106.10873668157622
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 189,
|
||||||
|
"position_mm": [
|
||||||
|
453.49652099609375,
|
||||||
|
-168.57383728027344,
|
||||||
|
403.028076171875
|
||||||
|
],
|
||||||
|
"orientation_deg": {
|
||||||
|
"roll": 88.85554131822369,
|
||||||
|
"pitch": -7.808091604864712,
|
||||||
|
"yaw": -48.2507766865305
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 196,
|
||||||
|
"position_mm": [
|
||||||
|
426.4018859863281,
|
||||||
|
-168.291748046875,
|
||||||
|
377.80609130859375
|
||||||
|
],
|
||||||
|
"orientation_deg": {
|
||||||
|
"roll": 16.74814878527144,
|
||||||
|
"pitch": -9.998891362798654,
|
||||||
|
"yaw": -21.35050086279306
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 197,
|
||||||
|
"position_mm": [
|
||||||
|
297.35264103055096,
|
||||||
|
-122.58445163275444,
|
||||||
|
90.08801199506212
|
||||||
|
],
|
||||||
|
"orientation_deg": {
|
||||||
|
"roll": 95.40654253536692,
|
||||||
|
"pitch": 83.10358092445118,
|
||||||
|
"yaw": -83.20497125428815
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 198,
|
||||||
|
"position_mm": [
|
||||||
|
338.6861877441406,
|
||||||
|
-34.96370315551758,
|
||||||
|
116.44953918457031
|
||||||
|
],
|
||||||
|
"orientation_deg": {
|
||||||
|
"roll": -10.259342232120957,
|
||||||
|
"pitch": 0.24870528512126713,
|
||||||
|
"yaw": -1.645925923556587
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 200,
|
||||||
|
"position_mm": [
|
||||||
|
268.4554138183594,
|
||||||
|
-18.676528930664062,
|
||||||
|
115.06306457519531
|
||||||
|
],
|
||||||
|
"orientation_deg": {
|
||||||
|
"roll": 0.9062729692050792,
|
||||||
|
"pitch": -1.0632288819207127,
|
||||||
|
"yaw": 1.9070692806416922
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 201,
|
||||||
|
"position_mm": [
|
||||||
|
232.35826110839844,
|
||||||
|
58.9295539855957,
|
||||||
|
100.61632537841797
|
||||||
|
],
|
||||||
|
"orientation_deg": {
|
||||||
|
"roll": 48.97241093155402,
|
||||||
|
"pitch": 59.257661898345866,
|
||||||
|
"yaw": 20.58152841399833
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 204,
|
||||||
|
"position_mm": [
|
||||||
|
268.6045837402344,
|
||||||
|
134.6527099609375,
|
||||||
|
120.11669921875
|
||||||
|
],
|
||||||
|
"orientation_deg": {
|
||||||
|
"roll": -3.9025079982094075,
|
||||||
|
"pitch": 1.6157619620164512,
|
||||||
|
"yaw": -1.0273413143882555
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 205,
|
||||||
|
"position_mm": [
|
||||||
|
803.1948852539062,
|
||||||
|
-90.6617660522461,
|
||||||
|
-0.7710586786270142
|
||||||
|
],
|
||||||
|
"orientation_deg": {
|
||||||
|
"roll": 131.7462374697395,
|
||||||
|
"pitch": -47.94838144672623,
|
||||||
|
"yaw": -88.08547595658573
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 210,
|
||||||
|
"position_mm": [
|
||||||
|
-5.272350788116455,
|
||||||
|
3.7151503562927246,
|
||||||
|
-4.148390293121338
|
||||||
|
],
|
||||||
|
"orientation_deg": {
|
||||||
|
"roll": -1.0895745898564984,
|
||||||
|
"pitch": 1.597902036769897,
|
||||||
|
"yaw": -1.101966066052541
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 211,
|
||||||
|
"position_mm": [
|
||||||
|
200.220947265625,
|
||||||
|
0.6223337650299072,
|
||||||
|
-1.1855000257492065
|
||||||
|
],
|
||||||
|
"orientation_deg": {
|
||||||
|
"roll": -1.2056214342111915,
|
||||||
|
"pitch": 0.2315656693236613,
|
||||||
|
"yaw": -1.1785846140745873
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 215,
|
||||||
|
"position_mm": [
|
||||||
|
199.1853485107422,
|
||||||
|
-89.6837387084961,
|
||||||
|
-0.5997236967086792
|
||||||
|
],
|
||||||
|
"orientation_deg": {
|
||||||
|
"roll": -1.6261955295642851,
|
||||||
|
"pitch": -0.8340209558933352,
|
||||||
|
"yaw": -1.4828278676661735
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 218,
|
||||||
|
"position_mm": [
|
||||||
|
410.84588623046875,
|
||||||
|
-161.1257781982422,
|
||||||
|
200.04945373535156
|
||||||
|
],
|
||||||
|
"orientation_deg": {
|
||||||
|
"roll": -93.28051907841518,
|
||||||
|
"pitch": -7.489671997832344,
|
||||||
|
"yaw": 129.36034680599943
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 219,
|
||||||
|
"position_mm": [
|
||||||
|
418.1803283691406,
|
||||||
|
-170.76272583007812,
|
||||||
|
306.6425476074219
|
||||||
|
],
|
||||||
|
"orientation_deg": {
|
||||||
|
"roll": -36.85526866474793,
|
||||||
|
"pitch": -10.152567906310786,
|
||||||
|
"yaw": 137.79108214891733
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 222,
|
||||||
|
"position_mm": [
|
||||||
|
453.786514652246,
|
||||||
|
-138.60719584007464,
|
||||||
|
61.69153094975155
|
||||||
|
],
|
||||||
|
"orientation_deg": {
|
||||||
|
"roll": -96.55321857084233,
|
||||||
|
"pitch": -4.102189790510929,
|
||||||
|
"yaw": -175.99142561055683
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 229,
|
||||||
|
"position_mm": [
|
||||||
|
341.875244140625,
|
||||||
|
-124.09217071533203,
|
||||||
|
129.34832763671875
|
||||||
|
],
|
||||||
|
"orientation_deg": {
|
||||||
|
"roll": -7.622257491837189,
|
||||||
|
"pitch": 0.8403760856279705,
|
||||||
|
"yaw": -0.05929184338877813
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 243,
|
||||||
|
"position_mm": [
|
||||||
|
353.6258784328338,
|
||||||
|
-145.70869032187207,
|
||||||
|
80.99019815263763
|
||||||
|
],
|
||||||
|
"orientation_deg": {
|
||||||
|
"roll": 81.12712553142183,
|
||||||
|
"pitch": 1.472073634639913,
|
||||||
|
"yaw": 0.6510713155997453
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
BIN
test/snapshots/snapshot_video0_1778845508432_two_cam_annotated.jpg
Executable file
BIN
test/snapshots/snapshot_video0_1778845508432_two_cam_annotated.jpg
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 268 KiB |
BIN
test/snapshots/snapshot_video0_1778845508432_two_cam_overlay.png
Executable file
BIN
test/snapshots/snapshot_video0_1778845508432_two_cam_overlay.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
BIN
test/snapshots/snapshot_video1_1778845508432.jpg
Executable file
BIN
test/snapshots/snapshot_video1_1778845508432.jpg
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 153 KiB |
BIN
test/snapshots/snapshot_video1_1778845508432_two_cam_annotated.jpg
Executable file
BIN
test/snapshots/snapshot_video1_1778845508432_two_cam_annotated.jpg
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 239 KiB |
BIN
test/snapshots/snapshot_video1_1778845508432_two_cam_overlay.png
Executable file
BIN
test/snapshots/snapshot_video1_1778845508432_two_cam_overlay.png
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
Reference in New Issue
Block a user