Files
appRobotDriver/doc/ToDo_12_InverseKinematikConfig_ROADMAP.md

6.5 KiB
Raw Blame History

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 02 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:

// 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):

calculateAngles3D()                 // Workspace → Motorwinkel (schreibt auf this.*)
calculatePositionFromMotorAngles()  // Motorwinkel → Workspace (schreibt auf this.*)
  • robot/RobotBase.js anlegen — generische Infrastruktur aus Robot.js
  • Beide Kinematik-Methoden in RobotBase als Stub mit throw new Error('not implemented')
  • JSDoc: Interface-Vertrag dokumentieren
  • 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
  • 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
  • robot/Robot.js wurde zunächst Kompatibilitäts-Alias und anschließend entfernt (siehe Update-Hinweis oben). Tests importieren direkt ./kinematics/Arm3SegmentLinearX.
  • 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

# docker-compose.yml
environment:
  ROBOT_KINEMATICS: arm3segmentlinearx
  ROBOT_KINEMATICS_PARAMS: '{"l1": 250, "l2": 264, "l3": 100}'
  • ROBOT_KINEMATICS — Bezeichner der Kinematik-Klasse (Default: arm3segmentlinearx)
  • ROBOT_KINEMATICS_PARAMS — JSON mit Konstruktor-Parametern
  • KinematicsFactory.js (createRobotFromEnv), eingebunden in startRobot.js:
    const robot = createRobotFromEnv(processEnv, { l1: 250, l2: 264, l3: 100 });
    
  • 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