Files
appRobotDriver/doc/ToDo_6a_Speed.md
2026-06-09 12:05:18 +02:00

5.0 KiB

ToDo 6a — Speed-Steuerung

Ist-Zustand und Defizite

Die Feedrate-Logik ist auf zwei Ebenen defekt:

Ebene 1: calculateSpeeds() berechnet NaN

Robot.calculateSpeeds(oldPos, newPos) liest oldPos.xMotor, oldPos.alpha, oldPos.beta — diese Properties existieren in RobotMotorPosition nicht. Dort heißen sie x, y, z. Ergebnis: alle motorSpeeds-Werte sind NaN. Die Methode ist seit ihrer Einführung kaputt und fällt nur nicht auf, weil ROBOT_USE_SPEED_CALC standardmäßig false ist.

// Zeile ~214 Robot.js — falsch:
this.motorSpeeds.x = (this.xMotor - oldPos.xMotor) / time;  // oldPos.xMotor → undefined
this.motorSpeeds.y = (this.alpha  - oldPos.alpha)  / time;  // oldPos.alpha  → undefined
this.motorSpeeds.z = (this.beta   - oldPos.beta)   / time;  // oldPos.beta   → undefined

// Richtig (RobotMotorPosition-Felder):
this.motorSpeeds.x = (this.xMotor - oldPos.x) / time;
this.motorSpeeds.y = (this.alpha  - oldPos.y) / time;
this.motorSpeeds.z = (this.beta   - oldPos.z) / time;

Ebene 2: motorSpeeds werden von keinem Sender gelesen

Selbst wenn calculateSpeeds() korrekte Werte lieferte, ignorieren beide Sender die berechneten Geschwindigkeiten vollständig:

  • TelnetSenderGRBL: sendet mNew.feedrate (Kartesisch, mm/min) an alle Achsen gleich
  • WSSenderGrbl: sendet immer this.maxSpeedF, ignoriert mNew.feedrate komplett

Das ist grundsätzlich falsch: Der Roboter hat drei unabhängige GRBL-Controller. Damit die Fingerspitze mit F1000 mm/min fährt, muss jede Achse mit einer anderen Winkelgeschwindigkeit drehen — je nachdem, wie weit sie sich für diesen Schritt bewegt. Alle Achsen mit derselben Feedrate zu befehlen führt zu nicht-linearen Werkzeugbahnen.

Ebene 3: FPoint kodiert Feedrate hart

// GCode.js FPoint — immer f1000, egal was robot.feedrate ist:
var strGCode = `G90 G1 x${robot.x} ... f1000`

Konzept: Korrekte Feedrate-Verteilung

Gesamtziel: Die Kartesische Feedrate F (mm/min) des G-Code-Befehls bestimmt, wie lange der Bewegungsschritt dauert. Diese Zeit wird auf alle Achsen aufgeteilt.

Zeit = kartesische_Distanz / F_mm_per_min

Achsen-Feedrate[i] = Achsen-Delta[i] / Zeit
                   (in Grad/min, da GRBL-Achsen typisch in Grad konfiguriert)

Der Sender kennt seine Achse (xAxisGrbl, yAxisGrbl, zAxisGrbl) und kann die passende Geschwindigkeit aus motorPosition.speeds lesen, wenn diese korrekt befüllt sind.


Pakete

Paket 1: calculateSpeeds() reparieren

  • Property-Namen korrigieren: oldPos.x/y/z/a/b/c/e statt oldPos.xMotor/alpha/beta/...
  • Einheit klären: motorSpeeds in rad/min oder direkt in Grad/min?
    • Sender wandeln Motorwinkel bereits von rad → Grad (* 180/π) für Positionen
    • Einheitlichste Lösung: motorSpeeds ebenfalls in Grad/min speichern, oder die Umrechnung konsistent im Sender vornehmen
  • Grenzfall: Wenn kartesische Distanz null ist (reine Gelenkbewegung), Distanz über Handgelenk-Punkt verwenden — das ist bereits so angelegt, aber mit den falschen Property-Namen
  • Unit-Test: calculateSpeeds mit bekannten Werten, prüfen dass keine NaN entstehen

Paket 2: motorSpeeds in den Sender durchreichen

  • motorPosition.speeds korrekt befüllen (passiert bereits via this.motorPosition.speeds = {...this.motorSpeeds} nach calculateSpeeds)
  • Sender-Interface (execCommand): wenn ROBOT_USE_SPEED_CALC aktiv und motorPosition.speeds[achse] verfügbar und > 0 → diesen Wert als F verwenden
  • Jeder Sender (TelnetSenderGRBL, WSSenderGrbl) kennt seine Achse und holt die passende Geschwindigkeit aus speeds:
    // Beispiel: Sender ist für Achse "a" zuständig
    const f = (useSpeedCalc && mNew.speeds.a > 0) ? mNew.speeds.a : mNew.feedrate;
    data += ` f${f.toFixed(2)}`;
    
  • Fallback: wenn ROBOT_USE_SPEED_CALC=false oder Speeds nicht berechnet → mNew.feedrate wie bisher (Rückwärtskompatibilität)

Paket 3: WSSenderGrbl Feedrate-Handling vereinheitlichen

  • WSSenderGrbl.execCommand() auf dasselbe Feedrate-Schema wie TelnetSenderGRBL umstellen
    • aktuell: immer this.maxSpeedF → ignoriert das F aus dem G-Code-Befehl komplett
    • richtig: mNew.feedrate verwenden (bzw. per-Achse aus Paket 2)
  • maxSpeedF als Obergrenze behalten (Clamp), nicht als feste Ausgabe

Paket 4: Kleinere Korrekturen

  • FPoint in GCode.receiveFC(): robot.feedrate statt hardcodierten 1000 speichern
  • ROBOT_USE_SPEED_CALC-Flag dokumentieren: was ändert sich mit/ohne Flag? Klarer Kommentar in Robot.js und im README

Betroffene Dateien

  • robot/Robot.jscalculateSpeeds() bugfix, Einheitenwahl
  • robot/RobotMotorPosition.js — ggf. speeds-Feld klarer benennen
  • robot/TelnetSenderGRBL.js — per-Achse Feedrate aus speeds
  • robot/WSSenderGrbl.js — Feedrate auf mNew.feedrate umstellen + Clamp
  • robot/GCode.jsFPoint: robot.feedrate statt 1000
  • test/GCode.speed.test.js — Tests für NaN-freie Berechnung ergänzen