115 lines
5.0 KiB
Markdown
115 lines
5.0 KiB
Markdown
# 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.
|
|
|
|
```js
|
|
// 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
|
|
|
|
```js
|
|
// 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`:
|
|
```js
|
|
// 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.js` — `calculateSpeeds()` 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.js` — `FPoint`: `robot.feedrate` statt `1000`
|
|
- `test/GCode.speed.test.js` — Tests für NaN-freie Berechnung ergänzen
|