Files
appRobotDriver/README.md
2026-06-14 11:18:46 +02:00

280 lines
15 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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.
# 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, routet G-Code-Befehle lokal und leitet FCodes via `robot/FCodeClient.js` an `appRobotFileservice` weiter.
- `robot/GCode.js` verarbeitet G-Code, übersetzt ihn in Roboter-Koordinaten und triggert `robot.sendCommand()` (kein Datei-Handling mehr).
- `robot/FCodeClient.js` übersetzt FCodes (`FPoint`, `FPlus`, …) in REST-Aufrufe an `appRobotFileservice` (Gateway-Funktion des Drivers).
- `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
- FCodes (Datei-/Programm-Befehle) — werden durch den Driver an `appRobotFileservice` weitergeleitet:
- `FPoint`, `FPlus`, `FMinus`, `FFirst`, `FLast`, `FGoto <n>`
- `FShow [id]`, `FList`, `FLoad <id>`, `FSave <name>`, `FClear`
- `FPlay`, `FStop`
- Vollständige API: `doc/fileserviceAPI.md`
### 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 FCodes leitet der Driver das Ergebnis von `appRobotFileservice` weiter (Stepping-Befehle zusätzlich als Pose-Broadcast nach lokaler Ausführung).
- 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 Bewegungs­schritt
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.
- `FILESERVICE_URL`
- Standard: `http://appRobot_Fileservice:2100`
- URL der `appRobotFileservice` — wird von `robot/FCodeClient.js` verwendet.
Im Container-Netz entspricht das dem Docker-Dienstnamen aus dem Portainer-Stack.
- `SHELLY_URL`
- URL für den Shelly Smart Plug Emergency-Stop: `http://<IP>/rpc/Switch.Set?id=0&on=false`
- Überschreibt `controllers.emergencyStop.url` aus `robot.json` (analog zu `GRBL_BASE_IP`).
- **Wichtig in Docker:** `.local`-mDNS-Hostnamen werden im Container nicht aufgelöst —
stattdessen die echte IP verwenden (z.B. `http://192.168.0.99/rpc/Switch.Set?id=0&on=false`).
- Details: `doc/15_EmergencyStop_done.md`
### 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"], "heartbeatInterval": 10000 },
"elbow": { "ip": "fluidNcEllbow.local", "port": 5000, "protocol": "telnet", "axes": ["a",null,null], "heartbeatInterval": 10000 },
"hand": { "ip": "fluidNcHand.local", "port": 5000, "protocol": "telnet", "axes": ["c","e","b"], "heartbeatInterval": 10000 },
"emergencyStop": {
"protocol": "shelly",
"url": "http://<SHELLY-IP>/rpc/Switch.Set?id=0&on=false",
"urlOn": "http://<SHELLY-IP>/rpc/Switch.Set?id=0&on=true",
"urlStatus": "http://<SHELLY-IP>/rpc/Switch.GetStatus?id=0"
}
}
}
```
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 | `heartbeatInterval` |
|-----|-----------|------|--------|---------------------|
| `base` | `fluidNcBase.local` | 2300 | `x, y, z` | 10 000 ms |
| `elbow` | `fluidNcEllbow.local` | 5000 | `a` | 10 000 ms |
| `hand` | `fluidNcHand.local` | 5000 | `c, e, b` | 10 000 ms |
IPs können per Env-Variable überschrieben werden (`GRBL_BASE_IP`, `GRBL_ELLBOW_IP`,
`GRBL_HAND_IP`). Alles andere (Port, Achsen, Controller-Anzahl, Heartbeat) wird in
`robot.json` konfiguriert.
**`heartbeatInterval`** (ms) steuert, wie oft `?` an den FluidNC-Controller gesendet wird.
Der Sender erkennt eine tote Verbindung (z.B. nach NotAus), wenn zwei aufeinanderfolgende
Heartbeats ohne Antwort bleiben (`deadTimeout = 2 × heartbeatInterval`). Danach wird der
Socket geschlossen und der bestehende Reconnect-Mechanismus startet automatisch.
## 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` — Sender-Status inkl. `isGCodeReceiver`-Flag
- `/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
- `/api/power-status` — Shelly-Schaltzustand (`armed: true/false`, Spannung, Leistung)
- `/api/emergency-stop``POST`: Feed Hold `!` an alle FluidNC + Shelly Strom AUS
- `/api/power-on``POST`: Shelly Strom EIN
- `/api/alarm-unlock``POST`: `$X` an alle FluidNC (nach Strom-Neustart)
## 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 für G-Code-Verarbeitung (Bewegung, Pose, Logging)
- `robot/FCodeClient.js` — Gateway: übersetzt FCodes in REST-Aufrufe an `appRobotFileservice`
- `robot/TelnetSenderGRBL.js`
- `robot/ShellyEmergencyStop.js` — steuert Shelly Smart Plug als Emergency-Stop-Aktor (HTTP GET, kein GCode)
- `robot/fluidnc/FluidNCClient.js` — alternative WebSocket-basierte FluidNC-Anbindung mit Reconnect-Logik (noch nicht integriert)
- `GCodeFiles/` — G-Code-Programme werden jetzt in `appRobotFileservice` verwaltet
## 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 | ✅ ausgelagert → `appRobotFileservice` |
| `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 | ✅ ausgelagert → `appRobotFileservice` |
| `doc/fileserviceAPI.md` | REST-API der `appRobotFileservice` (Programme, aktiver Cursor, Teaching/Playback) | ✅ implementiert |
| `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 16 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 14 in appRobotDriver ✅, Schritte 57 offen) |
| `doc/15_EmergencyStop_done.md` | Emergency Stop: Shelly + FluidNC Feed Hold, API, UI, Restart-Ablauf | ✅ erledigt |
| `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 — ausgelagert → appRobotFileservice (siehe drafts)
ToDo_6a Speed-Steuerung — calculateSpeeds bugfix, dann Sender-Integration
ToDo_6b File-Handling Detail — ausgelagert → appRobotFileservice (siehe drafts)
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
- [x] `FFirst`/`FLast` und gesamtes File-Handling → ausgelagert in `appRobotFileservice` (siehe `doc/fileserviceAPI.md`)
- [ ] `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`)