161 lines
6.5 KiB
Markdown
161 lines
6.5 KiB
Markdown
# Roadmap 12 — Austauschbare Kinematik
|
||
|
||
## Ziel
|
||
|
||
Der `appRobotDriver` soll als generischer G-Code-Treiber für beliebige Roboterarme
|
||
funktionieren. Die Kinematik ist der einzige arm-spezifische Teil — alles andere
|
||
(G-Code, WebSocket, Sender, Konfiguration) ist roboter-unabhängig.
|
||
|
||
## Konventionen (festgelegt)
|
||
|
||
- **Workspace-Koordinaten:** `x, y, z, phi, theta, psi` + `e` (Greifer) — gilt für alle
|
||
6-DOF-Arme mit Greifer. Das ist der implizite Vertrag dieses Frameworks.
|
||
- **Motoranzahl:** 7 Slots (`x, y, z, a, b, c, e` in `RobotMotorPosition`) bleiben fest.
|
||
Das Framework ist für 6-DOF + Greifer ausgelegt.
|
||
- **Ordner:** `robot/kinematics/` (nicht `inverseKinematics/` — enthält beide Richtungen)
|
||
- **Klassenname:** beschreibend für die physikalische Struktur, z. B. `Arm3SegmentLinearX`
|
||
|
||
---
|
||
|
||
## Dateistruktur (Zielzustand)
|
||
|
||
```
|
||
robot/
|
||
├── RobotBase.js ← Interface + generische Infrastruktur
|
||
├── KinematicsFactory.js ← lädt Kinematik-Klasse anhand Env-Variable
|
||
└── kinematics/
|
||
├── Arm3SegmentLinearX.js ← aktuelle Implementierung
|
||
└── <NextRobot>.js ← zukünftige Implementierungen
|
||
```
|
||
|
||
> **Update (umgesetzt):** Der ursprünglich geplante dauerhafte Kompatibilitäts-Alias
|
||
> `robot/Robot.js` wurde **nicht** beibehalten, sondern nach Abschluss von Phase 0–2
|
||
> **entfernt**. Tests importieren direkt `kinematics/Arm3SegmentLinearX` bzw.
|
||
> `RobotBase`; Produktivcode geht über `KinematicsFactory`. Die folgenden Abschnitte
|
||
> zur Transition über `Robot.js` sind daher historisch.
|
||
|
||
## Wo ist das Interface?
|
||
|
||
**`RobotBase` ist das Interface** — als abstrakte Basisklasse (JavaScript-Idiom).
|
||
Es definiert zwei Dinge:
|
||
1. Die **Infrastruktur**, die jede Implementierung erbt (State, `sendCommand`, ...)
|
||
2. Den **Vertrag**: zwei Methoden, die jede Implementierung überschreiben *muss*
|
||
|
||
`RobotBase` ist die einzige Klasse, die alle anderen Module (`GCode.js`, `InputWS.js`,
|
||
Sender, ...) kennen müssen. Sie importieren nie eine konkrete Kinematik.
|
||
|
||
## Wie greift der restliche Code auf den Roboter zu?
|
||
|
||
**Heute und während der Transition:**
|
||
```
|
||
startRobot.js → require('./robot/Robot') → Robot.js (Alias) → Arm3SegmentLinearX
|
||
GCode.js → bekommt robot als Parameter → sieht nur RobotBase-Methoden
|
||
InputWS.js → bekommt robot als Parameter → sieht nur RobotBase-Methoden
|
||
```
|
||
|
||
`GCode.js`, `InputWS.js` und alle Sender erhalten `robot` bereits als Parameter —
|
||
sie importieren `Robot.js` gar nicht. **Für sie ändert sich nichts.**
|
||
|
||
**Langfristig (nach Abschluss Phase 2):**
|
||
```
|
||
startRobot.js → KinematicsFactory → instantiiert Arm3SegmentLinearX (oder anderen)
|
||
robot/Robot.js → dauerhafter Alias für RobotBase (nicht mehr für eine Implementierung)
|
||
```
|
||
|
||
`robot/Robot.js` bleibt erhalten, zeigt aber auf `RobotBase`:
|
||
```js
|
||
// robot/Robot.js — dauerhaft
|
||
module.exports = require('./RobotBase');
|
||
```
|
||
|
||
Damit kann externer Code weiterhin `require('./robot/Robot')` schreiben und bekommt
|
||
die Basisklasse — z. B. für `instanceof`-Checks oder zum Ableiten in Tests.
|
||
|
||
---
|
||
|
||
## Phase 0 — `RobotBase` und Interface-Vertrag
|
||
|
||
`Robot.js` enthält heute zwei Dinge: generische Infrastruktur und arm-spezifische Kinematik.
|
||
Der Schnitt:
|
||
|
||
**`RobotBase` (generisch, nie überschreiben):**
|
||
- Zustandsvariablen: `x, y, z, phi, theta, psi, e, feedrate, moveRelative`
|
||
- Motor-Zustand: `xMotor, alpha, beta, a, b, c, eMotor` + Changed-Flags
|
||
- `sendCommand()`, `createMotorPosition()`, `calculateSpeeds()`
|
||
- `cmdReceivers`, `savedPoints`
|
||
|
||
**Interface-Vertrag (abstrakt, muss überschrieben werden):**
|
||
```js
|
||
calculateAngles3D() // Workspace → Motorwinkel (schreibt auf this.*)
|
||
calculatePositionFromMotorAngles() // Motorwinkel → Workspace (schreibt auf this.*)
|
||
```
|
||
|
||
- [x] `robot/RobotBase.js` anlegen — generische Infrastruktur aus `Robot.js`
|
||
- [x] Beide Kinematik-Methoden in `RobotBase` als Stub mit `throw new Error('not implemented')`
|
||
- [x] JSDoc: Interface-Vertrag dokumentieren
|
||
- [x] `rotateAroundAxis()` wandert in `RobotBase` als geschützte Hilfsmethode
|
||
|
||
---
|
||
|
||
## Phase 1 — `Arm3SegmentLinearX` als erste Implementierung
|
||
|
||
```
|
||
robot/
|
||
├── RobotBase.js
|
||
└── kinematics/
|
||
└── Arm3SegmentLinearX.js ← bisheriger Robot.js-Kinematik-Teil
|
||
```
|
||
|
||
- [x] `robot/kinematics/Arm3SegmentLinearX.js` anlegen
|
||
- `class Arm3SegmentLinearX extends RobotBase`
|
||
- Konstruktor: `constructor(l1, l2, l3)` → `super()` + Längen
|
||
- `calculateAngles3D()` — unverändert übernommen
|
||
- `calculatePositionFromMotorAngles()` — unverändert übernommen
|
||
- [x] `robot/Robot.js` wurde zunächst Kompatibilitäts-Alias und anschließend
|
||
**entfernt** (siehe Update-Hinweis oben). Tests importieren direkt
|
||
`./kinematics/Arm3SegmentLinearX`.
|
||
- [x] Alle bestehenden Tests müssen grün bleiben — kein Verhalten ändert sich
|
||
(`Robot.Kinematics.RoundTrip.test.js` ist das primäre Sicherheitsnetz)
|
||
|
||
---
|
||
|
||
## Phase 2 — Konfiguration über Umgebungsvariable
|
||
|
||
```yaml
|
||
# docker-compose.yml
|
||
environment:
|
||
ROBOT_KINEMATICS: arm3segmentlinearx
|
||
ROBOT_KINEMATICS_PARAMS: '{"l1": 250, "l2": 264, "l3": 100}'
|
||
```
|
||
|
||
- [x] `ROBOT_KINEMATICS` — Bezeichner der Kinematik-Klasse (Default: `arm3segmentlinearx`)
|
||
- [x] `ROBOT_KINEMATICS_PARAMS` — JSON mit Konstruktor-Parametern
|
||
- [x] `KinematicsFactory.js` (`createRobotFromEnv`), eingebunden in `startRobot.js`:
|
||
```js
|
||
const robot = createRobotFromEnv(processEnv, { l1: 250, l2: 264, l3: 100 });
|
||
```
|
||
- [x] Unbekannte Kinematik → klare Fehlermeldung beim Start, kein silent fail
|
||
- [ ] Neue Variablen ins zentrale Config-Modul aufnehmen (koordinieren mit `ToDo_3_Config`)
|
||
→ **offen:** `ToDo_3_Config` ist noch nicht umgesetzt. Die Factory liest `process.env`
|
||
vorerst direkt (gleicher Stil wie `ROBOT_DEFAULT_FEEDRATE`); das zentrale Config-Modul
|
||
kann die beiden Variablen später übernehmen. In `docker-compose.yaml` bereits dokumentiert.
|
||
|
||
---
|
||
|
||
## Phase 3 — Zweite Kinematik-Implementierung
|
||
|
||
Erst wenn ein konkreter zweiter Roboter definiert ist.
|
||
|
||
- [ ] Physikalische Spezifikation dokumentieren (DOF, Achsen, Gelenkreihenfolge)
|
||
- [ ] `robot/kinematics/<Name>.js` anlegen — nur die zwei Kinematik-Methoden
|
||
- [ ] RoundTrip-Tests für die neue Implementierung schreiben
|
||
- [ ] Prüfen ob die 7 Motor-Slots ausreichen; falls nicht → `RobotMotorPosition` anpassen
|
||
|
||
---
|
||
|
||
## Abhängigkeiten
|
||
|
||
- Phase 1 ist unabhängig von allen anderen ToDos — kann sofort angegangen werden
|
||
- Phase 2 koordiniert mit `ToDo_3_Config`
|
||
- Phase 3 hat keine zeitliche Vorgabe — wird bei Bedarf aufgenommen
|