protocol — Canali del protocollo OpenMV¶
Il modulo protocol espone il protocollo host di OpenMV a Python. Consente di inizializzare e configurare lo stack di protocollo lato firmware e permette al codice utente di registrare canali logici personalizzati supportati da un oggetto Python che implementa l’interfaccia del canale (read, write, size, poll, ecc.). È ciò con cui dialogano gli strumenti companion desktop quando trasmettono dati immagine in streaming o espongono widget interattivi a una camera collegata.
Esempi¶
Trasmette in streaming un’immagine RGB565 a uno strumento host usando un backend personalizzato che implementa l’interfaccia raw del canale (backend.size(), backend.shape(), backend.poll(), backend.read()):
import csi
import protocol
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.HD)
img = csi0.snapshot()
img_mv = memoryview(img.bytearray())
frame_ready = True
class FrameChannel:
def size(self):
return len(img_mv)
def shape(self):
return (img.height(), img.width(), len(img_mv))
def poll(self):
return frame_ready
def read(self, offset, size):
global frame_ready
end = offset + size
chunk = img_mv[offset:end]
if end >= len(img_mv):
frame_ready = False
return chunk
protocol.register(name="frame", backend=FrameChannel())
while True:
if not frame_ready:
img = csi0.snapshot()
img_mv = memoryview(img.bytearray())
frame_ready = True
Lo script lato host corrispondente, che usa il pacchetto Python openmv (pip install openmv) per connettersi, inviare lo script sulla camera e recuperare ogni frame:
import cv2
import numpy as np
from openmv.camera import Camera
# The on-cam script above, stored as a string (or read from a file).
SCRIPT = open("frame_streamer_on_cam.py").read()
with Camera("/dev/ttyACM0", baudrate=921600) as cam:
cam.stop()
cam.exec(SCRIPT)
while True:
status = cam.read_status()
if not cam.has_channel("frame") or not status.get("frame"):
continue
h, w, size = cam._channel_shape(cam.get_channel(name="frame"))
if cam.channel_size("frame") < size:
continue
data = cam.channel_read("frame", size)
rgb565 = np.frombuffer(data, dtype="<u2").reshape(h, w)
# Unpack RGB565 to an HxWx3 uint8 RGB image.
r = ((rgb565 >> 11) & 0x1F) << 3
g = ((rgb565 >> 5) & 0x3F) << 2
b = ( rgb565 & 0x1F) << 3
frame = np.dstack([r, g, b]).astype(np.uint8)
# Display with OpenCV (cv2 expects BGR, not RGB).
cv2.imshow("OpenMV", cv2.cvtColor(frame, cv2.COLOR_RGB2BGR))
if cv2.waitKey(1) == ord("q"):
break
cv2.destroyAllWindows()
Sostituisci /dev/ttyACM0 con la porta seriale della camera (ad esempio COM3 su Windows). Il costruttore openmv.camera.Camera accetta gli stessi parametri di protocollo di init (crc / seq / ack / events / max_payload / max_retry / timeout) quando lo stack lato camera è stato riconfigurato in modo corrispondente.
Funzioni¶
- protocol.init(crc: bool = True, seq: bool = True, ack: bool = True, events: bool = True, max_payload: int = ..., rtx_retries: int = 3, rtx_timeout_ms: int = 500, lock_interval_ms: int = 10, poll_ms: int = 0) None¶
Inizializza (o riconfigura) lo stack di protocollo e registra i canali di dati logici predefiniti (
stdin,stdout,streame, se compilato,profile). SollevaRuntimeErrorse l’inizializzazione fallisce. Il firmware si avvia con uno stack di protocollo USB predefinito già in esecuzione, quindi richiamare questa funzione è necessario solo per cambiare il trasporto o sovrascrivere i parametri di framing predefiniti.crcabilita la validazione CRC sui frame di protocollo.seqabilita il tracciamento dei numeri di sequenza.ackabilita gli acknowledgement per ogni frame.eventsabilita le notifiche di evento del canale.max_payloadè la dimensione massima del payload in byte. Se omesso viene usato il valore predefinito per camera indicato di seguito; deriva dalla dimensione del buffer di protocollo di ciascuna scheda secondo la formulabuffer - 10 (header) - 4 (CRC).Camera
Dimensione buffer
Payload massimo
OpenMV Cam M4 (
OPENMV2)512
498
OpenMV Cam M7 (
OPENMV3)512
498
OpenMV Cam H7 (
OPENMV4)512
498
OpenMV Cam H7 Plus (
OPENMV4P)4096
4082
OpenMV Pure Thermal (
OPENMVPT)4096
4082
OpenMV Cam RT1062 (
OPENMV_RT1060)4096
4082
OpenMV Cam N6 (
OPENMV_N6)8192
8178
OpenMV AE3 (
OPENMV_AE3)8192
8178
Arduino Portenta H7 (
ARDUINO_PORTENTA_H7)4096
4082
Arduino Giga (
ARDUINO_GIGA)4096
4082
Arduino Nicla Vision (
ARDUINO_NICLA_VISION)4096
4082
rtx_retriesè il numero di tentativi di ritrasmissione. Predefinito3.rtx_timeout_msè il timeout di ritrasmissione in millisecondi (raddoppiato dopo ogni timeout). Predefinito500.lock_interval_msè l’intervallo di lock minimo in millisecondi. Predefinito10.poll_msè l’intervallo di polling in millisecondi.0(il valore predefinito) disabilita il polling tramite timer.
- protocol.is_active() bool¶
Restituisce
Truese un host è attualmente connesso e lo stack di protocollo è attivo, altrimentiFalse.
- protocol.register(name: str, *, backend: object, flags: int = 0) ProtocolChannel¶
Registra un oggetto Python
backendcome nuovo canale logico e restituisce un handleProtocolChannel. I metodi disponibili dell’oggettobackend(vedi Interfaccia del backend di seguito) determinano le capacità del canale;protocol.CHANNEL_FLAG_READ,protocol.CHANNEL_FLAG_WRITEeprotocol.CHANNEL_FLAG_LOCKvengono aggiunti automaticamente aflagsquando i metodi corrispondenti sono implementati.nameè il nome del canale come stringa. Viene troncato alla dimensione del buffer del nome canale del firmware. Obbligatorio.backendè l’oggetto Python che implementa l’interfaccia del backend. Obbligatorio. Tipicamente passato per parola chiave (backend=...).flagssono bit di flag aggiuntivi del canale (vedi le costantiCHANNEL_FLAG_*). Opzionale; il valore predefinito è0.Solleva
RuntimeErrorse il canale non può essere registrato (ad esempio se non ci sono slot di canale liberi).
Classi¶
- class protocol.ProtocolChannel¶
Handle restituito da
protocol.register. Le istanze non vengono costruite direttamente.
Interfaccia del backend¶
Un oggetto backend passato a protocol.register può implementare un qualsiasi sottoinsieme dei metodi seguenti. Solo i metodi presenti nell’oggetto vengono collegati al livello di protocollo C; i metodi mancanti lasciano disabilitata la capacità corrispondente.
- class protocol.backend¶
Oggetto backend del canale passato a
protocol.register. I metodi seguenti descrivono l’interfaccia opzionale che un backend Python può implementare.- init() object¶
Richiamato una volta sola quando il canale viene inizializzato. Restituisce un qualsiasi valore diverso da
Nonein caso di successo; un’eccezione o un valore di ritorno mancante viene trattato come errore.
- shape() tuple¶
Restituisce una tupla di un massimo di quattro interi che descrivono la forma dei dati (ad esempio le dimensioni dell’immagine). Il livello di protocollo consuma fino a quattro elementi.
- flush() object¶
Svuota eventuali dati in sospeso. Restituisce un qualsiasi valore diverso da
Nonein caso di successo.
- read(offset: int, size: int) bytes¶
Restituisce fino a
sizebyte a partire daoffsetcome oggetto di tipobytesche supporta il protocollo buffer.
- readp(offset: int, size: int) bytes¶
Variante zero-copy di
read. Restituisce un buffer la cui memoria sottostante viene letta direttamente dal livello di protocollo; il buffer deve rimanere valido per tutta la durata del trasferimento.
- write(offset: int, data: bytearray) int¶
Scrive
dataaoffset.dataè unbytearrayche fa riferimento direttamente al buffer C. Restituisce il numero di byte scritti, oppure0come successo predefinito.
- class protocol.CBORChannel(on_read: Callable | None = None, on_write: Callable | None = None)¶
Un backend Python di livello più alto (fornito dal pacchetto
protocolcongelato) che serializza campi denominati in CBOR usando chiavi intere compatibili con SenML. Supporta widget di visualizzazione (label,depth) e controlli interattivi (toggle,slider,select) con callbackon_read/on_write.on_readè un callable opzionaleon_read(channel)invocato prima che il canale venga serializzato per l’host. Usalo per aggiornare i valori dei campi.on_writeè un callable opzionaleon_write(channel, name, value)invocato quando l’host scrive un nuovo valore per un campo denominato.- add(name: str, type: str, value: Any = None, unit: str | None = None, min: int | float | None = None, max: int | float | None = None, step: int | float | None = None, options: list | None = None, width: int | None = None, height: int | None = None) None¶
Aggiunge un campo denominato al canale.
nameè il nome visualizzato; deve essere univoco all’interno di questo canale.typeè il tipo di widget:"label","toggle","slider","select"o"depth".valueè il valore iniziale. Il valore predefinito dipende datype.unitè la stringa dell’unità perlabel/slider(ad esempio"Cel","%RH").minè il valore minimo (intervallo dello slider o intervallo di profondità).maxè il valore massimo (intervallo dello slider o intervallo di profondità).stepè la dimensione del passo (slider).optionsè l’elenco delle stringhe di opzione (select).widthè la larghezza in pixel (depth).heightè l’altezza in pixel (depth).
- __getitem__(name: str) object¶
Restituisce il valore corrente del campo denominato. Per i campi
depthviene restituito il buffer di dati binari, altrimenti il valore scalare.
- __setitem__(name: str, value: Any) None¶
Imposta il valore del campo denominato. Per i campi
slider, una tupla(min, max, value)aggiorna simultaneamente l’intervallo e il valore corrente. Per i campidepth,valueè il buffer di dati binari.
- poll() bool¶
Metodo dell’interfaccia del backend. Restituisce
Truequando ci sono dati serializzati disponibili per l’host.
- size() int¶
Metodo dell’interfaccia del backend. Invoca
on_read(se impostato) e restituisce la dimensione del buffer serializzato.
Costanti¶
Bit di flag del canale (combinati bit a bit; passati a protocol.register tramite flags o impostati automaticamente in base ai metodi del backend).
- protocol.CHANNEL_FLAG_PHYSICAL: int¶
Il canale rappresenta un trasporto fisico (in contrapposizione a un canale di dati logico).
Identificatori dei canali integrati.