Files
appRobotDriver/doc/Info_Config.md
2026-06-26 08:27:50 +02:00

195 lines
8.4 KiB
Markdown

# 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:
```json
"kinematics": {
"_owner": "appRobotDriver",
"type": "arm3segmentlinearx"
}
```
Kein Duplizieren von `links`-Daten. `RobotConfig.js` liest z.B.:
- `links.Arm1.skeleton.to[1]` → l1
- `links.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:
```json
"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 aus `motion.defaultFeedrate`.
- `controller` — Verweis auf den Schlüssel in `controllers`. 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).
```json
"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:
```json
"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:
```js
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
```js
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`, `controllers` eintragen
- In jedem `jointToParent`: `feedrate` und `controller` ergänzen
- Hinweis: `controllers` enthält explizite `axes`-Reihenfolge (Baum-Traversal liefert für Hand-Controller falsche Reihenfolge)
- Beide Kopien aktualisiert: `appRobotRendering/data/robot/robot.json` und `appRobotDriver/data/robot/robot.json`
### ✅ Schritt 2 — `robot/RobotConfig.js` anlegen
- Liest robot.json synchron
- Leitet l1/l2/l3 aus `links.*.skeleton.to` ab (behebt alten Bug: `Ellbow.size[0]` existierte nicht)
- Gibt `axesByController(key)` aus `controllers[key].axes` zurü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`: `readArmLengthsFromConfig` entfernt, ersetzt durch `RobotConfig.load()`; Controller-Setup config-getrieben (keine hardcodierten IPs/Ports/Achsen mehr)
- `RobotBase.js`: akzeptiert optionalen `config`-Parameter im Konstruktor; Env-Vars bleiben als Fallback
- `Arm3SegmentLinearX` und `Arm3SegmentRotaryBase`: reichen `config`/`params` an `super()` 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
- `speedMode` Details → ToDo 6a