// calculateActions.js // Funktionen zum Berechnen von Vorschlägen basierend auf den neuesten CSV-Daten const analysisLogEl = document.getElementById('analysis-log'); function appendToAnalysis(line) { const now = new Date().toISOString(); analysisLogEl.value += `[${now}] ${line}\n`; analysisLogEl.scrollTop = analysisLogEl.scrollHeight; } async function fetchCSV() { console.log('Lade und verarbeite CSV-Daten...'); const res = await fetch('/api/latest-snapshot'); if (!res.ok) throw new Error('Fehler beim Laden des Snapshots'); let data; if (res.headers.get('content-type')?.includes('application/json')) { data = await res.json(); } else { const csvData = await res.text(); data = { filename: 'latest.csv', mtime: new Date().toISOString(), content: csvData }; } // CSV parsen const lines = data.content.trim().split('\n'); if (lines.length < 2) { throw new Error('Keine oder unvollständige Daten'); } const headers = lines[0].split(',').map(h => h.trim()); const rows = lines.slice(1).map(line => { const cells = line.split(','); let obj = {}; headers.forEach((h, i) => { const val = cells[i]?.trim(); obj[h] = isNaN(val) ? val : parseFloat(val); }); return obj; }); appendToAnalysis(`CSV-Daten geladen: ${rows.length} Zeilen, ${headers.length} Spalten.`); return { data, headers, rows }; } async function readValues( data, headers, rows ){ console.log('Geladene Daten:', data); console.log('Headers:', headers); console.log('Parsed rows:', rows); } function calculateAngleFromPosition(row, axisY, axisZ, deltaYangle0, deltaZangle0 = 0) { let y = parseFloat(row.y_mm); let z = parseFloat(row.z_mm); let dy = -(y - axisY); let dz = z - axisZ; let angle0Rad = 0; if(deltaZangle0 !== 0){ angle0Rad = Math.atan(deltaZangle0/deltaYangle0); } angleRad = Math.atan(dz/dy) - angle0Rad; angleDeg = angleRad * (180 / Math.PI); appendToAnalysis(`(yMotor = ${angleDeg.toFixed(2)}° = ${angleRad.toFixed(4)} rad ) aus Position von ID = ${row.id}`); return angleRad; } function calculateAngleFromRollColumn(row, roll0 = 0, pitch0 = 0, yaw0 = 0, strMotor = "yMotor") { let roll = -parseFloat(row.roll_deg) + roll0; appendToAnalysis(`(${strMotor} = ${roll.toFixed(2)}° = ${(roll * Math.PI / 180).toFixed(4)} rad) aus roll_deg von ID = ${row.id}`); return roll*Math.PI / 180; } function calculateAngleFromRelativePosition(row1, row2, strMotor = "zMotor") { let y1 = parseFloat(row1.y_mm); let z1 = parseFloat(row1.z_mm); let y2 = parseFloat(row2.y_mm); let z2 = parseFloat(row2.z_mm); let dy = y1 - y2; let dz = z1 - z2; let angleRad = -Math.atan(dz/dy); let angleDeg = angleRad * (180 / Math.PI); appendToAnalysis(`(${strMotor} = ${angleDeg.toFixed(2)}° = ${angleRad.toFixed(4)} rad) aus relativer Position von ID = ${row1.id} und ID = ${row2.id}`); return angleRad; } async function calculate() { let shoulderAxisY = 115; let shoulderAxisZ = 61; let rows = null; let headers = null; try { appendToAnalysis('Starte Berechnung...'); const result = await fetchCSV(); rows = result.rows; headers = result.headers; const data = result.data; await readValues( data, headers, rows ); } catch (err) { appendToAnalysis('Fehler in calculate: ' + err.message); } // Oberarm: var angleY = 0; var angleZ = 0; var angleYcount = 0; var angleZcount = 0; // 243 damit 35mm weiter außen (250+35) und 0mm höher als Schulterachse const row243 = rows.find(r => r.id == 243 && r.seen_by == 3) if(row243){ angleY += await calculateAngleFromPosition(row243, shoulderAxisY, shoulderAxisZ, 250+35, 0); angleY += await calculateAngleFromRollColumn(row243, 90, 0, 0); angleYcount+=2; } const row229 = rows.find(r => r.id == 229 && r.seen_by == 3) if(row229){ angleY += await calculateAngleFromPosition(row229, shoulderAxisY, shoulderAxisZ, 250, 35); //angleY +=calculateAngleFromRollColumn(row229, 0, 0, 0); // Roll ist extrem unzuverlässig angleYcount+=1; } console.log(angleY, angleYcount); const row198 = rows.find(r => r.id == 198 && r.seen_by == 3) if(row198){ angleY += await calculateAngleFromPosition(row198, shoulderAxisY, shoulderAxisZ, 165, 35); //angleY +=calculateAngleFromRollColumn(row198, 180, 0, 0); // ist ungenau angleYcount++; } if(row198 && row229){ angleY += 3*(calculateAngleFromRelativePosition(row198, row229, "yMotor")); angleYcount += 3; } const row197 = rows.find(r => r.id == 197) if(row197){ var angleDeg = 90 - row197.pitch_deg; var angleRad = angleDeg * Math.PI / 180; appendToAnalysis(`(yMotor = ${angleDeg.toFixed(2)}° = ${angleRad.toFixed(4)} rad ) aus Pitch von ${row197.id}`); } // Unterarm: // 218 und 219, wenn die sichtbar sind, ist auch die Schulter eindeutig definiert const row218 = rows.find(r => r.id == 218 && r.seen_by == 3) const row219 = rows.find(r => r.id == 219 && r.seen_by == 3) if(row218 && row219){ const lowerArmAngle = calculateAngleFromRelativePosition(row218, row219, "zMotor"); angleZ += lowerArmAngle; angleZcount++; } console.log("z", angleZ); const row226 = rows.find(r => r.id == 226 && r.seen_by == 3) if(row226){ angleZ += calculateAngleFromRollColumn(row226, 0, 0, 0, "zMotor"); angleZcount++; } console.log("z", angleZ); if(angleYcount > 0 && angleYcount > 0){ strActionOptionA = `G92 y${(angleY*180/(angleYcount*Math.PI)).toFixed(1)} z${(angleZ*180/(Math.PI*angleZcount)).toFixed(1)} (Set Coord. Angles in deg)`; strActionOptionB = `M92 y${(angleY/(angleYcount)).toFixed(3)} z${(angleZ/(angleZcount)).toFixed(3)} (Set Coord. Angles in rad)`; appendToAnalysis(`Suggestion: ${strActionOptionA}`); appendToAnalysis(`Suggestion: ${strActionOptionB}`); // ToDo: Change } // Ellbow const row242 = rows.find(r => r.id == 242 && r.seen_by == 3) const row200 = rows.find(r => r.id == 200 && r.seen_by == 3) const row204 = rows.find(r => r.id == 204 && r.seen_by == 3) // Ellenbogen-Rotation aus x-Position 218 219 // dazu brauche ich genaue x-Position von 226 if(row226 || row229 || row198 || row243 || row242 || row200 || row200){ var x226 = 0; var xCount = 0; if(row226){ x226 += row226.x_mm * 5; xCount += 5; } if(row229){ x226 += row229.x_mm + 90; xCount += 1; } if(row198){ x226 += row198.x_mm + 90; xCount += 1; } if(row243){ x226 += row243.x_mm + 90; xCount += 1; } if(row242){ x226 += row242.x_mm + 90; xCount += 1; } if(row200){ x226 += row200.x_mm + 154; xCount += 1; } if(row204){ x226 += row204.x_mm + 160; xCount += 1; } x226 = x226 / xCount; appendToAnalysis(`Ellebogen x226=${x226}`) // Wenn 218 und/oder 219 sicher gesehen wird, kann ich daraus x-pos bestimmen if(row218 || row219){ var x219 = 0; xCount = 0; if(row218){ x219 += row218.x_mm; xCount += 1; } if(row219){ x219 += row219.x_mm; xCount += 1; } x219 = x219 / xCount; appendToAnalysis(`Ellebogen x219=${x219}`) var xDelta = x219 - x226; if(Math.abs(xDelta) < 35){ appendToAnalysis(`Ellebogen xDelta / 35=${xDelta / 35}`) var angleRad = Math.asin(xDelta / 35) var angleDeg = 90 -angleRad*180/Math.PI; appendToAnalysis(`(xEllbow = ${angleDeg.toFixed(2)}° = ${angleRad.toFixed(4)} rad ) aus x von 218 bzw. 219`); } } } } if (typeof module !== 'undefined') { module.exports = { calculateAngleFromPosition, calculateAngleFromRollColumn, calculateAngleFromRelativePosition, calculate }; } // Export für Module, falls benötigt // export { fetchCSV, calculate };