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

267 lines
9.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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_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 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:
```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 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.