157 lines
6.2 KiB
Markdown
157 lines
6.2 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
|
|
├── Robot.js ← dauerhafter Alias: module.exports = RobotBase
|
|
├── KinematicsFactory.js ← lädt Kinematik-Klasse anhand Env-Variable
|
|
└── kinematics/
|
|
├── Arm3SegmentLinearX.js ← aktuelle Implementierung
|
|
└── <NextRobot>.js ← zukünftige Implementierungen
|
|
```
|
|
|
|
## 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` wird zum Kompatibilitäts-Alias für die Übergangsperiode:
|
|
```js
|
|
module.exports = require('./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
|