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

213 lines
6.6 KiB
Markdown

# approbot-pipeline
Roboter-Pose-Schätzung aus Mehrkamera-ArUco-Bildern.
**Input:** Kamerabilder (`render_*.png`) + Kamera-Intrinsiken (`render_*.npz`) + `robot.json`
**Output:** Gelenkwinkel im R⁷ — `{x, y, z, a, b, c, e}` in mm bzw. Grad
---
## Drei Interfaces, eine Logik
```
┌──────────────────────────────────────────────────────┐
│ REST API (FastAPI, POST /v1/estimate) │ ← Robotersteuerung, beliebige Sprache
│ CLI (python -m approbot_pipeline <image_dir>) │ ← Terminal, Batch, CI
│ Python (from approbot_pipeline import ...) │ ← direkte Einbindung
└──────────────────────────────────────────────────────┘
```
---
## Schnellstart
### Als Python-Bibliothek
```python
from approbot_pipeline import estimate_from_dir
result = estimate_from_dir("pfad/zu/bildern", robot_json="robot.json")
print(result.joints) # {"x": 50.2, "y": -2.1, "z": 94.8, ...}
print(result.confidence) # {"x": "high", "b": "low", ...}
```
### Als CLI
```bash
pip install -e .
python -m approbot_pipeline data/Scene8 --robot robot.json
python -m approbot_pipeline data/Scene8 --robot robot.json --cameras a,b,d
```
### Als REST-Service (Docker / Portainer)
```bash
# robot.json in config/ ablegen, dann:
docker compose up
# oder manuell:
docker compose build
docker compose up -d
```
**Anfrage senden:**
```python
import requests
resp = requests.post(
"http://localhost:8080/v1/estimate",
files=[
("images", ("render_a.png", open("render_a.png", "rb"))),
("images", ("render_b.png", open("render_b.png", "rb"))),
("intrinsics", ("render_a.npz", open("render_a.npz", "rb"))),
("intrinsics", ("render_b.npz", open("render_b.npz", "rb"))),
],
)
joints = resp.json()["joints"]
```
---
## Verzeichnisstruktur
```
approbot-pipeline/
├── approbot_pipeline/ Python-Package
│ ├── __init__.py öffentliche API: estimate_from_dir, PipelineResult
│ ├── pipeline.py Orchestrator (ruft Scripts auf)
│ ├── __main__.py CLI-Einstiegspunkt
│ ├── scripts/ Pipeline-Scripts (kopiert aus dem Haupt-Repo)
│ │ ├── 1_detect_aruco_observations.py
│ │ ├── 2_estimate_camera_from_observations.py
│ │ ├── 3_multiview_bundle_adjustment_v4.py
│ │ ├── 3b_corner_marker_poses.py
│ │ ├── pose_estimation.py
│ │ └── robot_fk.py
│ └── api/
│ ├── __init__.py start_server()
│ ├── __main__.py python -m approbot_pipeline.api
│ └── server.py FastAPI-App
├── config/
│ └── robot.json ← hier die eigene robot.json ablegen
├── doc/
│ ├── README.md diese Datei
│ └── robot_json_pipeline_schema.md
├── tests/
│ ├── test_pipeline.py
│ └── fixtures/
│ └── robot_minimal.json
├── pyproject.toml
└── docker-compose.yaml
```
---
## Portainer-Stack einrichten
**Voraussetzung:** Docker Engine 23.0+ / Docker Compose Plugin 2.17+
(prüfen: `docker compose version`)
### Schritt 1 — robot.json auf dem Host ablegen
Auf dem Server, auf dem Portainer läuft, robot.json in einem festen Pfad speichern,
z.B. `/opt/approbot/config/robot.json`.
Den Volume-Pfad im `docker-compose.yaml` anpassen:
```yaml
volumes:
- /opt/approbot/config/robot.json:/config/robot.json:ro
```
### Schritt 2 — Option A: Stack aus Git-Repository
Empfohlen — Portainer zieht automatisch Updates wenn das Repo aktualisiert wird.
1. Portainer öffnen → **Stacks****+ Add stack**
2. Name vergeben, z.B. `approbot-pipeline`
3. **Build method:** `Repository`
4. **Repository URL:** Git-URL des `approbot-pipeline`-Verzeichnisses eintragen
5. **Compose path:** `docker-compose.yaml`
6.**Re-pull image and redeploy** aktivieren (für automatische Updates)
7. **Deploy the stack** klicken
Portainer führt `docker compose up --build` aus — das Image wird aus dem
`dockerfile_inline` im Compose-File gebaut.
### Schritt 2 — Option B: Stack aus Compose-Datei einfügen
Wenn kein Git-Zugang vorhanden ist:
1. Portainer öffnen → **Stacks****+ Add stack**
2. Name vergeben
3. **Build method:** `Web editor`
4. Inhalt von `docker-compose.yaml` vollständig in den Editor einfügen
5. **Deploy the stack** klicken
> Portainer baut das Image beim ersten Deploy aus dem `dockerfile_inline`-Block.
> Bei erneutem Deploy wird das Image neu gebaut wenn der Compose-Inhalt geändert wurde.
### Schritt 3 — Service prüfen
```bash
curl http://<server-ip>:8080/v1/health
# → {"status": "ok", "version": "1.0.0"}
```
Oder in Portainer unter **Containers**`approbot-pipeline`**Logs** nachschauen.
### Roboter wechseln (Portainer)
Neue `robot.json` auf dem Host ablegen (gleicher Pfad), dann in Portainer:
**Stacks**`approbot-pipeline`**Recreate** (Container neu starten, kein Rebuild nötig —
die Datei wird per Volume gemountet, nicht ins Image kopiert).
---
## API-Referenz
| Endpoint | Methode | Beschreibung |
|---|---|---|
| `/v1/estimate` | POST | Bilder → Gelenkwinkel |
| `/v1/health` | GET | `{"status": "ok", "version": "..."}` |
| `/v1/config` | GET | Aktiver `pose_estimation`-Block aus robot.json |
### POST /v1/estimate — Response
```json
{
"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
}
```
Confidence-Stufen: `high` | `medium` | `low` | `none`
---
## Konfiguration
Die einzige Konfigurationsdatei ist `robot.json` — sie beschreibt den Roboter vollständig
für alle Werkzeuge der Umgebung (Pipeline, Renderer, Benchmark).
Die Pipeline liest daraus `links`, `pose_estimation`, `vision_config`, `movements` und `units`;
alle anderen Abschnitte werden ignoriert.
Vollständige Dokumentation: [robot_json.md](robot_json.md)
API-Integrationsbeispiele (Python, Node.js): [api_integration.md](api_integration.md)
---
## Abhängigkeiten
| Paket | Version | Zweck |
|---|---|---|
| numpy | 1.26.4 | Numerik |
| scipy | 1.13.1 | Bundle Adjustment |
| opencv-contrib-python-headless | 4.10.0.84 | ArUco-Detektion |
| fastapi | 0.115.0 | REST-API |
| uvicorn | 0.30.6 | ASGI-Server |
| python-multipart | 0.0.9 | File-Upload |