5.7 KiB
5.7 KiB
AppRobotWebcam – Roadmap
Ziel
Sauberer, fokussierter Webcam-Streaming-Service als Docker-Container.
Kein Robot-Control, kein ArUco – nur zwei Verantwortlichkeiten:
- Live-Video mit minimaler Latenz (MJPEG über WebSocket)
- Standbilder auf Abruf via HTTP REST (
/api/snapshot/cam{n})
Das Homing-Projekt holt seine Standbilder über den Snapshot-Endpunkt – keine weitere Kopplung nötig.
Architektur
USB Kameras
│
▼
FFmpeg (v4l2 → MJPEG)
│
▼
Node.js Server (Express + ws)
├── WebSocket /ws/cam0, /ws/cam1 → Browser (Live-Stream)
└── HTTP GET /api/snapshot/cam0 → Homing-Projekt (JPEG)
Stack-Entscheide (bereits umgesetzt):
| Komponente | Wahl | Begründung |
|---|---|---|
| Webserver | Node.js + Express | Wartbar, grosses Ecosystem, user-präferiert |
| WebSocket | ws-Library |
Schlank, bewährt, kein Overhead |
| Video-Capture | FFmpeg | Stabil, flexibel, MJPEG-passthrough möglich |
| Stream-Protokoll | MJPEG über WebSocket | Geringste Latenz, einfach im Browser |
| Snapshot-API | HTTP GET → raw JPEG | Einfachste Schnittstelle für Consumer |
| Container | dockerfile_inline in docker-compose |
Kein separates Dockerfile, Portainer-tauglich |
Tasks
Phase 1 – Grundgerüst ✅ (erledigt)
- Projektstruktur anlegen
package.jsonmit Abhängigkeiten (express, ws)docker-compose.yamlmitdockerfile_inline(Node.js + FFmpeg, kein separates Dockerfile)server.js– HTTP + WebSocket-Server, Graceful Shutdownsrc/deviceDetect.js– Kamera-Erkennung (env → by-id → /dev/video*)src/videoStream.js– FFmpegStreamer (MJPEG splitten, WebSocket broadcast, Auto-Restart mit Backoff)src/snapshotService.js– REST-Endpunkt: aktuellstes Frame aus laufendem Streampublic/index.html+public/viewer.js– Basis-Viewer
Phase 2 – Deployment & Latenz-Baseline
- Kamera-Zugriff im Container verifizieren:
/dev/video0und/dev/video2im Container sichtbargroup_add: videogreift (Zugriffsrechte)- Fallback auf YUYV422 wenn MJPEG nicht unterstützt
- Latenz messen (Baseline):
- Uhr auf Kamera richten, Screenshot → Differenz ablesen
- Zielwert: <100 ms Ende-zu-Ende (Kamera → Browser-Pixel)
- Multi-Format-Fallback implementieren: MJPEG → YUYV422 → RGB24
- Health-Endpunkt
/healtherweitern: Kamera-Status, verbundene Clients, FPS
Phase 3 – Latenz optimieren
- FFmpeg-Flags tunen für minimale Latenz:
-fflags nobuffer -flags low_delay -probesize 32 -analyzeduration 0 - Native MJPEG pass-through testen:
Wenn Kamera MJPEG nativ bei Zielauflösung liefert →
-vcodec copy(kein Re-Encoding, minimale CPU-Last, minimale Latenz) - Canvas-Rendering im Browser:
createImageBitmap()statt Blob-URL-Overhead - WebRTC evaluieren: <50 ms möglich, aber STUN/TURN-Komplexität in Docker – sinnvoll erst wenn MJPEG-Latenz >150 ms bleibt
Phase 4 – Hochauflösende Snapshots
Aktuell: Snapshot = letztes Frame aus dem Stream (Auflösung = Stream-Auflösung).
Ziel: Snapshot in originaler Kamera-Auflösung (z.B. 1280×960).
Drei Optionen (noch offen):
| Option | Vorgehen | Pro | Contra |
|---|---|---|---|
| A | Stream-Frame direkt nehmen | Sofort, kein Aufwand | Auflösung = Stream-Auflösung |
| B | Zweite FFmpeg-Pipeline 0.5 FPS High-Res | Immer verfügbar | CPU-Last, pipe:3 Komplexität |
| C | Einmaliger ffmpeg -frames:v 1 on-demand |
Hohe Qualität | ~500 ms Delay, Stream-Unterbrechung |
- Option wählen und implementieren
- Mit Homing-Projekt testen (Consumer von
/api/snapshot) - Snapshot-Metadaten in Response-Headern: Zeitstempel, Auflösung, Kamera-ID
- Optionaler Webhook: POST nach Snapshot an konfigurierbaren Endpunkt
Phase 5 – Robustheit & Produktion
- Kamera hot-plug: Stream-Neustart wenn
/dev/videoXverschwindet/wiederkommt - Resource Limits:
--memory 512m --cpus 1.0in docker-compose - HTTPS: Reverse Proxy (nginx/traefik) vorschalten – kein TLS im App-Code
- JSON-Logging mit Level (info/warn/error)
- Kamera-Parameter per env var:
CAM0_WIDTH,CAM0_HEIGHT,CAM0_FPS,CAM0_QUALITY
Abgrenzung zu appRobotVideoControls
| Feature | appRobotVideoControls | appRobotWebcam |
|---|---|---|
| Video-Streaming | ✅ | ✅ (verbessert) |
| Snapshots | ✅ (komplex, dual-pipe) | ✅ (HTTP REST, einfach) |
| Robot-Control (G-Code) | ✅ | ❌ anderes Projekt |
| ArUco / Homing | ✅ (Python+OpenCV) | ❌ anderes Projekt |
| Gamepad / Keyboard | ✅ | ❌ |
| HTTPS (self-signed) | ✅ | ❌ (Reverse Proxy empfohlen) |
| Separates Dockerfile | ✅ (gross, OpenCV-Build) | ❌ (inline in compose) |
Ports & Netzwerk
| Service | Container-Port | Host-Port |
|---|---|---|
| HTTP + WS | 8080 | 8444 |
# Netzwerk einmalig erstellen (falls noch nicht vorhanden)
docker network create appRobotNet
Datei-Struktur
appRobotWebcam/
├── src/
│ ├── deviceDetect.js Kamera-Erkennung (env → by-id → /dev/video*)
│ ├── videoStream.js FFmpeg-MJPEG-Streamer + WebSocket-Broadcast
│ └── snapshotService.js REST-Router für /api/snapshot
├── public/
│ ├── index.html Basis-Viewer
│ └── viewer.js WebSocket-Client, MJPEG-Rendering
├── doc/
│ ├── 01_WebcamRoadmap.md (diese Datei)
│ └── 05_OptionalToDo_roadmap.md Control-Optionen
├── docker-compose.yaml Einzige Docker-Datei (dockerfile_inline)
├── package.json
└── server.js Einstiegspunkt