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

6.6 KiB

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

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

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)

# robot.json in config/ ablegen, dann:
docker compose up

# oder manuell:
docker compose build
docker compose up -d

Anfrage senden:

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:

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

curl http://<server-ip>:8080/v1/health
# → {"status": "ok", "version": "1.0.0"}

Oder in Portainer unter Containersapprobot-pipelineLogs nachschauen.

Roboter wechseln (Portainer)

Neue robot.json auf dem Host ablegen (gleicher Pfad), dann in Portainer: Stacksapprobot-pipelineRecreate (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

{
  "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 API-Integrationsbeispiele (Python, Node.js): 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