Files
appRobotHoming/doc/Homing.md
2026-06-16 15:28:14 +02:00

162 lines
6.7 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.
# Homing appRobotHoming
> Stand: 2026-06-15
> Homing läuft bei **jedem Einschalten** — schnell, vollautomatisch, ohne mechanische Endschalter.
---
## Was ist Homing?
Der Roboter weiss beim Einschalten nicht, wo er steht.
Die Kameras schauen auf die ArUco-Marker am Roboter und berechnen daraus
die vollständige Pose aller Gelenke.
**Homing** (dieser Prozess): bei jedem Einschalten, automatisch.
**Kalibrierung** (`doc/Kalibrierung.md`): nur nach mechanischen Änderungen.
Dieses Dokument ist der **allgemeine Ablauf**. Technische Detail-Doku je Teilstrecke:
| Doku | Inhalt |
|---|---|
| [`Homing_0_Camera.md`](Homing_0_Camera.md) | Foto → Kamera-Pose → trianguliertes `aruco_marker_poses.json` (Schritte 13b) |
| [`Homing_1_StepByStep.md`](Homing_1_StepByStep.md) | `aruco_marker_poses.json` → Gelenkwinkel je Link (4b-Kette, Schätz-Methoden/Fallbacks) |
| `Homing_2_improvement.md` *(geplant)* | Bekannte Probleme, Genauigkeits-Befunde, Verbesserungsideen |
---
## Kinematik-Kette
```
Board (ROOT, fest) ← Referenz aller Kameras
├── Base linear x axis=[1,0,0] ← Slider-Position
├── Arm1 revolute y axis=[-1,0,0] ← Schultergelenk
├── Ellbow revolute z axis=[-1,0,0] ← Ellbogen
├── Arm2 revolute a axis=[0,-1,0] ← Unterarm-Drehung
├── Hand revolute b axis=[1,0,0] ← Handgelenk
├── Palm revolute c axis=[0,-1,0] ← Handfläche
└── FingerA/B linear e axis=±[1,0,0] ← Greifer (symmetrisch)
```
**Ergebnis-State:** `{ x_mm, y_deg, z_deg, a_deg, b_deg, c_deg, e_mm }`
---
## Voraussetzungen
Homing setzt eine abgeschlossene Kalibrierung voraus:
| Was | Status |
|-----|--------|
| Kamera-Intrinsik (NPZ) | ✅ |
| Board-Marker-Positionen | ✅ |
| X-Achsen-Richtung | ✅ |
| Arm1 Joint-Origin Y/Z | ✅ Button vorhanden und ausführbar |
| Arm-Marker in robot.json | 🔶 Position manuell eintragen; Spin-Verifikation via Kalibrierung → Tab „Marker" (→ `doc/Kalibrierung_Marker.md`) |
---
## Ablauf
```
Foto alle Kameras
1_detect_aruco_observations.py (pro Kamera, mit NPZ)
2_estimate_camera_from_observations.py (pro Kamera)
3b_corner_marker_poses.py (einmal, benötigt ≥2 Kamera-Posen)
│ → aruco_marker_poses.json
X-Position aus Marker-Positionen schätzen
│ → x_mm (pro Arm-Marker: beobachtetes_x Modell_x(slider=0), gemittelt)
4b_revolute_angle.py --link Arm1 --x-mm {x_mm}
│ → state_Arm1.json (accumulated_state)
4b_revolute_angle.py --link Ellbow --from-state state_Arm1.json
│ → state_Ellbow.json
4b_revolute_angle.py --link Arm2 --from-state state_Ellbow.json
│ → state_Arm2.json
4b_revolute_angle.py --link Hand --from-state state_Arm2.json
│ → state_Hand.json ← accumulated_state enthält x,y,z,a,b,c,e
POST ROBOT_URL/api/state
```
**Schritte 13b** sind dieselbe Board-Pipeline wie in der Kalibrierung.
Sie sind in `runBoardPipeline()` (`server/server.js`) als gemeinsame Funktion ausgelagert.
**4b-Schleife**: sequenziell von root nach tip; jedes Script bekommt den Zustand des
vorherigen Schritts über `--from-state`. Der erste Aufruf erhält die geschätzte
X-Slider-Position über `--x-mm`.
---
## Implementierung
| Komponente | Datei | Beschreibung |
|-----------|-------|--------------|
| Board-Pipeline | `server/server.js``runBoardPipeline(runDir, send)` | Foto + Scripts 1, 2, 3b; von Board-Run und Homing genutzt |
| X-Schätzung | `server/homingOrchestrator.js``estimateXFromMarkers()` | Pro Arm-Marker `beobachtetes_x Modell_x(slider=0)`, gemittelt — rechnet den kinematischen Gelenk-Offset (z.B. Arm1.origin.x=110) heraus. Nur x-zuverlässige Ketten (x-Rotation: Arm1/Ellbow). Fallback: roher Mittelwert |
| Homing-Orchestrator | `server/homingOrchestrator.js``runHoming()` | Kompletter Ablauf als SSE-Stream |
| Backend-Route | `POST /api/homing/run` | SSE-Stream, startet `runHoming()` |
| State senden | `POST /api/homing/send-state` | Weiterleitung an `ROBOT_URL/api/state` |
| Run-Daten | `GET /api/homing/run-data?run=ts` | Debug-Bilder (base64) + finalState |
| Frontend | `public/index.html` + `public/client.js` | Homing-Buttons, Fortschrittsbalken, Tree View; schreibt Teil-Pose als `G92`-GCode ins Eingabefeld |
| Board-Viewer (Homing) | `public/boardViewer.html?mode=homing` | Skelett + Arm-Marker per FK (Three.js): Marker-Quadrat spin-korrekt rotiert + Orientierungszeiger zu Ecke 0 (Modell-Seite); gemessene Marker als Kugeln + Fehlerlinien; progressiver Update je erkanntem Gelenk |
**Lauf-Verzeichnisse:** `data/homing/{timestamp}/`
---
## SSE-Event-Typen
Das Backend streamt während des Homing-Laufs folgende Events:
| `type` | Felder | Bedeutung |
|--------|--------|-----------|
| `log` | `text` | Zeile aus Script-Ausgabe |
| `step` | `step`, `total`, `text` | Fortschritt (16) |
| `analysis` | `key`, `value` | Zwischenergebnis (x_mm, state_Arm1, …) |
| `error` | `text` | Fehler (Script-Exit ≠ 0 o.ä.) |
| `done` | `exitCode`, `state?`, `runDir` | Abschluss; `state` nur bei Erfolg |
---
## robot.json — Ladestrategie
**Aktuell:** Lokale Datei
```javascript
ROBOT_JSON = process.env.ROBOT_JSON || 'scripts/robot_1781069752019.json'
```
**Geplant** (wenn Driver `GET ROBOT_URL/api/robot/config` implementiert):
```javascript
async function loadRobotConfig() {
if (ROBOT_URL) {
const res = await fetch(new URL('/api/robot/config', ROBOT_URL));
return res.json();
}
return JSON.parse(await fs.readFile(ROBOT_JSON, 'utf8'));
}
```
Auswirkung: nur `ROBOT_JSON`-Variable ändern — alle Scripts bekommen automatisch
die aktuelle Konfiguration.
---
## Offene Punkte
- [~] **Arm-Marker eintragen** (Nutzer): `links.Arm1/Ellbow/Arm2/Hand.markers` in `robot.json` — Arm1 + Ellbow eingetragen, Arm2/Hand offen
- [~] **Erstmals testen**: Homing-Run mit echtem Roboter — Arm1 erkannt (x, y); Ellbow scheitert noch an fehlenden Markern
- [x] **X-Schätzung verfeinern** (2026-06-14): `estimateXFromMarkers()` rechnet den kinematischen Gelenk-Offset heraus statt rohem Mittelwert — behebt den ~110 mm Versatz der Modell-Marker
- [x] **Unit-Test für X-Schätzung** (2026-06-14): reine Geometrie nach `server/homingXEstimate.cjs` ausgelöst, `test/homingXEstimate.test.js` (9 Tests, inkl. Regression gegen den Offset-Bug)
- [ ] **y-Restfehler** (~2°): erkannt 30° → ausgegeben 28°; vermutlich X-Rest-Rauschen + 4b-Fit-Residuum, noch zu untersuchen
- [ ] **robot.json via Driver-API** (optional): wenn Driver `GET ROBOT_URL/api/robot/config` bereitstellt