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.jsstartet zwei HTTPS-Server:- Eingabe-Server + WebSocket für G-Code und Steuerbefehle
- Info-Server für Status, Position und einfache Weboberfläche
server/InputWS.jsempfängt Nachrichten von WebSocket-Clients, prüft sie auf G-Code oder Datei-Kommandos und gibt Positionsdaten zurück.robot/GCode.jsverarbeitet G-Code, übersetzt ihn in Roboter-Koordinaten und triggertrobot.sendCommand().robot/RobotBase.jsist die abstrakte Basisklasse / der Interface-Vertrag: generische Infrastruktur (Zustand,sendCommand, Motor-Geschwindigkeiten) plus die zwei abstrakten Kinematik-Methoden.robot/kinematics/Arm3SegmentLinearX.jsist die konkrete Kinematik (Inverse + Vorwärts) für den aktuellen Arm. Die Auswahl der Kinematik erfolgt überrobot/KinematicsFactory.js(UmgebungsvariablenROBOT_KINEMATICS/ROBOT_KINEMATICS_PARAMS). Siehedoc/ToDo_12_InverseKinematikConfig_ROADMAP.md.robot/RobotConfig.jsliestdata/robot/robot.jsonbeim Start synchron und gibt einen typisierten Konfigurations-Record zurück (Kinematik-Parameter, Bewegungs-Defaults, Controller-Endpunkte). Env-Variablen überschreiben die JSON-Werte.server/RobotConfigService.jsstelltGET/PUT /api/robotundGET /api/robot/historyüber den InfoServer bereit (Single Source of Truth für alle Apps). Schreibzugriffe erfordernAuthorization: Bearer <ROBOT_API_KEY>.robot/TelnetSenderGRBL.jsformatiert 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,G28G92(wird intern alsM92verarbeitet — setzt Motorposition ohne Bewegung)- Messungen in
X,Y,Z,A,B,C,E,F M1für direkte Motor-Koordinaten
- Datei-Kommandos:
FPoint,FPlus,FMinus,FShow,FList,FLoad <file>,FSave <file>,FClearFFirst,FLast— erkannt, aber noch nicht implementiertM20,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()
- Gruppiert Zeilen, unterstützt Inline-Jogging (
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.
- Nachdem ein G-Code-Befehl verarbeitet wurde, sendet das System
- Telnet-Ausgabe an GRBL/FluidNC-Geräte
TelnetSenderGRBL.execCommand()erzeugtG1/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
- Standard:
GRBL_BASE_IP- Standard:
fluidNcBase.local - Zielhost für den ersten Telnet-Sender
- Standard:
GRBL_ELLBOW_IP- Standard:
fluidNcEllbow.local - Zielhost für den Ellbogen-Sender
- Standard:
GRBL_HAND_IP- Standard:
fluidNcHand.local - Zielhost für den Hand-Sender
- Standard:
ROBOT_DEFAULT_FEEDRATE- Standard:
1000(mm/min) - Default-Feedrate für
G1-Befehle, wenn keineF-Angabe vorhanden ist
- Standard:
ROBOT_SPEED_MODE- Werte:
legacy(Standard) odercorrect legacy: alte Speed-Regelung — jeder Sender erhält die kartesische FeedrateFunverändert (Verhalten exakt wie bisher).correct: koordinierte Feedrate pro Sender, sodass alle Controller den Bewegungsschritt gleichzeitig beenden. Aktiviert automatischcalculateSpeeds().- Details:
doc/ToDo_6a_Speed.md
- Werte:
ROBOT_USE_SPEED_CALC- Werte:
true,1oder sonst leer - Interner Schalter, ob
robot.calculateSpeeds()rechnet. Ändert allein nicht die Sender-Ausgabe — dafür istROBOT_SPEED_MODE=correctnötig. Vom Korrekt-Modus automatisch aktiviert.
- Werte:
ROBOT_KINEMATICS- Standard:
arm3segmentlinearx - Bezeichner der Kinematik-Klasse (case-insensitive). Bekannte Werte:
arm3segmentlinearx,grabit/robot02(Joy-IT Grab-It). Unbekannter Bezeichner → Fehler beim Start.
- Standard:
ROBOT_KINEMATICS_PARAMS- JSON-Objekt mit Konstruktor-Parametern, z. B.
{"l1":250,"l2":264,"l3":100}. Überschreibt die Werte ausrobot.json. Wird von der Factory als viertes Argument an den Konstruktor weitergereicht (erlaubt kinematik-spezifische Parameter wiebaseHeight).
- JSON-Objekt mit Konstruktor-Parametern, z. B.
ROBOT_API_KEY- Statischer Bearer-Token für
PUT /api/robot. Fehlt die Variable, generiertRobotConfigServicebeim ersten Start einen zufälligen Key und speichert ihn indata/robot/.apikey(nicht im Repo). Der Key wird beim Start einmalig geloggt.
- Statischer Bearer-Token für
SHELLY_URL- URL für den Shelly Smart Plug Emergency-Stop:
http://<IP>/rpc/Switch.Set?id=0&on=false - Überschreibt
controllers.emergencyStop.urlausrobot.json(analog zuGRBL_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
- URL für den Shelly Smart Plug Emergency-Stop:
HTTPS-Konfiguration
https/localhost.keyhttps/localhost.pem- Passphrase: Env-Variable
HTTPS_PASSPHRASE, Defaultabcd
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:
{
"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: aktuellerobot.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:$Xan alle FluidNC (nach Strom-Neustart)
Wichtige Dateien
startRobot.jsserver/InputWS.jsserver/InfoServer.jsrobot/RobotBase.js— abstrakte Basisklasse / Interface-Vertrag (generische Infrastruktur)robot/kinematics/Arm3SegmentLinearX.js— konkrete Kinematik (Modell + Inverse/Vorwärts), Default-Armrobot/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 Umgebungsvariablerobot/RobotConfig.js— liestdata/robot/robot.json, gibt typisierten Konfigurations-Record zurückserver/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 Befehlsobjekterobot/RobotController.js— wendet geparste Befehle auf das Modell an (Steuerlogik)robot/GCode.js— Fassade + Datei-Befehlerobot/TelnetSenderGRBL.jsrobot/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/— enthalten Beispiel- und Log-G-Code-Dateien
Laufzeitvoraussetzungen
- HTTPS-Zertifikate:
https/localhost.keyundhttps/localhost.pem(Passphrase viaHTTPS_PASSPHRASE, Defaultabcd). 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 })instartRobot.js).- Telnet-Sender werden sofort beim Start als
cmdReceiversregistriert; 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/draft_filehandeling.md |
File-Handling als externes Projekt appRobotFileservice (Driver als Gateway, FCode-Pass-through) |
Entwurf |
doc/draft_filehandeling_API.md |
API der appRobotFileservice (Programme, aktiver Cursor, Teaching/Playback) |
Entwurf |
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/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
FFirst/FLast(und übriges File-Handling) → ausgelagert inappRobotFileservice(siehedoc/draft_filehandeling.md)ROBOT_USE_SPEED_CALCundmotorSpeedsim echten Betrieb prüfenFluidNCClient.jsevaluieren: als Ersatz oder Ergänzung zuTelnetSenderGRBL?- HTTPS-Passphrase aus Env-Variable (
HTTPS_PASSPHRASE) — erledigt logs/-Verzeichnis beim Start automatisch anlegen — erledigt (startRobot.js)