# 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 ) │ ← 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_estimation` → *Algorithmus-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: ```python 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.py` → `approbot_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 ```bash 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: ```yaml 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) ```bash 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: ```python 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) ```python 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 5–8) 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: ```json "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 3–5 passen in die Docker-Roadmap Phase 4–8. --- ## 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.