13.3.1.6. Riferimento API

La superficie pubblica del pacchetto openmv è costituita dalla classe Camera per comunicare con una cam e dalla gerarchia OMVException per gli errori di protocollo. Entrambe sono documentate in questa pagina.

13.3.1.6.1. La classe Camera

class openmv.Camera(port: str, *, baudrate: int = 921600, crc: bool = True, seq: bool = True, ack: bool = True, events: bool = True, timeout: float = 1.0, max_retry: int = 3, max_payload: int = 4096, drop_rate: float = 0.0)

Il proxy lato host per una cam OpenMV raggiunta tramite seriale USB.

Parametri:
  • port – Percorso del dispositivo seriale. Su Linux, /dev/ttyACMx per USB CDC e /dev/ttyUSBx per un ponte USB-to-UART. Su macOS, /dev/tty.usbmodem... o /dev/cu.usbmodem.... Su Windows, COMx.

  • baudrate – Baud rate seriale. Su USB, 921600 è il valore magico che fa passare la cam dal REPL di MicroPython al protocollo OpenMV – qualsiasi altro valore su un collegamento USB lascia la cam in modalità REPL, quindi è necessario usare il valore predefinito. Su un collegamento UART il valore è il baud rate effettivo della linea e può essere impostato liberamente su entrambi i lati.

  • crc – Abilita la validazione CRC su ogni pacchetto.

  • seq – Abilita i numeri di sequenza per ogni pacchetto.

  • ack – Richiede la conferma di ricezione dei pacchetti.

  • events – Abilita le notifiche di eventi dalla cam.

  • timeout – Timeout per operazione, in secondi.

  • max_retry – Numero di tentativi prima di sollevare un’eccezione su un pacchetto fallito.

  • max_payload – Dimensione massima negoziata del payload in byte. La cam può negoziare un valore inferiore.

  • drop_rate – Probabilità, solo per test, di scartare un pacchetto, in [0.0, 1.0]. Lasciare a 0.0 in produzione.

La classe supporta il protocollo del context manager; with Camera(port) as cam: chiama connect() all’ingresso e disconnect() all’uscita.

13.3.1.6.2. Connessione

Camera.connect() None

Apre la porta seriale ed esegue l’handshake del protocollo. Lo stato memorizzato in cache (elenco dei canali, informazioni di sistema, informazioni sulla versione) viene popolato come effetto collaterale. Chiamato automaticamente dal context manager.

Camera.disconnect() None

Chiude la porta seriale e rilascia il trasporto. Chiamato automaticamente all’uscita dal context manager.

Camera.is_connected() bool
Ritorna:

True se la porta seriale è aperta.

Camera.reset() None

Resetta la cam. La connessione viene interrotta perché la cam si riavvia.

Camera.boot() None

Fa entrare la cam nel suo bootloader. La connessione viene interrotta perché la cam si riavvia.

Camera.update_capabilities() None

Rinegozia le capacità del protocollo (CRC, controllo della sequenza, ACK, eventi, payload massimo) con la cam. La cam comunica il payload massimo che può gestire; la richiesta dell’host viene limitata a tale valore e le impostazioni concordate vengono rinviate. Chiamato automaticamente da connect() – non c’è motivo di chiamarlo dal codice utente, a meno che i flag del costruttore non debbano essere rinegoziati su una connessione esistente.

Camera.poll_events() None

Esegue una volta il percorso di ricezione del trasporto per consumare eventuali eventi in sospeso dalla cam senza inviare un comando. Utile in programmi di lunga durata che restano per minuti senza altro I/O e vogliono far emergere prontamente gli eventi di registrazione dei canali.

13.3.1.6.3. Esecuzione di script

Camera.exec(script: str) None

Carica script (una stringa di codice sorgente Python) nel buffer stdin della cam e ne avvia l’esecuzione.

Parametri:

script – Codice sorgente MicroPython da eseguire.

Camera.stop() None

Interrompe lo script in esecuzione. Equivalente al pulsante Stop dell’IDE.

Camera.read_stdout() str | None

Legge tutti i byte che lo script in esecuzione ha scritto su stdout dall’ultima chiamata.

Ritorna:

L’output come stringa decodificata, oppure None se non ci sono dati in attesa.

13.3.1.6.4. Streaming

Camera.streaming(enable: bool, raw: bool = False, resolution: tuple[int, int] | None = None) None

Attiva o disattiva lo stream dei frame e sceglie il formato sul filo.

Parametri:
  • enableTrue abilita lo streaming, False lo disabilita.

  • raw – Quando è False (predefinito), la cam comprime in JPEG ogni frame prima di inserirlo nel canale dello stream e read_frame() lo decomprime sull’host. Quando è True, la cam invia il buffer di pixel acquisito non compresso – la scelta giusta su cam senza supporto JPEG hardware, dove la compressione software è il passo più lento del ciclo.

  • resolution(width, height) di destinazione a cui la cam riduce in scala ogni frame grezzo prima dell’invio, dato che i frame non compressi sono molto più grandi di quelli compressi in JPEG. Obbligatorio quando raw=True; ignorato altrimenti.

Camera.read_frame() dict | None

Legge l’ultimo frame dal canale dello stream.

Ritorna:

None se nessun frame è in attesa, oppure un dict con le chiavi width (int, pixel), height (int, pixel), format (int, l’identificatore di formato pixel dichiarato dalla cam), depth (int, la dimensione dell’immagine compressa in byte per i frame JPEG / PNG; non utilizzato per i formati non compressi), data (bytes, RGB888 di lunghezza width * height * 3) e raw_size (int, byte inviati dalla cam su USB prima della decodifica).

13.3.1.6.5. Canali personalizzati

Camera.has_channel(name: str) bool
Ritorna:

True se sulla cam esiste un canale registrato con name.

Camera.channel_size(name: str) int
Ritorna:

Numero di byte attualmente disponibili sul canale indicato, oppure 0 quando il canale è vuoto o non esiste.

Camera.channel_read(name: str, size: int | None = None) bytes | None

Legge da un canale personalizzato.

Parametri:
  • name – Nome del canale registrato dallo script lato cam.

  • size – Byte da leggere, oppure None per leggere tutto ciò che è disponibile.

Ritorna:

I byte, oppure None se il canale non esiste.

Camera.channel_write(name: str, data: bytes) bool

Scrive data su un canale personalizzato. Le scritture più grandi del payload vengono automaticamente suddivise su più pacchetti.

Parametri:
  • name – Nome del canale registrato dallo script lato cam.

  • data – Payload di tipo bytes-like da inviare.

Ritorna:

True se il canale esiste e la scrittura è stata inviata, False altrimenti.

Camera.read_status() dict[str, bool]

Interroga ogni canale registrato.

Ritorna:

Dict che mappa il nome del canale a un booleano che indica «i dati sono pronti per la lettura».

Camera.update_channels() None

Aggiorna l’elenco dei canali memorizzato in cache dalla cam. Viene eseguito automaticamente alla successiva ricerca di un canale per nome dopo l’arrivo di un evento di registrazione di un canale; un’applicazione che vuole conoscere immediatamente un canale appena registrato può chiamarlo direttamente.

Camera.get_channel(name: str | None = None, channel_id: int | None = None) int | str | None

Cerca un canale per nome (restituendo il suo ID numerico) oppure per ID (restituendo il suo nome). Aggiorna prima la cache dei canali tramite update_channels() se ci sono eventi di registrazione di canali in sospeso.

Parametri:
  • name – Nome del canale da risolvere in un ID.

  • channel_id – ID del canale da risolvere in un nome.

Ritorna:

L’ID o il nome corrispondente, oppure None quando il canale non esiste. Deve essere fornito uno tra name e channel_id.

13.3.1.6.6. Introspezione del dispositivo

Camera.version() dict

Restituisce le terne di versione di protocollo, bootloader e firmware della cam. Memorizzate in cache dopo connect(). Ogni terna è una tupla (major, minor, patch) di int:

  • protocol_version – la versione del protocollo OpenMV sul filo implementata dalla cam.

  • bootloader_version – l’immagine del bootloader residente in flash.

  • firmware_version – il firmware MicroPython attualmente in esecuzione.

Camera.system_info() dict

Restituisce le informazioni sulle capacità hardware e sulla memoria della cam. Memorizzate in cache dopo connect(). Le chiavi del dict restituito ricadono in quattro gruppi.

Identità

  • cpu_id – identificatore della CPU a 32 bit.

  • device_id – tupla di 3 parole a 32 bit, il numero di serie univoco del dispositivo inciso nel silicio.

  • chip_id – tupla di 3 parole a 32 bit, una voce per ogni sensore di immagine collegato alla cam.

  • usb_vid – USB vendor ID.

  • usb_pid – USB product ID.

Dimensioni di memoria (tutte in kilobyte)

  • flash_size_kb – flash interna totale.

  • ram_size_kb – RAM totale.

  • framebuffer_size_kb – RAM riservata all’acquisizione di immagini.

  • stream_buffer_size_kb – RAM riservata al canale dello stream che invia i frame all’host.

Flag di capacità (un booleano per funzionalità, tutti denominati <feature>_present)

  • gpu_present – unità di elaborazione grafica.

  • npu_present – unità di elaborazione neurale.

  • isp_present – processore di segnale immagine.

  • venc_present – encoder video.

  • jpeg_present – encoder JPEG hardware.

  • dram_present – DRAM esterna.

  • crc_present – acceleratore CRC.

  • pmu_present – unità di monitoraggio delle prestazioni.

  • wifi_present – radio Wi-Fi.

  • bt_present – radio Bluetooth.

  • sd_present – slot per scheda SD.

  • eth_present – PHY Ethernet.

  • multicore_present – più core CPU.

Altro

  • usb_highspeed – booleano, True quando USB ha enumerato in modalità high-speed (USB 2.0 HS, 480 Mbps).

  • pmu_eventcnt – numero di contatori di eventi PMU disponibili; 0 quando non è presente alcuna PMU.

Camera.print_system_info() None

Registra il blocco formattato di informazioni di sistema su logging al livello INFO. La CLI usa questo metodo alla connessione.

13.3.1.6.7. Diagnostica

Camera.host_stats() dict
Ritorna:

I contatori a livello di trasporto tracciati sul lato host: sent, received, checksum, sequence.

Camera.device_stats() dict
Ritorna:

I contatori a livello di trasporto tracciati sul lato cam: sent, received, checksum, sequence, retransmit, transport, sent_events, max_ack_queue_depth.

13.3.1.6.8. Profiler

Il profiler riporta i conteggi delle chiamate per funzione e i tempi di esecuzione minimo / massimo / totale per i moduli del firmware strumentati – attualmente image, ml e ulab. L’ingresso e l’uscita dalle funzioni vengono intercettati al momento della compilazione; il runtime campiona un contatore monotono in microsecondi a ciascuno, accumula il risultato per funzione ed espone la tabella all’host attraverso il canale profile.

Il profiler viene incluso nel firmware solo quando a make viene passato PROFILE_ENABLE=1. Le immagini firmware di serie non lo includono – il flag -finstrument-functions che la build aggiunge ai moduli tracciati ha un sovraccarico di runtime non trascurabile, quindi le build con profilazione vengono prodotte dai sorgenti per la specifica sessione di debug che ne ha bisogno. Quando il firmware non è stato compilato con il flag, il canale profile non viene registrato e ogni metodo del profiler in questa pagina ritorna silenziosamente senza fare nulla.

L’Arm Performance Monitoring Unit (PMU) è il blocco di contatori hardware del Cortex-M55 – un piccolo insieme di contatori configurabili che tracciano conteggi di cicli, hit e miss della cache, comportamento dei branch e altri eventi definiti dall’architettura senza rallentare il codice sotto misurazione. Sulle cam che ne dispongono – la AE3 e la N6, le due cam della gamma OpenMV costruite attorno all’M55 – il profiler campiona questi contatori insieme ai dati di temporizzazione e i totali degli eventi compaiono in ogni record per funzione. Le cam senza PMU producono comunque record di temporizzazione; i campi degli eventi tornano a zero e profiler_event() non ha effetto.

Camera.profiler_mode(exclusive: bool = False) None

Passa dalla temporizzazione inclusiva a quella esclusiva e viceversa. La temporizzazione inclusiva addebita al chiamante il tempo dei chiamati; quella esclusiva no.

Parametri:

exclusiveTrue seleziona la temporizzazione esclusiva, False seleziona quella inclusiva.

Camera.profiler_reset(config: list | None = None) None

Azzera tutti i contatori del profiler. config=None ripristina anche l’assegnazione predefinita degli eventi PMU.

Parametri:

config – Riservato a future sovrascritture di configurazione per singolo contatore. Passare None per mantenere i valori predefiniti.

Camera.profiler_event(counter_num: int, event_id: int) None

Associa uno degli slot di contatore PMU a un evento hardware specifico.

Parametri:
  • counter_num – Indice del contatore.

  • event_id – Identificatore di evento definito dall’architettura.

Camera.read_profile() list[dict] | None

Restituisce i record di profilo per funzione raccolti dall’ultimo reset. Ogni record è un dict con address, caller, call_count, min_ticks, max_ticks, total_ticks, total_cycles e una tupla events dimensionata in base al pmu_eventcnt della cam.

Ritorna:

Elenco di dict record, oppure None se il canale del profiler non è disponibile o non sono stati raccolti dati.

13.3.1.6.9. Sottoclassi e dettagli interni dei canali

I metodi documentati sopra coprono ogni uso comune del pacchetto. Alcuni pattern – gestire eventi lato cam a cui l’host vuole reagire, bloccare un canale per uno scambio in più passi, comunicare con canali che trasportano dati strutturati invece di flussi di byte, o pilotare comandi di controllo specifici di un canale – richiedono metodi che Camera mantiene prefissati con un underscore. Questi nomi sono privati per convenzione (Python non li sottopone a name-mangling) e le applicazioni che ne hanno bisogno dovrebbero o derivare da Camera tramite sottoclasse o chiamare i metodi direttamente.

Sottoclassi per reagire agli eventi. Ogni evento emesso dalla cam arriva tramite Camera._handle_event(). Derivare da Camera tramite sottoclasse e sovrascrivere il metodo è il modo in cui un’applicazione reagisce agli eventi sollevati dal suo script lato cam; la pagina Eventi illustra il pattern completo.

Camera._handle_event(channel_id: int, event: int) None

Smista un evento dalla cam. Chiamato dal livello di trasporto ogni volta che arriva un pacchetto di evento. Sovrascriverlo in una sottoclasse per aggiungere una gestione specifica dell’applicazione; chiamare super()._handle_event(...) per mantenere il comportamento predefinito (aggiornamento dell’elenco dei canali su CHANNEL_REGISTERED, tracciamento della disponibilità dei frame sul canale stream, logging di avvio / arresto del canale stdin).

Parametri:
  • channel_id0 per gli eventi di sistema, altrimenti l’ID del canale registrato.

  • event – Identificatore dell’evento; i valori provengono dall’enum EventType per gli eventi di sistema e da qualsiasi cosa abbia scelto il backend del canale lato cam per gli eventi di canale.

Una sottoclasse che aggiunge i propri metodi di comunicazione con il protocollo dovrebbe decorarli con retry_if_failed() in modo che ereditino lo stesso comportamento di risincronizzazione e ritentativo di ogni metodo distribuito in questa pagina.

static Camera.retry_if_failed(func)

Decoratore. Avvolge un metodo di istanza in modo che riprovi una volta quando il trasporto solleva ResyncException. Qualsiasi metodo che chiama _send_cmd_wait_resp() (direttamente o tramite uno dei wrapper _channel_*) dovrebbe portare questo decoratore:

class MyCamera(Camera):
    @Camera.retry_if_failed
    def my_custom_command(self, payload):
        return self._send_cmd_wait_resp(Opcode.MY_CMD,
                                        0, payload)

Il blocco dei canali garantisce che lo stato del canale non cambi tra due operazioni correlate (ad esempio una _channel_size() seguita da una _channel_read(), su un canale che continua ad aggiungere dati). read_frame() e read_profile() lo usano internamente; un’applicazione che pilota un canale personalizzato con accesso in più passi fa lo stesso.

Camera._channel_lock(channel_id: int) bool

Acquisisce un lock esclusivo su un canale. Le altre operazioni dell’host sullo stesso canale si bloccano finché il lock non viene rilasciato.

Parametri:

channel_id – ID numerico del canale, tipicamente risolto con get_channel().

Ritorna:

True quando il lock è stato concesso.

Camera._channel_unlock(channel_id: int) bool

Rilascia un lock precedentemente acquisito con _channel_lock(). Sempre abbinato a una chiamata di lock; usare try / finally per assicurarsi che lo sblocco avvenga anche quando la lettura intermedia solleva un’eccezione.

Parametri:

channel_id – ID numerico del canale, tipicamente risolto con get_channel().

I canali strutturati trasportano record strutturati anziché un flusso piatto di byte. Il canale del profiler è l’esempio distribuito: la sua forma è (record_count, record_size) e un host che vuole sapere quanti record sono in attesa legge la forma anziché la dimensione in byte.

Camera._channel_shape(channel_id: int) tuple[int, ...]

Legge il descrittore di forma di un canale.

Parametri:

channel_id – ID numerico del canale, tipicamente risolto con get_channel().

Ritorna:

Tupla di interi a 32 bit senza segno che descrive la disposizione del canale. Il significato è specifico del canale.

I comandi di controllo specifici di un canale – start, stop, reset, configure – viaggiano su un singolo opcode (CHANNEL_IOCTL) con un numero di comando specifico del canale e un payload struct.pack opzionale. I metodi distribuiti come stop(), exec() e streaming() sono sottili wrapper attorno a chiamate _channel_ioctl() sui canali stdin e stream; un canale personalizzato lato cam che definisce il proprio menu di ioctl viene pilotato allo stesso modo.

Camera._channel_ioctl(channel_id: int, cmd: int, fmt: str | None = None, *args) bytes | None

Emette un comando ioctl su un canale.

Parametri:
  • channel_id – ID numerico del canale, tipicamente risolto con get_channel().

  • cmd – Numero di comando definito dal backend del canale lato cam.

  • fmt – Stringa di formato struct opzionale per la tupla di argomenti. Passare None per gli ioctl che non accettano argomenti.

  • args – Valori corrispondenti a fmt.

Ritorna:

Qualsiasi payload restituito dal canale, oppure None.

Le varianti per ID a flusso di byte dei metodi pubblici dei canali saltano la ricerca da nome a ID e accettano un offset di byte esplicito – utile per leggere un blocco dal centro di un buffer di grandi dimensioni (ad esempio i record del canale profile).

Camera._channel_size(channel_id: int) int
Parametri:

channel_id – ID numerico del canale, tipicamente risolto con get_channel().

Ritorna:

Byte attualmente disponibili sul canale.

Camera._channel_read(channel_id: int, offset: int, length: int) bytes

Legge length byte a partire da offset. Le letture su più pacchetti vengono riassemblate automaticamente.

Parametri:
  • channel_id – ID numerico del canale, tipicamente risolto con get_channel().

  • offset – Offset in byte da cui iniziare la lettura.

  • length – Numero di byte da leggere.

Camera._channel_write(channel_id: int, data: bytes, offset: int = 0) None

Scrive data all”offset indicato. Le scritture su più pacchetti vengono suddivise automaticamente su più pacchetti.

Parametri:
  • channel_id – ID numerico del canale, tipicamente risolto con get_channel().

  • data – Payload di tipo bytes-like da scrivere.

  • offset – Offset in byte da cui iniziare la scrittura.

Le primitive di protocollo sono il livello più basso che la classe espone – le voci grezze di invio-di-un-comando, recupero-dell’elenco-canali-grezzo e risincronizzazione-manuale su cui tutto quanto sopra è alla fine costruito. Un’applicazione vi ricorre quando invia un opcode che la classe non avvolge già, o quando implementa un ripristino personalizzato in una sottoclasse.

Camera._send_cmd_wait_resp(opcode: int, channel: int = 0, data: bytes = b'') bytes | None

Invia un comando di protocollo e attende la risposta della cam. La primitiva su cui ogni altro metodo di questa sezione è costruito.

Parametri:
  • opcode – Numero di comando. L’enum Opcode distribuito elenca i codici forniti con il firmware, ma il parametro è semplicemente un intero – una build firmware personalizzata può definire e rispondere ai propri.

  • channel – ID del canale, oppure 0 per i comandi di sistema.

  • data – Payload specifico del comando.

Ritorna:

Payload di risposta, oppure None per comandi come Opcode.SYS_RESET e Opcode.SYS_BOOT che interrompono la connessione.

Camera._channel_list() dict

Recupera l’elenco corrente dei canali dalla cam senza toccare i dizionari memorizzati in cache channels_by_id e channels_by_name che update_channels() popola. Utile per una sottoclasse che vuole ispezionare direttamente lo stato dei canali della cam.

Ritorna:

Dict che mappa l’ID del canale a {'name': str, 'flags': int}.

Camera._resync() None

Riesegue da zero l’handshake del protocollo. Chiamato automaticamente da connect() alla connessione iniziale e da ogni metodo pubblico che intercetta una OMVException dal trasporto. Un’applicazione che implementa il proprio ciclo di ripristino in una sottoclasse può chiamarlo direttamente dopo aver gestito l’errore sottostante.

13.3.1.6.10. Eccezioni

exception openmv.OMVException

Classe base per ogni errore a livello di protocollo. Le tre sottoclassi seguenti ereditano tutte da essa, quindi un singolo except OMVException copre l’intera superficie di errore.

exception openmv.TimeoutException

La cam non ha risposto entro il timeout configurato. Sottoclasse di OMVException.

exception openmv.ChecksumException

Il CRC di un pacchetto non ha corrisposto. Sollevata dopo che il protocollo ha esaurito il proprio budget di tentativi. Sottoclasse di OMVException.

exception openmv.SequenceException

Un pacchetto è arrivato con un numero di sequenza inatteso dopo i tentativi. Sottoclasse di OMVException.