Metadata-Version: 2.4
Name: approbot-pipeline
Version: 1.0.0
Summary: Robot pose estimation from multi-camera ArUco images
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: numpy==1.26.4
Requires-Dist: scipy==1.13.1
Requires-Dist: opencv-contrib-python-headless==4.10.0.84
Requires-Dist: fastapi==0.115.0
Requires-Dist: uvicorn[standard]==0.30.6
Requires-Dist: python-multipart==0.0.9

# appRobotBodyTrack

3D-Body-Tracking für Roboter aus Mehrkamera-ArUco-Bildern.

**Input**  
- Bilder: `render_*.png`  
- Intrinsics: `render_*.npz`  
- Konfiguration: `robot.json`  

**Output**  
- Gelenke **R⁷** → `{x, y, z, a, b, c, e}` (mm / Grad)

---

## Interfaces

Eine Logik, drei Zugänge:

- **Python**
- **CLI**
- **REST (FastAPI)**

---

## Quickstart

### Python

```python
from scripts import estimate_from_dir

result = estimate_from_dir("data/Scene8", robot_json="robot.json")

print(result.joints)
print(result.confidence)
```

---

### CLI

```bash
pip install -e .

python -m scripts data/Scene8 --robot robot.json
python -m scripts data/Scene8 --robot robot.json --cameras a,b,d
```

---

### REST API

```bash
docker compose up
```

**Request:**

```python
import requests

resp = requests.post(
    "http://localhost:8446/v1/estimate",
    files=[
        ("images", ("render_a.png", open("render_a.png", "rb"))),
        ("intrinsics", ("render_a.npz", open("render_a.npz", "rb"))),
    ],
)

print(resp.json()["joints"])
```

---

## API

| Endpoint | Methode | Zweck |
|----------|--------|------|
| `/v1/estimate` | POST | Bilder → Gelenke |
| `/v1/health` | GET | Status |
| `/v1/config` | GET | aktive Konfiguration |

**Maschinenlesbares Schema / interaktive Doku** (automatisch von FastAPI):

| URL | Zweck |
|-----|-------|
| `/openapi.json` | OpenAPI-Spezifikation (für Client-Generatoren) |
| `/docs` | Swagger-UI (interaktiv ausprobieren) |
| `/redoc` | ReDoc-Ansicht |

**Response:**

```json
{
  "joints": {"x": 50.2, "y": -2.1, "z": 94.8, "a": 20.1},
  "confidence": {"x": "high", "b": "low"},
  "residual_rms": 1.45,
  "n_markers": 56,
  "processing_ms": 1240
}
```

---

## Struktur

```
.
├── scripts/
├── config/robot.json
├── tests/
└── docker-compose.yaml
```

---

## Deployment (Docker / Portainer)

Die `config/robot.json` wird beim Build **mit ins Image gebacken** (`COPY . .`) und
liegt dort fest unter `/app/config/robot.json`. Damit läuft der Container
out-of-the-box — **kein Bind-Mount nötig**, auch nicht als Portainer-Stack.

> Voraussetzung: `config/robot.json` muss **zum Build-Zeitpunkt** als Datei
> vorhanden sein. Falls nicht: `cp config/robot.json.example config/robot.json`
> und mit der echten Konfiguration füllen.

**Start & Healthcheck:**
```bash
docker compose up -d
curl http://<host>:8446/v1/health     # {"status":"ok","version":"1.0.0"}
```

**Eigene robot.json ohne Rebuild** (optional): die eingebackene Kopie per Mount
überlagern — siehe auskommentierter `volumes`-Block in `docker-compose.yaml`.

> ⚠️ **Portainer-Falle:** Ein Bind-Mount auf einen Host-Pfad, der **nicht
> existiert**, lässt Docker dort ein leeres **Verzeichnis** anlegen. Die Pipeline
> liest es dann als Datei → `IsADirectoryError` → jeder `/v1/estimate` und
> `/v1/config` antwortet mit **500**. Deshalb ist der Mount jetzt optional;
> aktiviere ihn nur, wenn die Datei am Host-Pfad wirklich liegt.

---

## Konfiguration

Zentrale Datei: **`robot.json`**

Verwendete Bereiche:
- `links`
- `pose_estimation`
- `vision_config`
- `movements`
- `units`

---

## Stack (minimal)

- numpy  
- scipy  
- opencv (aruco)  
- fastapi + uvicorn  

---

## Naming

- **BodyTrack** → Tracking (dynamisch) ✅  
- **BodyMap** → Modell / Repräsentation  
- **BodySense** → Wahrnehmung (low-level)
