External observer with OpenCV UI baseline

This commit is contained in:
administrator
2026-06-03 15:28:27 +02:00
parent f728524ee6
commit e86c05a885
9 changed files with 1375 additions and 47 deletions

View File

@@ -0,0 +1,261 @@
# FlyWMS Step 1 - Core/Observer Split
Data: 2026-05-29
## Scopo
Ridurre il tempo totale della demo fino a portarlo vicino alla durata reale del video, evitando che la parte visuale OpenCV rallenti il loop critico di acquisizione, inferenza e logica demo.
Lo Step 1 non cambia ancora la struttura single-process del core di calcolo, ma separa in modo netto:
- `core`: acquisizione, YOLO, tracking, macchina a stati, logging prestazioni
- `observer`: processo separato per preview e telemetria
L'obiettivo e' ottenere una demo visibile senza riportare nel loop principale il costo della vecchia UI OpenCV.
## Motivazione tecnica
I benchmark gia' disponibili dicono:
- video reale: `658.3 s`
- benchmark headless: `762.13 s`
- demo vecchia con UI integrata: molto piu' lenta
La UI OpenCV dentro al loop ha gia' dimostrato di pesare in modo determinante. La strada piu' pulita e' quindi:
1. mantenere il core il piu' simile possibile al benchmark
2. spostare la visualizzazione in un processo esterno
3. accettare che l'observer non mostri tutti i frame
## Perimetro di Step 1
Step 1 include:
- canale di telemetria `core -> observer`
- canale preview `core -> observer`
- observer separato e opzionale
- modalita' `latest update wins`
Step 1 non include ancora:
- multiprocessing tra capture e inference
- shared memory
- zero-copy
- nuovo frontend DearPyGUI
- protocollo distribuito multi-host
## Architettura proposta
### Processo core
Responsabilita':
- legge il video o la camera
- rispetta i limiti `preview_fps` e `yolo_fps`
- esegue YOLO
- aggiorna tracking e macchina a stati
- salva snapshot e gestisce WMS
- scrive `tempistiche.txt`
- pubblica telemetria e preview in modo non bloccante
Il core non deve mai aspettare l'observer.
### Processo observer
Responsabilita':
- ricevere dati dal core
- mantenere l'ultimo stato disponibile
- mostrare:
- preview principale
- eventuali preview secondarie
- comandi/stato
- fps/logica macchina a stati
L'observer puo' perdere aggiornamenti. Questo e' accettabile.
## Trasporto dati
Per Step 1 si usa un trasporto semplice su `localhost`, in modo da ridurre il rischio di complessita' prematura.
Scelta:
- socket TCP locale per preview e telemetria
Motivi:
- semplice da debuggare
- leggibile anche con strumenti esterni
- facile da riusare in seguito
- non richiede introdurre subito shared memory
## Formato messaggi
### Telemetria
Formato: JSON line-delimited o JSON framed su socket
Campi minimi previsti:
```json
{
"type": "telemetry",
"frame_id": 123,
"timestamp": 1710000000.123,
"state": "scan_level",
"command_lines": ["...", "..."],
"motion_text": "MOTO: stabile ...",
"snapshot_counter": 4,
"det_count": 2,
"label_count": 1,
"track_count": 2,
"active_track_count": 2,
"run_yolo": true,
"last_yolo_ms": 28.4,
"loop_fps": 25.8,
"yolo_fps": 12.6,
"video_fps": 30.0,
"preview_fps": 30.0,
"yolo_target_fps": 15.0
}
```
### Preview
Formato: messaggio con header JSON + payload JPEG.
Campi minimi header:
```json
{
"type": "preview",
"stream": "navigate",
"frame_id": 123,
"timestamp": 1710000000.123,
"width": 960,
"height": 540,
"encoding": "jpeg",
"jpeg_size": 45231
}
```
Il payload binario segue subito dopo l'header.
## Frequenze observer
Per non pesare sul core:
- telemetria: fino a `5-10 Hz`
- preview principale: `3-5 fps`
- preview snapshot/etichetta: solo su evento o ultima disponibile
Step 1 non ha l'obiettivo di mostrare una preview fluida. Ha l'obiettivo di restare credibile a livello demo senza penalizzare il core.
## Strategia "latest update wins"
Il core non accumula backlog per l'observer.
Regole:
- se l'observer e' lento, gli aggiornamenti vecchi possono essere scartati
- il core invia solo l'ultimo stato rilevante
- nessuna coda lunga per la preview
Questo vale in particolare per:
- preview `navigate`
- testo comandi
- metriche fps
## Gestione overlay
Step 1 adotta una soluzione intermedia:
- il core genera una preview gia' ridotta
- il core puo' continuare a disegnare l'overlay minimo necessario sulla preview inviata
- l'observer resta semplice e mostra il risultato
Questo non e' il modello finale ideale, ma riduce il lavoro di riscrittura nello Step 1.
Evoluzione futura possibile:
- inviare frame piu' bbox/stato
- disegnare overlay interamente nell'observer
## Modalita' di fallback
Il sistema deve funzionare anche senza observer.
Regole:
- se l'observer non e' avviato, il core continua a lavorare
- se il socket non e' disponibile, il core logga e prosegue
- se l'observer si scollega, il core non deve bloccarsi
Questo e' un requisito fondamentale dello Step 1.
## Parametri di configurazione da introdurre
Nuovi parametri suggeriti nel file INI:
- `observer_enabled = true/false`
- `observer_host = 127.0.0.1`
- `observer_port = 8765`
- `observer_preview_fps = 4.0`
- `observer_preview_width = 960`
- `observer_jpeg_quality = 75`
- `observer_telemetry_fps = 8.0`
## File previsti
### Nuovo file
- `flywms_navigation_observer.py`
Responsabilita':
- connettersi al core
- ricevere messaggi
- mantenere ultimo stato per stream
- mostrare finestre OpenCV lato observer
### Modifiche a file esistente
- `flywms_navigation.py`
- aggiunta configurazione observer
- serializzazione telemetria
- invio preview/telemetria non bloccante
- disattivazione progressiva della vecchia UI integrata
## Piano implementativo di Step 1
1. aggiungere parametri observer a config e argparse
2. creare un piccolo publisher non bloccante nel core
3. creare `flywms_navigation_observer.py`
4. pubblicare:
- preview `navigate`
- preview `snapshot`
- preview `etichetta`
- telemetria/comandi
5. rendere opzionale la vecchia UI integrata
6. testare:
- core senza observer
- core con observer
- benchmark con observer attivo ma leggero
## Criteri di successo
Step 1 e' considerato riuscito se:
1. il core continua a funzionare senza finestre locali
2. l'observer mostra una preview leggibile e lo stato della missione
3. l'observer non blocca il core se rallenta o si chiude
4. il tempo totale della demo si avvicina al benchmark headless, senza ricadere nella penalizzazione della vecchia UI
## Limiti noti
- Step 1 non risolve ancora il costo seriale di `cap.read()` e inferenza
- Step 1 non introduce ancora il multiprocessing tra capture e inference
- Step 1 non ottimizza ancora l'uso adattivo di YOLO
Questi temi restano demandati agli Step 2 e 3.