# Step 2 - Disaccoppiamento Capture / Inference ## Obiettivo Ridurre la serializzazione del loop principale separando: - acquisizione video e campionamento metadati; - inferenza, tracking e logica demo. Lo scopo non e' introdurre ancora una pipeline completa multi-processo stile ROS, ma togliere dal percorso critico almeno la parte `cap.read()` e la preparazione del pacchetto frame. ## Vincolo architetturale Il frame consumato dall'inferenza non puo' essere un'immagine grezza isolata. Ogni frame deve essere rappresentato da un pacchetto logico di acquisizione che congela nello stesso istante: - `frame_id` - `timestamp` - `video_time_sec` - immagine - posa / stato del drone campionati nel momento di acquisizione Questo segue il modello gia' fissato nei documenti di architettura: - `capture` non inventa la posa; - `capture` la campiona dalla sorgente di stato disponibile; - `inference` consuma un `CapturedFrame` gia' coerente. Nel contesto della demo video attuale non esiste ancora una posa SLAM reale. Quindi il campo posa verra' popolato con una posa simulata minima, ma congelata all'acquisizione, utile a: - mantenere il contratto architetturale corretto; - evitare che in futuro frame e stato si disallineino; - propagare i metadati fino agli snapshot. ## Struttura dati proposta ```text CapturedFrame - frame_id - timestamp - video_time_sec - frame - pose ``` Dove `pose` e' un dizionario o struttura equivalente con almeno: - `mode` - `frame_id` - `video_time_sec` - `scan_direction` - `route_progress_ratio` Il campo `pose` potra' essere sostituito piu' avanti da un provider reale SLAM / PX4 / odometria senza cambiare il contratto tra capture e inference. ## Strategia di esecuzione ### Capture worker Un worker separato: - legge da `VideoCapture` - costruisce `CapturedFrame` - pubblica solo l'ultimo frame disponibile ### Inference / control loop Il loop principale: - legge l'ultimo `CapturedFrame` - esegue YOLO, tracking e logica demo - usa sempre i metadati congelati nel pacchetto ## Regola di coda La coda deve essere piccola: - niente backlog lungo; - meglio perdere frame che accumulare ritardo; - politica `latest frame wins`. ## Impatto sul codice esistente ### Nuove entita' - `CapturedFrame` - `CaptureWorker` - helper `sample_demo_pose(...)` ### Oggetti da aggiornare - `CandidateSnapshot` - `NavigationSnapshot` - metadata snapshot JSON - observer telemetry, se utile, con riferimento alla posa dell'ultimo frame ## Criteri di successo 1. il core continua a produrre lo stesso comportamento funzionale della demo; 2. inferenza e snapshot lavorano su frame con metadati coerenti; 3. `cap.read()` non sta piu' nel loop principale critico; 4. nessun backlog crescente; 5. nessun blocco se il capture worker arriva piu' veloce o piu' lento del consumer.