249 lines
12 KiB
Markdown
249 lines
12 KiB
Markdown
# AppRobotDriver
|
||
|
||
Dieses Projekt empfängt G-Code und Robotersteuerbefehle, berechnet Inverse Kinematik für einen mehrgliedrigen Roboterarm und leitet die resultierenden Achsenbefehle an mehrere GRBL/FluidNC-Telnet-Sender weiter.
|
||
|
||
## Architektur
|
||
|
||
- `startRobot.js` startet zwei HTTPS-Server:
|
||
- Eingabe-Server + WebSocket für G-Code und Steuerbefehle
|
||
- Info-Server für Status, Position und einfache Weboberfläche
|
||
- `server/InputWS.js` empfängt Nachrichten von WebSocket-Clients, prüft sie auf G-Code oder Datei-Kommandos und gibt Positionsdaten zurück.
|
||
- `robot/GCode.js` verarbeitet G-Code, übersetzt ihn in Roboter-Koordinaten und triggert `robot.sendCommand()`.
|
||
- `robot/RobotBase.js` ist die abstrakte Basisklasse / der Interface-Vertrag: generische Infrastruktur (Zustand, `sendCommand`, Motor-Geschwindigkeiten) plus die zwei abstrakten Kinematik-Methoden.
|
||
- `robot/kinematics/Arm3SegmentLinearX.js` ist die konkrete Kinematik (Inverse + Vorwärts) für den aktuellen Arm. Die Auswahl der Kinematik erfolgt über `robot/KinematicsFactory.js` (Umgebungsvariablen `ROBOT_KINEMATICS` / `ROBOT_KINEMATICS_PARAMS`). Siehe `doc/ToDo_12_InverseKinematikConfig_ROADMAP.md`.
|
||
- `robot/RobotConfig.js` liest `data/robot/robot.json` beim Start synchron und gibt einen typisierten Konfigurations-Record zurück (Kinematik-Parameter, Bewegungs-Defaults, Controller-Endpunkte). Env-Variablen überschreiben die JSON-Werte.
|
||
- `server/RobotConfigService.js` stellt `GET/PUT /api/robot` und `GET /api/robot/history` über den InfoServer bereit (Single Source of Truth für alle Apps). Schreibzugriffe erfordern `Authorization: Bearer <ROBOT_API_KEY>`.
|
||
- `robot/TelnetSenderGRBL.js` formatiert die Motor-Positionen in GRBL-kompatible Befehle und sendet sie per Telnet an einen Zielcontroller.
|
||
|
||
## Eingaben
|
||
|
||
Die Eingaben kommen per WebSocket an den HTTPS-Server und werden in `server/InputWS.js` verarbeitet.
|
||
|
||
### Unterstützte Nachrichten
|
||
|
||
- `Ping`
|
||
- Antwort: Wird zurück an alle verbundenen Clients gesendet.
|
||
- `M114`
|
||
- Antwort: Positionsdaten des Roboters im JSON-Format.
|
||
- G-Code-Befehle:
|
||
- `G90`, `G91`, `G1`, `G28`
|
||
- `G92` (wird intern als `M92` verarbeitet — setzt Motorposition ohne Bewegung)
|
||
- Messungen in `X`, `Y`, `Z`, `A`, `B`, `C`, `E`, `F`
|
||
- `M1` für direkte Motor-Koordinaten
|
||
- Datei-Kommandos:
|
||
- `FPoint`, `FPlus`, `FMinus`, `FShow`, `FList`, `FLoad <file>`, `FSave <file>`, `FClear`
|
||
- `FFirst`, `FLast` — erkannt, aber noch nicht implementiert
|
||
- `M20`, `M23`, `M28`, `M29`
|
||
|
||
### G-Code-Verarbeitung
|
||
|
||
- `GCode.receiveGCode(robot, message)`
|
||
- Gruppiert Zeilen, unterstützt Inline-Jogging (`$J=`)
|
||
- Schaltet zwischen absoluter und relativer Koordinatenverarbeitung
|
||
- Aktualisiert Position und Winkel im `robot`-Objekt
|
||
- Führt inverse Kinematik aus mit `robot.calculateAngles3D()`
|
||
- Sendet das Ergebnis an `robot.sendCommand()`
|
||
|
||
## Ausgaben
|
||
|
||
- WebSocket-Broadcasts an alle verbundenen Clients
|
||
- Nachdem ein G-Code-Befehl verarbeitet wurde, sendet das System `GCode.getM114(robot)` zurück.
|
||
- Für Datei-Kommandos gibt `GCode.receiveFC()` ebenfalls die aktuelle Position zurück.
|
||
- Telnet-Ausgabe an GRBL/FluidNC-Geräte
|
||
- `TelnetSenderGRBL.execCommand()` erzeugt `G1`/`G90`-Befehle mit Achsenzuordnung und Feedrate.
|
||
- Info-Server API
|
||
- `/api/status` — zeigt Client-Status, Sender-Status und letzte Befehle/Pings an
|
||
- `/api/position` — gibt die aktuelle Roboterposition und Motorwinkel als JSON zurück
|
||
|
||
## Konfiguration
|
||
|
||
### Starten
|
||
|
||
- `npm start`
|
||
- Alternativ: `node startRobot.js`
|
||
|
||
### Umgebungsvariablen
|
||
|
||
- `PORT`
|
||
- Standard: `2095`
|
||
- Port für den WebSocket/HTTPS-Eingabeserver
|
||
- `GRBL_BASE_IP`
|
||
- Standard: `fluidNcBase.local`
|
||
- Zielhost für den ersten Telnet-Sender
|
||
- `GRBL_ELLBOW_IP`
|
||
- Standard: `fluidNcEllbow.local`
|
||
- Zielhost für den Ellbogen-Sender
|
||
- `GRBL_HAND_IP`
|
||
- Standard: `fluidNcHand.local`
|
||
- Zielhost für den Hand-Sender
|
||
- `ROBOT_DEFAULT_FEEDRATE`
|
||
- Standard: `1000` (mm/min)
|
||
- Default-Feedrate für `G1`-Befehle, wenn keine `F`-Angabe vorhanden ist
|
||
- `ROBOT_SPEED_MODE`
|
||
- Werte: `legacy` (Standard) oder `correct`
|
||
- `legacy`: alte Speed-Regelung — jeder Sender erhält die kartesische Feedrate `F`
|
||
unverändert (Verhalten exakt wie bisher).
|
||
- `correct`: koordinierte Feedrate pro Sender, sodass alle Controller den Bewegungsschritt
|
||
gleichzeitig beenden. Aktiviert automatisch `calculateSpeeds()`.
|
||
- Details: `doc/ToDo_6a_Speed.md`
|
||
- `ROBOT_USE_SPEED_CALC`
|
||
- Werte: `true`, `1` oder sonst leer
|
||
- Interner Schalter, ob `robot.calculateSpeeds()` rechnet. Ändert allein **nicht** die
|
||
Sender-Ausgabe — dafür ist `ROBOT_SPEED_MODE=correct` nötig. Vom Korrekt-Modus
|
||
automatisch aktiviert.
|
||
- `ROBOT_KINEMATICS`
|
||
- Standard: `arm3segmentlinearx`
|
||
- Bezeichner der Kinematik-Klasse (case-insensitive). Bekannte Werte: `arm3segmentlinearx`,
|
||
`grabit` / `robot02` (Joy-IT Grab-It). Unbekannter Bezeichner → Fehler beim Start.
|
||
- `ROBOT_KINEMATICS_PARAMS`
|
||
- JSON-Objekt mit Konstruktor-Parametern, z. B. `{"l1":250,"l2":264,"l3":100}`.
|
||
Überschreibt die Werte aus `robot.json`. Wird von der Factory als viertes Argument
|
||
an den Konstruktor weitergereicht (erlaubt kinematik-spezifische Parameter wie `baseHeight`).
|
||
- `ROBOT_API_KEY`
|
||
- Statischer Bearer-Token für `PUT /api/robot`. Fehlt die Variable, generiert
|
||
`RobotConfigService` beim ersten Start einen zufälligen Key und speichert ihn in
|
||
`data/robot/.apikey` (nicht im Repo). Der Key wird beim Start einmalig geloggt.
|
||
|
||
### HTTPS-Konfiguration
|
||
|
||
- `https/localhost.key`
|
||
- `https/localhost.pem`
|
||
- Passphrase: Env-Variable `HTTPS_PASSPHRASE`, Default `abcd`
|
||
|
||
### robot.json
|
||
|
||
`data/robot/robot.json` ist die zentrale Konfigurationsdatei für einen konkreten Roboter.
|
||
Sie wird von `robot/RobotConfig.js` beim Start synchron gelesen. Fehlt die Datei, startet
|
||
der Driver mit Fallback-Defaults und loggt eine Warnung.
|
||
|
||
Relevante Abschnitte für den Driver:
|
||
|
||
```json
|
||
{
|
||
"kinematics": { "type": "arm3segmentlinearx" },
|
||
"motion": { "defaultFeedrate": 1000, "speedMode": "legacy" },
|
||
"controllers": {
|
||
"base": { "ip": "fluidNcBase.local", "port": 2300, "protocol": "telnet", "axes": ["x","y","z"] },
|
||
"elbow": { "ip": "fluidNcEllbow.local", "port": 5000, "protocol": "telnet", "axes": ["a",null,null] },
|
||
"hand": { "ip": "fluidNcHand.local", "port": 5000, "protocol": "telnet", "axes": ["c","e","b"] }
|
||
}
|
||
}
|
||
```
|
||
|
||
Armlängen werden aus dem `links`-Abschnitt abgeleitet (`Arm1.skeleton.to[1]` → l1 usw.).
|
||
Env-Variablen haben Vorrang vor robot.json (nützlich für Tests und schnelle Korrekturen).
|
||
|
||
Snapshots werden automatisch vor jedem PUT angelegt (`data/robot/robot_YYYYMMDD_HHmmss.json`).
|
||
Snapshots sind nicht im Repo (`.gitignore`), `robot.json` selbst schon.
|
||
|
||
### Telnet-Sender-Konfiguration
|
||
|
||
`startRobot.js` erzeugt die `TelnetSenderGRBL`-Instanzen dynamisch aus `cfg.controllers`
|
||
(geladen von `robot/RobotConfig.js`). Die Defaults entsprechen drei Controllern:
|
||
|
||
| Key | Default-IP | Port | Achsen |
|
||
|-----|-----------|------|--------|
|
||
| `base` | `fluidNcBase.local` | 2300 | `x, y, z` |
|
||
| `elbow` | `fluidNcEllbow.local` | 5000 | `a` |
|
||
| `hand` | `fluidNcHand.local` | 5000 | `c, e, b` |
|
||
|
||
IPs können per Env-Variable überschrieben werden (`GRBL_BASE_IP`, `GRBL_ELLBOW_IP`,
|
||
`GRBL_HAND_IP`). Alles andere (Port, Achsen, Controller-Anzahl) wird in `robot.json`
|
||
konfiguriert.
|
||
|
||
## Serverschnittstellen
|
||
|
||
### WebSocket Input Server
|
||
|
||
- Läuft auf `https://localhost:<PORT>`
|
||
- Erwartet WebSocket-Verbindungen und verarbeitet Nachrichten als G-Code oder Steuerbefehle
|
||
|
||
### Info Server
|
||
|
||
- Läuft auf `https://localhost:2098`
|
||
- Statische Dateien:
|
||
- `/`
|
||
- `/app.js`
|
||
- `/style.css`
|
||
- `/allApps.css`
|
||
- API-Endpunkte:
|
||
- `/api/status`
|
||
- `/api/position`
|
||
- `/api/robot` — `GET`: aktuelle `robot.json`; `PUT`: überschreibt sie (Auth erforderlich)
|
||
- `/api/robot/history` — Liste aller Snapshots
|
||
- `/api/robot/history/:ts` — einen bestimmten Snapshot abrufen
|
||
|
||
## Wichtige Dateien
|
||
|
||
- `startRobot.js`
|
||
- `server/InputWS.js`
|
||
- `server/InfoServer.js`
|
||
- `robot/RobotBase.js` — abstrakte Basisklasse / Interface-Vertrag (generische Infrastruktur)
|
||
- `robot/kinematics/Arm3SegmentLinearX.js` — konkrete Kinematik (Modell + Inverse/Vorwärts), Default-Arm
|
||
- `robot/kinematics/Arm3SegmentRotaryBase.js` — Kinematik für den Joy-IT „Grab-It" (Robot02), 5 Achsen + Greifer mit Drehbasis (`ROBOT_KINEMATICS=grabit`)
|
||
- `robot/KinematicsFactory.js` — wählt die Kinematik per Umgebungsvariable
|
||
- `robot/RobotConfig.js` — liest `data/robot/robot.json`, gibt typisierten Konfigurations-Record zurück
|
||
- `server/RobotConfigService.js` — REST-Endpunkte `/api/robot*` (lesen/schreiben, Snapshots, Auth)
|
||
- `data/robot/robot.json` — zentrale Roboter-Konfiguration (Single Source of Truth)
|
||
- `robot/GCodeParser.js` — wandelt rohe Nachrichten in strukturierte Befehlsobjekte
|
||
- `robot/RobotController.js` — wendet geparste Befehle auf das Modell an (Steuerlogik)
|
||
- `robot/GCode.js` — Fassade + Datei-Befehle
|
||
- `robot/TelnetSenderGRBL.js`
|
||
- `robot/fluidnc/FluidNCClient.js` — alternative WebSocket-basierte FluidNC-Anbindung mit Reconnect-Logik (noch nicht integriert)
|
||
- `GCodeFiles/` — enthalten Beispiel- und Log-G-Code-Dateien
|
||
|
||
## Laufzeitvoraussetzungen
|
||
|
||
- HTTPS-Zertifikate: `https/localhost.key` und `https/localhost.pem` (Passphrase via `HTTPS_PASSPHRASE`, Default `abcd`).
|
||
- `data/robot/robot.json` — wird beim Start eingelesen; fehlt die Datei, startet der Driver mit Defaults + Warnung.
|
||
- `logs/` wird beim Start automatisch angelegt (`fs.mkdirSync('logs', { recursive: true })` in `startRobot.js`).
|
||
- Telnet-Sender werden sofort beim Start als `cmdReceivers` registriert; interne Reconnect-Logik überbrückt verzögerte Controller-Verbindungen automatisch.
|
||
|
||
## ToDo / Open Tasks
|
||
|
||
Architektur- und Refactoring-Aufgaben sind in `doc/ToDo_*.md` dokumentiert:
|
||
|
||
| Datei | Thema | Status |
|
||
|---|---|---|
|
||
| `doc/ToDo_1_Parsing.md` | G-Code-Parser-Schicht einführen | ✅ erledigt |
|
||
| `doc/ToDo_2_Anbindung.md` | Sender-Interface und Orchestrierung | ✅ erledigt |
|
||
| `doc/ToDo_3_Config.md` | Zentralisierte Konfiguration | offen |
|
||
| `doc/ToDo_4_GCode.md` | G-Code- und Datei-Handling trennen | offen |
|
||
| `doc/ToDo_5_API.md` | WebSocket-Antwortlogik strukturieren | ✅ erledigt |
|
||
| `doc/ToDo_6_RobotController.md` | RobotController-Klasse einführen | ✅ erledigt |
|
||
| `doc/ToDo_6a_Speed.md` | Speed-Steuerung: Schalter, `calculateSpeeds()`-Fix, koordinierte Feedrate | ✅ erledigt (WS-Sender offen) |
|
||
| `doc/ToDo_6b_FileHandling.md` | File-Handling: fehlende Befehle, Cursor im Speicher, Fehler-Feedback | offen |
|
||
| `doc/ToDo_7_Tests.md` | Testabdeckung und Stabilität | teilweise |
|
||
| `doc/ToDo_8_Bugs.md` | Bekannte konkrete Bugs | teilweise |
|
||
| `doc/ToDo_9_HardwareFeedback.md` | Hardware-Feedback-Loop (GRBL-Antworten, Command-Queue, Positionsabgleich) | teilweise (Baustein Port→Motor ✅, Pakete 1–6 offen) |
|
||
| `doc/ToDo_10_VerbindungsVerlust.md` | Verbindungsverlust erkennen, Watchdog, UI-Statusanzeige | offen |
|
||
| `doc/ToDo_12_InverseKinematikConfig_ROADMAP.md` | Austauschbare Kinematik: RobotBase, KinematicsFactory, Grab-It | ✅ erledigt |
|
||
| `doc/ToDo_14_robot_json_service.md` | robot.json als REST-Service, RobotConfigService, RobotConfig | teilweise (Schritte 1–4 in appRobotDriver ✅, Schritte 5–7 offen) |
|
||
| `doc/ToDo_49_Cleanup.md` | Pre-Release-Cleanup: tote Code, Zertifikate, ToDos, README | offen |
|
||
|
||
### Empfohlene Bearbeitungsreihenfolge
|
||
|
||
```
|
||
ToDo_8 Bugs beheben — kurz, blockiert nichts anderes
|
||
ToDo_3 Config — Fundament für alles Weitere
|
||
ToDo_1 Parser ┐
|
||
ToDo_6 RobotController ┘ zusammen, da eng verzahnt
|
||
ToDo_4 Datei-Handling — danach, klar abgrenzbar
|
||
ToDo_6a Speed-Steuerung — calculateSpeeds bugfix, dann Sender-Integration
|
||
ToDo_6b File-Handling Detail — fehlende F-Befehle, Cursor im Speicher
|
||
ToDo_2 Sender-Interface — mit Entscheidung: Telnet vs. FluidNC-WebSocket
|
||
ToDo_9 Hardware-Feedback — baut auf ToDo_2 auf
|
||
ToDo_10 Verbindungsverlust — baut auf ToDo_2 auf, parallel zu ToDo_9 möglich
|
||
ToDo_5 API — parallel zu ToDo_2/4 möglich
|
||
ToDo_7 Tests — begleitend zu allen obigen
|
||
```
|
||
|
||
Kurzübersicht weiterer offener Punkte:
|
||
|
||
- [ ] Dokumentation der vollständigen G-Code-Syntax erweitern
|
||
- [ ] `FFirst`/`FLast`-Befehle in `GCode.receiveFC()` implementieren
|
||
- [ ] `ROBOT_USE_SPEED_CALC` und `motorSpeeds` im echten Betrieb prüfen
|
||
- [ ] `FluidNCClient.js` evaluieren: als Ersatz oder Ergänzung zu `TelnetSenderGRBL`?
|
||
- [x] HTTPS-Passphrase aus Env-Variable (`HTTPS_PASSPHRASE`) — erledigt
|
||
- [x] `logs/`-Verzeichnis beim Start automatisch anlegen — erledigt (`startRobot.js`)
|