Files
appRobotHoming/public/calculateActions.js
2026-03-30 20:33:15 +02:00

262 lines
8.7 KiB
JavaScript
Executable File

// 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 };