Files
appRobotRender/doc/separate_pipeline_solution_roadmap.md
2026-06-03 19:49:07 +02:00

9.5 KiB
Raw Blame History

Separate Pipeline Solution — Roadmap

Ziel: Die Pose-Schätzungs-Pipeline als eigenständige, wartbare, konfigurierbare Einheit, komplett losgelöst von Simulation und Rendering.

Input: Bilder (PNG/JPG) + Kamera-Intrinsiken (npz) + robot.json Output: robot_state.json — Gelenkwinkel im R⁷-Raum (x,y,z,a,b,c,e)


Status-quo-Analyse

Die Pipeline ist bereits de facto sauber trennbar:

  • Keine einzige Pipeline-Datei referenziert Simulation, Blender oder Rendering.
  • Externe Abhängigkeiten: nur numpy, scipy, opencv-contrib-python-headless.
  • Internes Modul: robot_fk.py.
  • Dockerfile.pipeline und requirements.pipeline.txt existieren bereits.

Was heute noch fehlt, um sie vollständig eigenständig zu machen:

  • Kein eigener Package-Einstiegspunkt (kein setup.py / pyproject.toml)
  • Kein stabiles, versioniertes API-Interface
  • robot.json ist zu stark mit Render-Parametern vermischt
  • Kein Health-Check / kein Service-Modus (nur CLI)

Architektur-Entscheidung

Drei Interface-Ebenen, alle parallel nutzbar:

┌──────────────────────────────────────────────────────┐
│  REST API  (FastAPI, /v1/estimate)                    │  ← Integration in Robotersteuerung
│  CLI       (python -m approbot_pipeline <scene>)      │  ← Terminal, Batch, CI
│  Python    (import approbot_pipeline; estimate(...))  │  ← direkte Einbindung in Python-Code
└──────────────────────────────────────────────────────┘
         alle lesen dieselbe robot.json → robot_fk → pose_estimation

Der Robot.json-Vertrag ist das einzige Konfigurationsinterface:

  • Kinematik (links) → Modell, ändert sich selten
  • pose_estimationAlgorithmus-Tuning, ändert sich gelegentlich
  • Keine Render-/Sim-Parameter mehr in der Pipeline-Config (die bleiben in renderingInfo)

Paketstruktur (Ziel)

approbot-pipeline/           ← eigenständiges Verzeichnis / eigenes Repo
│
├── approbot_pipeline/       ← Python-Package
│   ├── __init__.py          ← öffentliche API: estimate(), estimate_from_dir()
│   ├── pipeline.py          ← Orchestrator (run_pipeline.py → Modul)
│   ├── detect.py            ← 1_detect_aruco_observations
│   ├── camera_pose.py       ← 2_estimate_camera_from_observations
│   ├── triangulate.py       ← 3_multiview_bundle_adjustment_v4
│   ├── corner_poses.py      ← 3b_corner_marker_poses
│   ├── pose_estimation.py   ← pose_estimation (unverändert)
│   ├── robot_fk.py          ← robot_fk (unverändert)
│   └── api/
│       ├── __init__.py
│       └── server.py        ← FastAPI-Service
│
├── pyproject.toml           ← package metadata, dependencies gepinnt
├── Dockerfile               ← = Dockerfile.pipeline (schlankes Image ~200 MB)
├── docker-compose.yml       ← Service-Modus, Port-Mapping
├── README.md
└── tests/
    ├── test_pipeline.py     ← End-to-end gegen eine Beispiel-Scene
    └── fixtures/            ← kleine Testbilder + robot.json-Minimal

Phase 1 — Saubere Python-Package-Struktur

Aufgaben

  • pyproject.toml anlegen (Name: approbot-pipeline, Versions-Tag, Dependencies)
  • approbot_pipeline/__init__.py mit der öffentlichen API:
    from approbot_pipeline import estimate, estimate_from_dir
    result = estimate_from_dir("path/to/images", robot_json="robot.json")
    # result.joints  → {"x": 50.2, "y": -2.1, ..., "e": 3.0}
    # result.confidence → {"x": "high", "b": "low", ...}
    
  • pipeline/run_pipeline.pyapprobot_pipeline/pipeline.py (Module statt Subprocess-Kette)
  • Interne Schritte als direkte Python-Funktionsaufrufe statt subprocess.run — das eliminiert Process-Overhead und macht Fehler besser fangbar.

Ergebnis

pip install -e .                                # lokal entwickeln
python -m approbot_pipeline data/sim/Scene8    # CLI

Phase 2 — robot.json bereinigen

Das Pipeline-Package braucht aus robot.json nur zwei Abschnitte:

Abschnitt Braucht Pipeline Braucht Renderer
links (Kinematik, Marker)
pose_estimation
vision_config
units
renderingInfo
robot_test_poses
test_camera_positions

Aufgaben

  • Minimales Pipeline-Schema dokumentieren (welche Felder sind Pflicht, welche optional-mit-Default): doc/robot_json_pipeline_schema.md
  • Validierer: approbot_pipeline.config.validate(robot_json_path) → prüft Pflichtfelder, gibt sinnvolle Fehlermeldungen
  • robot.json bleibt eine Datei (kein Split), aber das Package liest nur seinen Teil — Renderer-Felder werden einfach ignoriert.

Phase 3 — REST API (FastAPI)

Für die Integration in die Robotersteuerung: die Steuerung postet Bilder, bekommt Gelenkwinkel zurück.

Interface

POST /v1/estimate
  Content-Type: multipart/form-data
  - robot_json: file  (oder als Pfad-Config beim Server-Start)
  - images[]:   file  (N Kamerabilder, benennt nach cam-ID: render_a.png etc.)
  - intrinsics[]: file  (N npz-Dateien, gleiche Reihenfolge wie images)

Response 200:
{
  "joints": {"x": 50.2, "y": -2.1, "z": 94.8, "a": 20.1, "b": 59.9, "c": 9.0, "e": 3.0},
  "confidence": {"x": "high", "y": "high", "z": "high", "a": "high", "b": "low", "c": "low", "e": "low"},
  "residual_rms": 1.45,
  "n_markers": 56,
  "processing_ms": 1240
}

GET /v1/health   → {"status": "ok", "version": "1.2.0"}
GET /v1/config   → aktuelle robot.json-Konfiguration (pose_estimation-Block)

Aufgaben

  • approbot_pipeline/api/server.py mit FastAPI
  • Temporäres Verzeichnis pro Request (keine Race-Conditions bei parallelen Anfragen)
  • docker-compose.yml für den Service-Modus:
    services:
      pipeline:
        image: approbot/pose-pipeline:latest
        ports: ["8080:8080"]
        volumes:
          - ./robot.json:/config/robot.json:ro
        command: ["python", "-m", "approbot_pipeline.api", "--robot", "/config/robot.json"]
    
  • GET /v1/health für Container-Health-Check

Phase 4 — Tests & CI

Aufgaben

  • tests/test_pipeline.py: End-to-end-Test auf minimaler Fixture-Scene (kleine PNGs + robot.json-Minimal) ohne Blender → CI-tauglich in < 30s
  • Regression gegen GT: eval_pose.py als pytest-Assertion (assert mean_error_deg < 0.5) — fängt Code-Regressions wie den fy-Bug automatisch
  • GitHub Actions (oder äquivalentes CI): docker build + Test auf jedem Commit
  • Versions-Tag: approbot-pipeline==1.0.0 → Pipeline-Verhalten ist reproduzierbar

Phase 5 — Deployment

Variante A: Docker-Service auf dem Roboter-PC (empfohlen)

docker run -d --rm \
  -p 8080:8080 \
  -v ./robot.json:/config/robot.json:ro \
  approbot/pose-pipeline:latest \
  python -m approbot_pipeline.api --robot /config/robot.json

Robotersteuerung (beliebige Sprache) postet Bilder per HTTP:

import requests
resp = requests.post("http://localhost:8080/v1/estimate",
    files=[("images", open(img, "rb")) for img in cam_images])
joints = resp.json()["joints"]

Variante B: Python direkt eingebunden (ohne Container)

from approbot_pipeline import estimate_from_dir
result = estimate_from_dir(image_dir, robot_json="robot.json")
move_robot(result.joints)

Variante C: Portainer / verteilte Nodes

Schnittstellt nahtlos an die Docker-Roadmap (Phase 58) an:

  • approbot/pose-pipeline ist das Image für Nomad-Batch-Jobs
  • Job-Payload: {"scene_dir": "/mnt/data/sceneX"} oder die Bilder direkt

Konfigurationsvertrag (stabiles Interface)

Der einzige Eingabepunkt für Algorithmus-Tuning:

"pose_estimation": {
  "method": "hybrid",
  "marker_observation": "corner_pose",
  "use_normals": true,
  "normal_weight": 100.0,
  "robust_loss": "huber",
  "huber_delta_mm": 8.0,
  "max_iterations": 200,
  "min_cameras_per_marker": 2,
  "per_link_method": {}
}

Dieses Schema ist versionsstabil: neue Parameter haben immer Defaults, alte werden nie entfernt (nur deprecated-markiert). So laufen Roboter-Deployments mit einer älteren robot.json unverändert weiter.


Vorgehen / Empfohlene Reihenfolge

  1. Phase 1 (pyproject.toml + __init__.py + Funktionsaufrufe statt Subprocess) — bringt sofort sauberere Fehlerbehandlung und elimiert ~2s Process-Startup pro Schritt.
  2. Phase 2 (Schema-Validierer) — frühzeitige, verständliche Fehlermeldungen statt kryptischen Abbrüchen in Schritt 2.
  3. Phase 3 (REST API) — sobald die Robotersteuerung integriert werden soll.
  4. Phase 4 (CI) — parallel zu Phase 2/3.
  5. Phase 5 (Deployment) — läuft auf Phase 3 auf.

Phases 1+2 sind unabhängig von der Docker-Roadmap und können sofort beginnen. Phase 35 passen in die Docker-Roadmap Phase 48.


Was sich NICHT ändert

  • robot.json ist und bleibt die einzige Konfigurations-Datei.
  • Die Algorithmen (pose_estimation.py, robot_fk.py) bleiben unberührt.
  • Bestehende run/run_pipeline.bat und pipeline/run_pipeline.py bleiben parallel lauffähig — das Package ist eine sauberere Schicht darüber, kein Ersatz.
  • Benchmark-Tools (benchmark/*.py) arbeiten weiterhin direkt gegen das Dateisystem.