Files
appRobotFileservice/doc/draft_filehandeling_API.md
chk b68bdfa9b4 Initiales Projekt-Skelett appRobotFileservice
Ausgelagertes Programm-/File-Handling (vormals GCode.receiveFC im appRobotDriver,
ToDo_4 / ToDo_6b). Express-Service mit .gcode + .json-Storage, aktivem Programm +
Cursor, Teaching (FPoint) und Playback. Speicherung in Grad, driver-nativ (Radian)
zum Driver. Konzept/API unter doc/draft_filehandeling*.md. Tests: jest (13 gruen).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14 10:12:41 +02:00

9.4 KiB

Draft — appRobotFileservice API

Status: Entwurf. Schnittstelle des ausgelagerten Programm-Handlings (appRobotFileservice). Konzept & Rollenteilung: draft_filehandeling.md.

Einziger Consumer ist der Driver (appRobotDriver). Steuerungen sprechen die appRobotFileservice nie direkt an, sondern schicken FCodes an den Driver, der sie hierher weiterreicht. Die appRobotFileservice ist passiv und driver-agnostisch: sie ruft den Driver nie an, kennt weder dessen URL noch dessen Pose. (Eine eigene Visualisierungs-UI darf direkt zugreifen — sie ist keine Steuerung.)


1. Überblick

  • Transport: HTTP/REST + JSON. Optional ein WebSocket-Event-Kanal (Abschnitt 8).
  • Basis-URL (Vorschlag): https://<host>:2100/api
  • Identität: Programme über id/Namenie über Dateipfade. Storage (.gcode + .json-Sidecar) ist intern gekapselt.
  • Einheiten am Wire: driver-nativ (φ/θ/ψ und e in Radian, x/y/z in mm) — exakt die G-Code-Strings, die der Driver ausführt. Gespeichert wird in Grad (standardnahe .gcode); die appRobotFileservice rechnet an ihrer Storage-Grenze um (Konzept §7).
  • Auth: Bearer <FILE_API_KEY> für schreibende Operationen (analog ROBOT_API_KEY).

2. Datenmodell

Program (Metadaten, aus dem .json-Sidecar)

{ "id": "besteck_spuelmaschine", "name": "Besteck Spülmaschine",
  "lineCount": 12, "angleUnit": "deg",
  "createdAt": "2025-10-04T10:25:00Z", "updatedAt": "2025-10-04T10:41:00Z" }

ActiveState (aktives Programm + Cursor — Single Source of Truth)

{ "programId": "besteck_spuelmaschine", "cursor": 4, "lineCount": 12,
  "currentLine": "G90 G1 x310 y444 z0.5 a1.5708 b-1.5708 c0 e0.12 f1000",
  "playing": false, "version": 7 }

currentLine ist driver-nativ (Radian) und kommentarfrei — direkt ausführbar. Gespeichert wird in Grad mit Zeitstempel-Kommentar (draft_filehandeling.md §8).

Pose (vom Driver beim FPoint mitgeschickt)

Native Radian-Werte inkl. Greifer e:

{ "pose": { "x": 0, "y": 300, "z": 0, "a": 1.5708, "b": -1.5708, "c": 0, "e": 0.12 },
  "feedrate": 1000 }

3. FCode ↔ Endpoint-Mapping

Der Driver übersetzt die FCodes der Steuerungen in diese Endpoints:

FCode Endpoint Antwort an Steuerung (über Driver)
FList GET /programs Liste (gezielt)
FShow [id] GET /programs/{id} Inhalt in Grad (gezielt)
FLoad <id> PUT /active ActiveState (gezielt)
FSave <name> POST /programs id (gezielt)
FClear POST /active/clear ActiveState (gezielt)
FPoint POST /active/points Bestätigung (gezielt)
FPlus POST /active/next Bewegung → Pose-Broadcast
FMinus POST /active/prev Bewegung → Pose-Broadcast
FFirst POST /active/first Bewegung → Pose-Broadcast
FLast POST /active/last Bewegung → Pose-Broadcast
FGoto <n> POST /active/goto Bewegung → Pose-Broadcast
FPlay / FStop POST /active/play / /stop Status

4. Endpoints — Programm-Verwaltung

GET /programsFList

{ "programs": [ { "id": "log", "name": "log", "lineCount": 36 },  ] }

GET /programs/{id}FShow

Inhalt + Metadaten für die Anzeige — in Grad, wie gespeichert (lesbar):

{ "id": "besteck_spuelmaschine", "displayUnit": "deg",
  "lines": [ "G90 G1 x0 y614 z0 a-90.00 b90.00 c0.00 e0 f1000 ;1759566014",
             "G90 G1 x0 y300 z0 a90.00 b-90.00 c0.00 e0 f1000 ;1759566052!" ] }

Kommentar ;<epoch> = Aufnahme-Zeitstempel; ein abschließendes ! markiert die Cursor-Zeile.

POST /programsFSave

{ "name": "Demo C", "fromActive": true }          // aus aktivem Puffer
// oder expliziter Inhalt (in Grad, wie eine .gcode):
{ "name": "Demo C", "lines": ["G90 G1 x0 y300 … a90.00 …"], "angleUnit": "deg" }

201 { "id": "demo_c", "lineCount": 12 } (legt demo_c.gcode + demo_c.json an)

PUT /programs/{id} · DELETE /programs/{id}

Inhalt ersetzen / umbenennen · löschen (jeweils .gcode und .json).


5. Endpoints — Aktives Programm & Cursor

GET /active

Aktuellen ActiveState lesen.

PUT /activeFLoad

{ "id": "besteck_spuelmaschine" }

ActiveState. Validierung: existiert, ≥1 gültige Zeile (sonst EMPTY_PROGRAM).

POST /active/clearFClear

Aktives Programm leeren, Cursor → 0.

Stepping — next · prev · first · last · goto

Bewegt den Cursor und gibt die driver-native, ausführbare Zeile (Radian) zurück. Der Driver führt sie selbst aus — der Fileservice pusht nichts.

POST /active/next · /prev · /first · /last · /goto { "index": 7 }

{ "cursor": 5, "line": "G90 G1 x310 y444 z30.5 a1.5708 b-1.5708 c0 e0.12 f1000" }

Grenzen: next am Ende / prev am Anfang → CURSOR_OUT_OF_RANGE (optional wrap).


6. Endpoints — Teaching / Aufnahme

POST /active/pointsFPoint

Der Driver schickt die aktuelle Pose mit (native Radian-Werte). Die appRobotFileservice rechnet nach Grad um, formatiert die Zeile (Feedrate, Zeitstempel als Kommentar ;<epoch>) und hängt sie an.

{ "pose": { "x": 0, "y": 300, "z": 0, "a": 1.5708, "b": -1.5708, "c": 0, "e": 0.12 },
  "feedrate": 1000 }

201 { "index": 12, "line": "G90 G1 x0 y300 z0 a90.00 b-90.00 c0.00 e6.88 f1000 ;1759566014" }

POST /active/lines

Rohe Zeile(n) anhängen/einfügen (z. B. Pause G4):

{ "line": "G4 P0.5", "atIndex": 8 }

PUT /active/lines/{index} · DELETE /active/lines/{index}

Einzelne Zeile ersetzen / löschen (Editieren der Aufnahme).


7. Endpoints — Playback (kontinuierlich)

POST /active/playFPlay

{ "mode": "run", "fromStart": false }   // "run" = bis Ende/Stop; "step" = eine Zeile

Die appRobotFileservice liefert die Zeilen getaktet zurück bzw. meldet Fortschritt über den Event-Kanal (§8); ausgeführt werden sie vom Driver. POST /active/stop hält an.

„Nächste File" (Playlist über mehrere Programme) baut darauf auf: POST /playlist/next lädt das nächste Programm (PUT /active) und startet play.


8. Optionaler Event-Kanal (WebSocket)

Für eine Live-UI der appRobotFileservice (Fortschritt) ohne Polling:

{ "event": "cursorMoved",   "cursor": 5, "line": "G90 G1 … a1.5708 …" }
{ "event": "activeChanged", "programId": "demo_c", "lineCount": 12 }
{ "event": "playStopped",   "cursor": 9, "reason": "end" }

(Die Roboter-Pose-Updates laufen weiterhin über den Driver-WS-Broadcast — der Fileservice kennt die Pose nur, soweit der Driver sie beim FPoint mitgibt.)


9. Fehler-Envelope

Konsistent mit dem Driver (doc/ToDo_5_API.md): { type, code, message, input }. Der Driver reicht Fileservice-Fehler unverändert an die Steuerung zurück.

code Bedeutung
PROGRAM_NOT_FOUND {id} existiert nicht
INVALID_NAME unzulässiger Name (kein Pfad)
EMPTY_PROGRAM FLoad auf Programm ohne gültige Zeile
CURSOR_OUT_OF_RANGE next/prev/goto über die Grenzen
NO_ACTIVE_PROGRAM Aktion erfordert geladenes Programm
FILE_ERROR Storage-Fehler (.gcode/.json)
{ "type": "error", "code": "PROGRAM_NOT_FOUND", "message": "no program 'demo_x'", "input": "demo_x" }

10. Durchgereichte Payloads

FShow/FList können größere Antworten erzeugen, die der Driver nur durchreicht. Die appRobotFileservice hält sie akzeptabel klein (Paginierung, Übersichtsform), sodass der Weg über den Driver unkritisch bleibt.


11. Konfiguration

Die appRobotFileservice braucht keinen Driver-Zugang (kein DRIVER_BASE_URL).

Variable Zweck Beispiel
FILE_SERVICE_PORT Port 2100
STORAGE_DIR Verzeichnis für .gcode + .json ./GCodeFiles
FILE_EXT gcode oder ngc gcode
STORE_ANGLE_UNIT Speichereinheit der Winkel deg
FILE_API_KEY Bearer-Token (Schreiben)

12. Beispiel-Flows (durch den Driver)

Teaching-Session (Joystick → Aufnahme)

Steuerung → Driver: FLoad demo_c         → Driver: PUT  /active {id:"demo_c"}
Steuerung → Driver: G1 …/$J=             (Arm bewegen, lokal — Fileservice unbeteiligt)
Steuerung → Driver: FPoint               → Driver hängt Live-Pose an,
                                           POST /active/points { pose, feedrate }
… weitere Punkte …
Steuerung → Driver: FSave "Demo C"       → Driver: POST /programs {name,fromActive:true}
                                           → demo_c.gcode + demo_c.json

Playback-Session (Datei → Roboter, schrittweise)

Steuerung → Driver: FList                → GET /programs            (Auswahl)
Steuerung → Driver: FLoad demo_c         → PUT /active
Steuerung → Driver: FFirst               → POST /active/first → {line (Radian)}
                                           Driver: receiveGCode(line) → Bewegung
                                           Driver: Pose-Broadcast an alle UIs
Steuerung → Driver: FPlus … / FPlay

13. Verweise