Files
appRobotHoming/doc/Homing.md
2026-06-16 16:01:32 +02:00

7.2 KiB
Raw Blame History

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 Foto → Kamera-Pose → trianguliertes aruco_marker_poses.json (Schritte 13b)
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
Homing_5_Pose.md Verfeinerungsschritt NACH der 4b-Kette (Bundle-Adjustment, 5_pose_estimation.py) — noch nicht verdrahtet

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.jsrunBoardPipeline(runDir, send) Foto + Scripts 1, 2, 3b; von Board-Run und Homing genutzt
X-Schätzung server/homingOrchestrator.jsestimateXFromMarkers() 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.jsrunHoming() 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

ROBOT_JSON = process.env.ROBOT_JSON || 'scripts/robot_1781069752019.json'

Geplant (wenn Driver GET ROBOT_URL/api/robot/config implementiert):

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 (x, y) und Ellbow (z) laufen durch; Arm2/Hand noch zu prüfen. Ellbow brach zunächst ab (4b: nur 2 Marker sichtbar, deren Verbindungsvektor parallel zur Gelenkachse liegt → keine Baseline), seit 2026-06-16 über Fallback-1/-2 in 4b_revolute_angle.py gelöst — Details: Homing_1_StepByStep.md
  • 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
  • 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