8.4 KiB
ToDo 3 — Konfiguration
Ausgangslage
Konfiguration ist aktuell über drei Orte verstreut:
| Ort | Beispiele |
|---|---|
| Hardcodiert im Code | Controller-Ports (2300, 5000), Passphrase 'abcd' |
| Env-Variablen | GRBL_BASE_IP, ROBOT_DEFAULT_FEEDRATE, PORT, … |
robot.json |
Geometrie, Rendering-Parameter, Pose-Estimation-Optionen |
Ergebnis: Wer einen Roboter in einer anderen Umgebung betreibt, muss Code lesen, um zu wissen was anzupassen ist. Und es ist unklar, welches Programm für welchen Abschnitt zuständig ist.
Architektur-Entscheidung
robot.json ist die einzige Wahrheitsquelle für alles, was roboter-spezifisch ist.
Eine robot.json beschreibt einen konkreten Roboter vollständig — sie kann weitergegeben werden, wenn der Roboter in einer anderen Umgebung eingesetzt wird.
Env-Variablen bleiben nur für deployment-spezifische Werte, die nichts mit dem Roboter selbst zu tun haben:
| Variable | Grund |
|---|---|
PORT (2095/2098) |
Server-Port ändert sich je Deployment, nicht je Roboter |
HTTPS_KEY_PATH, HTTPS_CERT_PATH, HTTPS_PASSPHRASE |
Sicherheits-Infrastruktur |
ROBOT_API_KEY |
Geheimnis, darf nie in einer weitergebbaren Datei stehen |
Änderungen an robot.json
1 — Kinematik-Typ (kinematics)
Die Kinematik-Parameter (Armlängen, Achsen, Gelenk-Kette) sind bereits vollständig in links enthalten und werden von robot/RobotConfig.js daraus abgeleitet. Einzig der Name des Solver-Algorithmus fehlt noch:
"kinematics": {
"_owner": "appRobotDriver",
"type": "arm3segmentlinearx"
}
Kein Duplizieren von links-Daten. RobotConfig.js liest z.B.:
links.Arm1.skeleton.to[1]→ l1links.Ellbow.skeleton.to[0]→ l3
2 — Feedrate und Controller-Zuordnung in jointToParent
Beide Infos gehören direkt zum Gelenk, weil sie die Hardware-Eigenschaft eines konkreten Joints beschreiben:
"jointToParent": {
"name": "Slider",
"type": "linear",
"axis": [1, 0, 0],
"origin": [0, 0, 16],
"variable": "x",
"feedrate": 2000,
"controller": "base"
}
feedrate— maximale Vorschubgeschwindigkeit dieses Joints in mm/min (linear) oder °/min (revolute). Überschreibt den globalen Default ausmotion.defaultFeedrate.controller— Verweis auf den Schlüssel incontrollers. Darüber weiss der Driver, welche Variable auf welchem Controller-Kanal liegt. Die heutigen hardcodierten Achszuordnungen ('x','y','z'/'a',null,null/ …) werden damit überflüssig.
3 — Controller-Endpunkte (controllers)
Top-Level-Abschnitt, nur IP und Port. Die Achszuordnung ergibt sich aus den controller-Verweisen in den Joints (kein Duplikat).
"controllers": {
"_owner": "appRobotDriver",
"base": { "ip": "fluidNcBase.local", "port": 2300, "protocol": "telnet" },
"elbow": { "ip": "fluidNcEllbow.local", "port": 5000, "protocol": "telnet" },
"hand": { "ip": "fluidNcHand.local", "port": 5000, "protocol": "telnet" }
}
Der Driver liest controllers für IP/Port, scannt dann links nach jointToParent.controller === "base" und bekommt so ["x", "y", "z"] als Achsliste.
4 — Globale Bewegungs-Defaults (motion)
Werte, die für alle Joints gelten, sofern kein feedrate im Joint hinterlegt ist. Ausserdem Software-Flags, die keine natürliche Heimat in einem einzelnen Joint haben:
"motion": {
"_owner": "appRobotDriver",
"defaultFeedrate": 2300,
"speedMode": "legacy",
"speedModeOptions": ["legacy", "correct"]
}
speedMode und defaultFeedrate lösen die Env-Vars ROBOT_DEFAULT_FEEDRATE und ROBOT_SPEED_MODE ab.
Interne Abhängigkeiten in robot.json
Mit controller-Verweisen in den Joints entstehen interne Cross-References. Die robot.json darf solche haben — das ist bewusste Design-Entscheidung, die Redundanz vermeidet. Ein späterer validator.py muss diese Konsistenz prüfen:
| Referenz | Regel |
|---|---|
jointToParent.controller → controllers.* |
Jeder Verweis muss auf einen existierenden Controller-Schlüssel zeigen |
| Marker-IDs | Jede ID darf global nur einmal vergeben sein |
parent in links |
Muss auf einen existierenden Link zeigen, kein Zyklus |
Verantwortlichkeits-Tabelle
Jeder Abschnitt hat genau einen Eigentümer (das Programm, das diesen Abschnitt schreiben darf). Konsumenten lesen nur.
| Abschnitt | Eigentümer (_owner) |
Konsumenten |
|---|---|---|
kinematics |
appRobotDriver | appRobotDriver (via RobotConfig.js) |
motion |
appRobotDriver | appRobotDriver |
controllers |
appRobotDriver | appRobotDriver |
units |
appRobotDriver | alle |
links (inkl. jointToParent.feedrate, .controller) |
appRobotDriver — Homing darf Marker-Positionen/-Normalen aktualisieren (via PUT /api/robot), aber keine Driver-Felder (feedrate, controller) verändern |
alle |
vision_config |
— | appRobotHoming |
constraint_rules, observation_weighting, multiview_calculation, pose_estimation, state_pose_params |
— | appRobotHoming |
renderingInfo |
— | appRobotRendering |
robot_test_poses, test_camera_positions/targets |
— | appRobotHoming, appRobotRendering |
defaultPosition |
— | appRobotDriver, appRobotRendering |
coordinateSystem |
— | alle |
Sektionen ohne _owner sind manuell konfiguriert und werden von keinem Programm automatisch überschrieben. Der Validator prüft, dass Homing in links nur die erlaubten Felder (position, normal, spin, size in Markern) verändert.
Zugriffsmuster
appRobotDriver — neues Modul robot/RobotConfig.js
Der Driver liest robot.json synchron beim Start (direkt vom Disk, vor dem HTTP-Server-Start). RobotConfig.js ist der einzige Ort im Driver-Code, der robot.json kennt:
const cfg = RobotConfig.load(); // synchron, gibt typisierten Record zurück
cfg.kinematics.type // → 'arm3segmentlinearx'
cfg.kinematics.l1 // → 250 (abgeleitet aus links.Arm1.skeleton)
cfg.motion.defaultFeedrate // → 2300
cfg.controllers // → { base: {ip, port}, elbow: {ip, port}, hand: {ip, port} }
cfg.axesByController('base') // → ['x', 'y', 'z'] (abgeleitet aus links)
Alle process.env-Lesungen für roboter-spezifische Werte wandern hierher. Env-Vars bleiben als Override-Ebene (Env hat Vorrang vor robot.json — nützlich für Tests und schnelle Korrekturen ohne Datei-Änderung).
Alle anderen Apps — HTTP GET
const robot = await fetch('https://appRobotDriver:2098/api/robot').then(r => r.json());
Kein eigenes Zugriffs-Modul nötig.
Umsetzungsschritte
✅ Schritt 1 — robot.json erweitern
- Abschnitte
kinematics,motion,controllerseintragen - In jedem
jointToParent:feedrateundcontrollerergänzen - Hinweis:
controllersenthält expliziteaxes-Reihenfolge (Baum-Traversal liefert für Hand-Controller falsche Reihenfolge) - Beide Kopien aktualisiert:
appRobotRendering/data/robot/robot.jsonundappRobotDriver/data/robot/robot.json
✅ Schritt 2 — robot/RobotConfig.js anlegen
- Liest robot.json synchron
- Leitet l1/l2/l3 aus
links.*.skeleton.toab (behebt alten Bug:Ellbow.size[0]existierte nicht) - Gibt
axesByController(key)auscontrollers[key].axeszurück - Gibt typisierten Record mit Fallbacks zurück
- Env-Override-Ebene: GRBL_*_IP, ROBOT_DEFAULT_FEEDRATE, ROBOT_SPEED_MODE, ROBOT_USE_SPEED_CALC
✅ Schritt 3 — startRobot.js und RobotBase.js umstellen
startRobot.js:readArmLengthsFromConfigentfernt, ersetzt durchRobotConfig.load(); Controller-Setup config-getrieben (keine hardcodierten IPs/Ports/Achsen mehr)RobotBase.js: akzeptiert optionalenconfig-Parameter im Konstruktor; Env-Vars bleiben als FallbackArm3SegmentLinearXundArm3SegmentRotaryBase: reichenconfig/paramsansuper()durch
✅ Schritt 4 — HTTPS-Passphrase aus Env-Variable
HTTPS_PASSPHRASE lesen statt hardcodiertem 'abcd'. Default bleibt 'abcd' für lokale Entwicklung.
✅ Schritt 5 — logs/-Verzeichnis automatisch anlegen
fsModule.mkdirSync?.('logs', { recursive: true }) in startRobot.js nach erfolgreichem HTTPS-Load. Bestehende ensureLogDir() in InputWS.js bleibt als zweite Absicherung.
Nicht in dieser ToDo
- JSON-Schema-Validierung (separates Ticket, koordiniert mit dem geplanten
validator.py) - Laufzeit-Reload von robot.json ohne Neustart
speedModeDetails → ToDo 6a