213 lines
6.6 KiB
Markdown
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 |
|