161 lines
7.4 KiB
Markdown
161 lines
7.4 KiB
Markdown
# ToDo – appRobotHoming
|
||
|
||
Nächste Schritte für den Umbau zum statischen Frontend + HTTPS-BFF-Proxy.
|
||
Kontext/Architektur: siehe [`../README.md`](../README.md).
|
||
|
||
Reihenfolge ist grob nach Priorität sortiert. Offene Entscheidungen sind als
|
||
**Frage** markiert – die müssen vor der Umsetzung geklärt werden.
|
||
|
||
---
|
||
|
||
## 1. HTTPS wieder zum Laufen bringen (blockierend)
|
||
|
||
**Diagnose abgeschlossen (2026-06-08):**
|
||
|
||
- Backend läuft auf 2093, aber als **HTTP** (`http://…:2093/` → 200 + UI;
|
||
`https://…:2093/` → keine Antwort). Es ist der **Container** (docker-compose):
|
||
`/api/health` meldet `webcamUrl: http://appRobotWebcam:8444`.
|
||
- Der Code ist korrekt: `https/localhost.key` + `localhost.pem` mit Passphrase
|
||
`abcd` laden lokal **einwandfrei** in `https.createServer`.
|
||
- **Root Cause:** Die Cert-Dateien **fehlen im Container**. `.gitignore` schließt
|
||
`*.key`/`*.pem`/`*.pfx` aus → nicht in git → der Mount
|
||
`/home/chk/Documents/appRobotHoming` auf `thinkcentre` hat sie nicht →
|
||
`createHttpsServer()` scheitert an `fsPromises.access()` → **stiller
|
||
HTTP-Fallback** (`server/server.js`, `createHttpsServer` → `return null`).
|
||
|
||
**Gewählte Lösung (Entscheidung): Cert reist mit dem Repo/Volume.**
|
||
|
||
Das self-signed Cert sichert nur den Hop **Proxy ↔ Backend** und hat keinen
|
||
echten Wert (nie öffentlich). Daher darf es mit ins Repo und kommt über den
|
||
bestehenden `/app`-Volume-Mount automatisch in den Container.
|
||
|
||
- [x] `.gitignore`: gezielte Ausnahme `!https/localhost.key` + `!https/localhost.pem`
|
||
(Schutz für alle anderen Schlüssel bleibt bestehen). → erledigt.
|
||
- [ ] `https/localhost.key` + `https/localhost.pem` committen.
|
||
- [ ] Deploy-Host `thinkcentre:/home/chk/Documents/appRobotHoming/` aktualisieren
|
||
(git pull bzw. Dateien bereitstellen), damit der Container sie sieht.
|
||
- [ ] Verifizieren: `https://thinkcentre.local:2093/api/health` antwortet über
|
||
**HTTPS** (aktuell nur HTTP).
|
||
|
||
Optional (separat, nicht Teil der Entscheidung):
|
||
|
||
- [ ] Passphrase/Pfad konsequent aus dem Env (`HTTPS_KEY_PATH`/`HTTPS_CERT_PATH`/
|
||
`HTTPS_PASSPHRASE`) statt hartkodiert.
|
||
- [ ] Stillen HTTP-Fallback lauter machen (klar loggen / hart abbrechen statt
|
||
unbemerkt HTTP) – dieser Fallback hat den Bug verschleiert.
|
||
- [ ] Reverse-Proxy prüfen: Leitet er WSS-Upgrade-Header korrekt an
|
||
`https://…:2093` weiter?
|
||
|
||
---
|
||
|
||
## 2. WebCam-Bilder über die dokumentierte API holen → **entschieden: Option B**
|
||
|
||
`server/server.js` ruft aktuell `WEBCAM_URL + /api/latest-snapshot` auf – diesen
|
||
Endpoint gibt es **nicht**. **Entscheidung:** Der Homing-Backend setzt das Bundle
|
||
selbst aus den dokumentierten Endpoints zusammen (kein neuer Endpoint im
|
||
WebCam-Service).
|
||
|
||
Service läuft und ist erreichbar unter `http://thinkcentre.local:8444`
|
||
(→ `WEBCAM_URL`). Real verifizierte Contracts:
|
||
|
||
- `GET /api/cameras` →
|
||
```json
|
||
{"cameras":[
|
||
{"id":"cam0","name":"Kamera 0","position":"front","stream":true,"hires":true, ...},
|
||
{"id":"cam1","name":"Kamera 1","position":"left", "stream":true,"hires":true, ...},
|
||
{"id":"cam2","name":"Kamera 2","position":"right","stream":true,"hires":true, ...}
|
||
]}
|
||
```
|
||
- `GET /api/snapshot/{id}/hires` → `200 image/jpeg` (cam0/cam1 ~1280px, cam2 1920px).
|
||
- `GET /health` → Status + `state`/`hasFrame` pro Kamera.
|
||
|
||
Umsetzung in `server/server.js` (`/api/latest-snapshot`):
|
||
|
||
- [ ] `GET {WEBCAM_URL}/api/cameras` holen → Kameraliste (mit `hires:true` filtern).
|
||
- [ ] Für jede Kamera **parallel** `GET {WEBCAM_URL}/api/snapshot/{id}/hires` →
|
||
JPEG, als base64 + `id`/`position` ins Bundle.
|
||
- [ ] Bundle ans UI zurückgeben (statt der bisherigen CSV-Annahme). Reihenfolge/
|
||
Zuordnung über `id`+`position` stabil halten (wichtig für §3).
|
||
- Hinweis: Die alte CSV/`_annotated.jpg`/JSON-Marker-Erkennung kommt **nicht**
|
||
von der Webcam. Für den BodyTracker-Pfad ist sie ohnehin redundant
|
||
(BodyTracker macht ArUco selbst); sie bleibt nur für den lokalen Fallback
|
||
`public/calculateAngles.js` relevant.
|
||
|
||
---
|
||
|
||
## 3. Intrinsics-Fluss → **entschieden: WebCam liefert Intrinsics mit**
|
||
|
||
**Klarstellung der Datentypen** (im Altcode unter „Intrinsics" vermischt):
|
||
|
||
| Typ | Beispiel | Quelle | statisch |
|
||
|---|---|---|---|
|
||
| **Kamera-Intrinsics** (K, Distortion) | das echte „NPZ" | Kalibrierung | ✅ pro Kamera |
|
||
| **Extrinsics** (`position_mm`, `orientation_deg`) | in `_two_cam.json` | wird gelöst | ❌ Output |
|
||
| **Marker-3D-Posen** | in `_two_cam.json` | trianguliert | ❌ Output |
|
||
|
||
Das, was `server/server.js` heute als `robotIntrinsics` (= `_two_cam.json`)
|
||
schickt, sind **Extrinsics + triangulierte Marker** – also **BodyTracker-Output**,
|
||
fälschlich als Input verschickt. Muss raus.
|
||
|
||
Die WebCam liefert aktuell **kein** NPZ (alle Intrinsics-Endpoints → 404). Der
|
||
BodyTracker hält in `/v1/config` nur Solver-Parameter, keine Intrinsics.
|
||
|
||
**Entscheidung:** Die Kamera-Intrinsics leben beim **WebCam-Service** (Source of
|
||
Truth) und werden mitgeliefert. Homing reicht sie an den BodyTracker durch.
|
||
|
||
Aufgaben WebCam-Service:
|
||
- [ ] Kameras kalibrieren (Schachbrett) → K + Distortion je Kamera. **Achtung:
|
||
Intrinsics sind auflösungsabhängig** – sie müssen zur **`hires`-Auflösung**
|
||
passen, die `/api/snapshot/{id}/hires` ausliefert (C270 1280×960,
|
||
C920 1920×1080).
|
||
- [ ] Intrinsics in `/api/cameras` je Kamera ausgeben (K, dist, `calib_size`),
|
||
stabil gekeyt über `id`/`note`-Serial.
|
||
|
||
Aufgaben Homing-Backend (`server/server.js`):
|
||
- [ ] `robotIntrinsics`/`_two_cam.json`-Pfad aus `/api/estimate` entfernen.
|
||
- [ ] Pro Kamera Bild + zugehörige Intrinsics paaren (über `id`) und an
|
||
`BODYTRACKER/v1/estimate` weiterreichen. **N Kameras** (aktuell 3), nicht
|
||
fix 2.
|
||
|
||
Aufgaben BodyTracker (wir besitzen ihn):
|
||
- [ ] `/v1/estimate` so anpassen, dass er Intrinsics **als JSON je Kamera**
|
||
annimmt (kein `.npz`-Zwang) – erspart NPZ-Erzeugung in Node. Format
|
||
gemeinsam festzurren (K 3×3 oder fx/fy/cx/cy, dist k1,k2,p1,p2,k3,
|
||
`image_size`).
|
||
|
||
---
|
||
|
||
## 4. Aufräumen (Altlasten aus der WSS/HTTPS-Server-Ära)
|
||
|
||
- [ ] `docker-compose.yaml`: `WSS_VIDEO_DRIVER`, `WSS_URL`, `HTTPS_PORT`-Doppelung
|
||
und `depends_on: appRobotDriver` prüfen/entfernen. Behalten: `WEBCAM_URL`,
|
||
`BODYTRACKER_URL`, Port-Mapping `2093`, Cert-Volume.
|
||
- [ ] `package.json` → `description` ist veraltet („verbindet zu WSS, sendet
|
||
Befehle").
|
||
- [ ] Command-Buttons in `public/index.html` (HOME/STOP/STATUS/RESET/PING/
|
||
GCodeMotor) rufen `window.sendCommand` – **das ist nirgends definiert**
|
||
(alter WSS-Transport). Entweder neuen Transport anbinden (gehört zu
|
||
Erweiterung „Pose an appRobotDriver") oder bis dahin deaktivieren.
|
||
- [ ] `public/snapshots` (Fallback) ist leer → `findLatestSnapshotFile()` liefert
|
||
`null` → 404. Beispiel-Datensatz ablegen **oder** Fallback dokumentiert
|
||
abschalten.
|
||
|
||
---
|
||
|
||
## 5. Frontend / UX (geplante Erweiterungen)
|
||
|
||
- [ ] Erkennungsergebnis + erkannte Pose klarer ausgeben (statt nur Roh-JSON).
|
||
- [ ] Manuelle Eingabe von `x, y, z, a, b, c, e`.
|
||
- [ ] Wenn Hand nicht erkannt: Vorschlag für bessere Arm-/Foto-Position.
|
||
- [ ] Pose an `appRobotDriver` weitergeben (neuer Schritt nach BodyTracker;
|
||
ggf. der WSS-Pfad, für den HTTPS gebraucht wird).
|
||
|
||
---
|
||
|
||
## Definition of Done (erster Meilenstein)
|
||
|
||
1. `https://<host>:2093/` liefert das statische UI über **HTTPS**.
|
||
2. `GET /api/latest-snapshot` liefert reale Bilder/Daten vom WebCam-Service.
|
||
3. `POST /api/estimate` liefert eine Pose vom BodyTracker und zeigt sie im UI.
|
||
4. Keine toten Buttons / keine WSS-Altlasten in Compose & package.json.
|