Files
appRobotRender/POSE_PIPELINE.md

113 lines
4.9 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.
# Pose-Erkennungs-Pipeline
Aus Mehrkamera-Fotos eines Roboters werden die Gelenkwinkel (`x,y,z,a,b,c,e`)
geschätzt. Kern: Jeder ArUco-Marker wird über seine **4 triangulierten Ecken**
als volle 6-DOF-Pose (Position **+ gemessene Normale**) rekonstruiert; daraus
werden die Gelenkwinkel über die Kinematik (`robot_fk.py`) bestimmt.
## Ergebnis (Stand: Nacht-Build)
Benchmark über 10 valide Sim-Posen (Scene49b, 11, 12; Scene10 war fehlerhaft
gerendert und ausgeschlossen), Methode **hybrid**:
| Metrik | Wert |
|---|---|
| Winkelfehler mittel | **0,25°** |
| Winkelfehler std (Stabilität) | 0,13° |
| Winkelfehler schlechtester | 1,57° |
| Positionsfehler mittel | 0,10 mm |
Zwei Vorbedingungen waren entscheidend und sind erledigt:
1. **npz-fy-Bug** in `render_robot.py` gefixt (war ~15 % Brennweitenfehler bei 16:9).
2. **Eck- statt Center-Triangulation** — liefert pro Marker eine Normale (~1,2° genau, validiert in `benchmark/stage0_corner_normals.py`).
## Pipeline (run/run_pipeline.bat)
```
1_detect_aruco_observations Fotos -> *_aruco_detection.json (inkl. 4 Ecken)
2_estimate_camera_from_observations -> *_camera_pose.json
3_multiview_bundle_adjustment_v4 -> aruco_positions_initial.json (Center; für Viewer/Vergleich)
3b_corner_marker_poses -> aruco_marker_poses.json (Eck-Pose + Normale)
pose_estimation -> robot_state.json (Gelenkwinkel + Konfidenz)
```
Aufruf: `.\run_pipeline.bat ..\data\simulation\Scene8`
## Pose-Estimation (pipeline/pose_estimation.py)
Parametrisiert über **Gelenk-Variablen** (nicht Links), damit Sonderfälle dieses
Roboters generisch funktionieren:
- Glieder ohne eigene Marker (Base/`x`, Hand/`b`, Palm/`c`) — über Kind-Marker bestimmt.
- Geteilte Variable (`e` für FingerA+FingerB) — eine Unbekannte.
- Verdeckte Mittelglieder — durch globales BA überbrückt.
### Vier Methoden (robot.json → `pose_estimation.method`)
| Methode | Idee | Benchmark (mean / worst) |
|---|---|---|
| `sequential_vector` | analytisch aus Marker-Paar-Vektoren | 0,32° / 1,72° |
| `sequential_fk` | blockweise 1D/Block-LS entlang der Kette | 0,43° / 1,84° |
| `global_ba` | alle Winkel gemeinsam, robuste Loss | 0,25° / 1,57° |
| **`hybrid`** (Default) | sequenzieller Init → globales BA | **0,25° / 1,57°** |
### robot.json-Konfiguration
```json
"pose_estimation": {
"method": "hybrid",
"marker_observation": "corner_pose", // oder "center_point"
"use_normals": true,
"normal_weight": 100.0, // höher = stabiler bei wenigen Markern
"robust_loss": "huber",
"huber_delta_mm": 8.0,
"max_iterations": 200,
"min_cameras_per_marker": 2,
"per_link_method": {} // optional: Methode pro Glied
}
```
`normal_weight=100` wurde empirisch gewählt: stabilisiert sicht-arme Posen
deutlich (Worst-Case-Winkel halbiert), kostet bei gut sichtbaren Posen nur ~0,2°.
### Konfidenz pro Gelenk
`robot_state.json → movements[v].confidence`: `high` (≥2 Marker/Variable im
Block), `medium` (≥1), `low` (unterbestimmt — misstrauen!), `none` (0 Marker).
Für die Kollisionssicherheit: Gelenke mit `low`/`none` nicht ungeprüft anfahren;
ggf. Homing/`a`-Drehung für mehr Sichtbarkeit (Multi-Pose).
## Benchmark- & Eval-Werkzeuge (benchmark/)
| Tool | Zweck |
|---|---|
| `stage0_corner_normals.py` | Eck-Normalen-Genauigkeit gegen GT (Go/No-Go) |
| `eval_pose.py` | geschätzte Gelenkwinkel vs. `pose.json` |
| `run_benchmark.py` | Scenes × Methoden → Matrix + Aggregat (CSV/JSON) |
| `pipeline/9_evaluateMarker.py` | Marker Position + Normale pro Glied vs. `render_*.json` |
Beispiele:
```
python benchmark/run_benchmark.py # alle bereiten Scenes, alle Methoden
python benchmark/run_benchmark.py --scenes 5 8 --methods hybrid
python benchmark/stage0_corner_normals.py --evalDir data/evaluations/Scene5 --gt data/simulation/Scene5/render_a.json
python benchmark/eval_pose.py data/evaluations/Scene5/robot_state.json data/simulation/Scene5/pose.json
```
## Viewer (run/robot_viewer.html)
Lade `aruco_marker_poses.json` als „aruco" → der **Observed-normals**-Pfeil zeigt
jetzt die **gemessene** Normale, eingefärbt nach Winkelabweichung zur Modell-
Normale (grün <2° / gelb 25° / rot >5°). Statistik-Panel zeigt Normal mean/max.
## Offene Punkte / Ideen
- **Adaptive `normal_weight`**: pro Marker nach Sicht-Qualität gewichten →
best-case und worst-case gleichzeitig optimal (statt fester Kompromiss 100).
- **Multi-Pose-Fusion**: mehrere Aufnahmen bei verschiedenen `a`-Winkeln in
*eine* globale BA werfen — für Posen, in denen die Hand sonst verdeckt ist.
- **Reale Kameras**: Schritt 1 nutzt aktuell für alle Bilder `render_a.npz`
(Sim: alle Kameras gleich). Real bräuchte jede Kamera ihre eigene Intrinsik-npz.
- **`center_point`-Vergleich** im Benchmark (`--observation center_point`) braucht
`aruco_positions_initial.json` pro Scene (Schritt 3).
```