Files
appRobotDriver/doc/ToDo_6a_Speed.md
2026-06-09 15:51:30 +02:00

130 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ToDo 6a — Speed-Steuerung
> ## ✅ Status: erledigt (Pakete 12)
>
> - **Schalter `ROBOT_SPEED_MODE`** (`legacy` Default = exakt wie bisher, `correct` = koordiniert)
> - **`calculateSpeeds()`-NaN-Bug behoben** + `moveTime` eingeführt
> - **Koordinierte Feedrate** im `TelnetSenderGRBL` (Korrekt-Modus), Legacy-Pfad unangetastet
> - Tests: `test/Robot.calculateSpeeds.test.js`, `test/Sender.Telnet.speedMode.test.js`,
> `test/Speed.coordination.test.js`
>
> **Offen:** WS-Sender (Paket 3), `FPoint`-Feedrate (Paket 4 → ToDo_6b).
## Der Schalter: `ROBOT_SPEED_MODE`
Die Speed-Regelung ist über **eine einzige Umgebungsvariable** umschaltbar:
| Wert | Bedeutung |
|---|---|
| `legacy` (Default) | **Alte Speed-Regelung — alles läuft exakt wie bisher.** Jeder Sender sendet die kartesische Feedrate `F` (aus dem G-Code bzw. `robot.feedrate`) unverändert an alle seine Achsen. |
| `correct` | **Korrekte Speed-Regelung.** Jeder Sender erhält eine eigene, koordinierte Feedrate, sodass alle Controller die Bewegung gleichzeitig beenden. |
```yaml
# docker-compose.yml
environment:
ROBOT_SPEED_MODE: legacy # oder: correct
```
### Garantie für `legacy`
Im Legacy-Modus wird der **Sende-Pfad der Sender nicht angefasst**. Die Feedrate-Zeile
entsteht über exakt denselben Code wie bisher. Die bestehenden Sender-Tests
(`Sender.Telnet.test.js`, `Sender.Telnet.caseBackward.test.js`) prüfen die Ausgabe
zeichengenau und sind das Sicherheitsnetz: solange sie grün sind, ist Legacy
byte-identisch zu vorher.
Der Korrekt-Modus fügt **nur zusätzlich** eine alternative Feedrate-Berechnung hinzu,
die ausschließlich greift, wenn `ROBOT_SPEED_MODE=correct`.
### Abgrenzung zu `ROBOT_USE_SPEED_CALC`
`ROBOT_USE_SPEED_CALC` bleibt der interne Schalter dafür, ob `Robot.calculateSpeeds()`
überhaupt rechnet. Der Korrekt-Modus aktiviert diese Berechnung automatisch.
`ROBOT_USE_SPEED_CALC` allein ändert **nicht** die Sender-Ausgabe — nur
`ROBOT_SPEED_MODE=correct` tut das. Damit bleibt bestehendes Verhalten erhalten.
---
## Hintergrund: Warum die alte Regelung falsch ist
Der Roboter hat drei unabhängige GRBL/FluidNC-Controller. Im Legacy-Modus bekommen alle
dieselbe kartesische Feedrate (z. B. `f1000`) — unabhängig davon, wie weit sich die
jeweilige Achse in diesem Schritt tatsächlich bewegt. Folge: die Achse mit kurzer
Bewegung ist viel früher fertig als die mit langer Bewegung, die Bewegungen laufen nicht
koordiniert, und die Werkzeugbahn der Fingerspitze ist nicht linear.
**Korrekt:** Die kartesische Feedrate `F` bestimmt die Gesamt-Zeit des Schritts:
```
Bewegungszeit = kartesische_Distanz / F
Sender-Feedrate = Distanz_dieses_Senders / Bewegungszeit
```
So braucht jeder Controller dieselbe Zeit → die Bewegungen sind koordiniert.
---
## Behobene Defizite (Implementierung dieses ToDos)
### 1. `calculateSpeeds()` berechnete NaN — behoben
`Robot.calculateSpeeds()` las `oldPos.xMotor`, `oldPos.alpha`, `oldPos.beta` — Felder, die
in `RobotMotorPosition` nicht existieren (dort `x`, `y`, `z`). Ergebnis: `NaN`.
Korrigiert auf `oldPos.x/y/z`. Zusätzlich speichert die Methode jetzt die `Bewegungszeit`
(`moveTime`), die der Sender für die koordinierte Feedrate braucht.
### 2. Koordinierte Feedrate im Sender (Korrekt-Modus)
`TelnetSenderGRBL` berechnet im Korrekt-Modus die Feedrate als
`Distanz_dieses_Senders / moveTime`. Die Distanz wird über `portValue()` ermittelt —
eine reine Funktion, die für jede (GRBL-Port, Roboter-Achse)-Zuordnung den gesendeten
Wert liefert (dieselben Formeln wie der Sende-Pfad, aber als isolierte, testbare Funktion).
---
## Pakete
### Paket 1: `calculateSpeeds()` reparieren — ✅ ERLEDIGT
- [x] Property-Namen korrigiert: `oldPos.x/y/z/a/b/c/e`
- [x] `moveTime` berechnen und auf `motorPosition` ablegen
- [x] Unit-Tests: NaN-Freiheit, exakte Werte, Handgelenk-/Finger-Zweige, Guards
(`test/Robot.calculateSpeeds.test.js`)
### Paket 2: Schalter + koordinierte Feedrate — ✅ ERLEDIGT
- [x] `ROBOT_SPEED_MODE`-Schalter (`legacy` Default, `correct`)
- [x] `TelnetSenderGRBL`: koordinierte Feedrate im Korrekt-Modus, Legacy-Pfad unverändert
- [x] `portValue()` als isolierte Funktion, per Kreuzprobe gegen den echten Sende-Pfad getestet
- [x] Korrekt-Modus-Tests + Koordinations-Invariante über alle drei Sender
(`test/Sender.Telnet.speedMode.test.js`, `test/Speed.coordination.test.js`)
### Paket 3: `WSSenderGrbl` — ⬜ OFFEN (Folge-Schritt)
- [ ] `WSSenderGrbl` auf denselben Schalter + koordinierte Feedrate bringen
- WS-Sender ist aktuell nicht in `startRobot.js` aktiv → kein Produktiv-Risiko
- Legacy-Verhalten des WS-Senders zunächst unverändert lassen
### Paket 4: Aufräumen — ⬜ OFFEN (Folge-Schritt)
- [ ] `FPoint` in `GCode.receiveFC()`: `robot.feedrate` statt hardcodiertem `1000`
→ gehört thematisch zur Datei-Logik, wird in **ToDo_6b** behandelt
- [ ] `portValue()` perspektivisch auch im Sende-Pfad nutzen (Dedupe der Formeln);
bewusst aufgeschoben, um den Legacy-Pfad in diesem Schritt nicht anzufassen
### Bekannte Grenze des Korrekt-Modus v1
Die koordinierte Feedrate bildet die euklidische Norm über die Achsen eines Senders.
Mischt ein Sender lineare (mm) und winklige (Grad) Achsen, mischt die Norm diese
Einheiten — dieselbe Vereinfachung, die GRBL bei gemischten Achsen ohnehin macht.
Für eine spätere, einheiten-saubere Behandlung ggf. eigenes ToDo.
## Betroffene Dateien
- `robot/Robot.js``calculateSpeeds()` Fix, `moveTime`, Schalter→`useSpeedCalc`
- `robot/RobotMotorPosition.js``moveTime`-Feld
- `robot/TelnetSenderGRBL.js``portValue()`, koordinierte Feedrate, Schalter
- `test/Robot.calculateSpeeds.test.js` — neu
- `test/Sender.Telnet.speedMode.test.js` — neu