protocol — OpenMV-Protokollkanäle¶
Das Modul protocol stellt das OpenMV-Host-Protokoll für Python bereit. Es erlaubt die Initialisierung und Konfiguration des firmwareseitigen Protokoll-Stacks und ermöglicht es Benutzercode, eigene logische Kanäle zu registrieren, die von einem Python-Objekt unterstützt werden, das die Kanalschnittstelle implementiert (read, write, size, poll usw.). Mit diesem kommunizieren Desktop-Begleittools, wenn sie Bilddaten streamen oder interaktive Widgets an einer verbundenen Kamera bereitstellen.
Beispiele¶
Streamt ein RGB565-Bild an ein Host-Tool über ein eigenes Backend, das die Roh-Kanalschnittstelle implementiert (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
Das passende hostseitige Skript, das das openmv-Python-Paket (pip install openmv) verwendet, um eine Verbindung herzustellen, das kameraseitige Skript zu übertragen und jedes Einzelbild abzurufen:
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()
Ersetzen Sie /dev/ttyACM0 durch den seriellen Port der Kamera (z. B. COM3 unter Windows). Der Konstruktor openmv.camera.Camera akzeptiert dieselben Protokollparameter wie init (crc / seq / ack / events / max_payload / max_retry / timeout), wenn der kameraseitige Stack passend neu konfiguriert wurde.
Funktionen¶
- 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¶
Initialisiert (oder rekonfiguriert) den Protokoll-Stack und registriert die logischen Standard-Datenkanäle (
stdin,stdout,streamund, falls einkompiliert,profile). LöstRuntimeErroraus, wenn die Initialisierung fehlschlägt. Die Firmware startet mit einem bereits laufenden USB-Standard-Protokoll-Stack, sodass dieser Aufruf nur erforderlich ist, um den Transport zu ändern oder die Standard-Framing-Parameter zu überschreiben.crcaktiviert die CRC-Validierung von Protokoll-Frames.seqaktiviert die Verfolgung von Sequenznummern.ackaktiviert Bestätigungen pro Frame.eventsaktiviert Kanal-Ereignisbenachrichtigungen.max_payloadist die maximale Nutzlastgröße in Bytes. Wird sie weggelassen, wird der untenstehende kameraspezifische Standardwert verwendet; er wird aus der Protokoll-Puffergröße der jeweiligen Platine alsbuffer - 10 (header) - 4 (CRC)abgeleitet.Kamera
Puffergröße
Maximale Nutzlast
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_retriesist die Anzahl der erneuten Übertragungsversuche. Standardwert3.rtx_timeout_msist das Zeitlimit für die erneute Übertragung in Millisekunden (verdoppelt sich nach jedem Zeitüberschreiten). Standardwert500.lock_interval_msist das minimale Sperrintervall in Millisekunden. Standardwert10.poll_msist das Abfrageintervall in Millisekunden.0(der Standardwert) deaktiviert das Timer-Polling.
- protocol.is_active() bool¶
Gibt
Truezurück, wenn aktuell ein Host verbunden und der Protokoll-Stack aktiv ist, andernfallsFalse.
- protocol.register(name: str, *, backend: object, flags: int = 0) ProtocolChannel¶
Registriert ein Python-
backend-Objekt als neuen logischen Kanal und gibt einProtocolChannel-Handle zurück. Die verfügbaren Methoden desbackend-Objekts (siehe Backend-Schnittstelle unten) bestimmen die Fähigkeiten des Kanals;protocol.CHANNEL_FLAG_READ,protocol.CHANNEL_FLAG_WRITEundprotocol.CHANNEL_FLAG_LOCKwerden automatisch zuflagshinzugefügt, wenn die entsprechenden Methoden implementiert sind.nameist der Kanalname als Zeichenkette. Wird auf die Größe des Kanalnamen-Puffers der Firmware gekürzt. Erforderlich.backendist das Python-Objekt, das die Backend-Schnittstelle implementiert. Erforderlich. Wird typischerweise als Schlüsselwort übergeben (backend=...).flagssind zusätzliche Kanal-Flag-Bits (siehe dieCHANNEL_FLAG_*-Konstanten). Optional; Standardwert0.Löst
RuntimeErroraus, wenn der Kanal nicht registriert werden kann (z. B. wenn keine freien Kanalplätze vorhanden sind).
Klassen¶
- class protocol.ProtocolChannel¶
Handle, das von
protocol.registerzurückgegeben wird. Instanzen werden nicht direkt erstellt.
Backend-Schnittstelle¶
Ein an protocol.register übergebenes Backend-Objekt kann eine beliebige Teilmenge der folgenden Methoden implementieren. Nur die auf dem Objekt vorhandenen Methoden werden mit der C-Protokollschicht verdrahtet; fehlende Methoden lassen die entsprechende Fähigkeit deaktiviert.
- class protocol.backend¶
Kanal-Backend-Objekt, das an
protocol.registerübergeben wird. Die folgenden Methoden beschreiben die optionale Schnittstelle, die ein Python-Backend implementieren kann.- init() object¶
Wird einmal aufgerufen, wenn der Kanal initialisiert wird. Gibt bei Erfolg einen beliebigen Wert ungleich
Nonezurück; eine Ausnahme oder ein fehlender Rückgabewert wird als Fehler behandelt.
- shape() tuple¶
Gibt ein Tupel aus bis zu vier Ganzzahlen zurück, das die Datenform beschreibt (z. B. Bildabmessungen). Bis zu vier Elemente werden von der Protokollschicht verbraucht.
- flush() object¶
Schreibt alle ausstehenden Daten aus. Gibt bei Erfolg einen beliebigen Wert ungleich
Nonezurück.
- read(offset: int, size: int) bytes¶
Gibt bis zu
sizeBytes aboffsetalsbytes-ähnliches Objekt zurück, das das Buffer-Protokoll unterstützt.
- readp(offset: int, size: int) bytes¶
Zero-Copy-Variante von
read. Gibt einen Puffer zurück, dessen zugrunde liegender Speicher direkt von der Protokollschicht gelesen wird; der Puffer muss für die Dauer der Übertragung gültig bleiben.
- write(offset: int, data: bytearray) int¶
Schreibt
dataanoffset.dataist einbytearray, das direkt auf den C-Puffer verweist. Gibt die Anzahl der geschriebenen Bytes zurück oder0bei standardmäßigem Erfolg.
- class protocol.CBORChannel(on_read: Callable | None = None, on_write: Callable | None = None)¶
Ein übergeordnetes Python-Backend (bereitgestellt durch das eingefrorene Paket
protocol), das benannte Felder mit SenML-kompatiblen Ganzzahl-Schlüsseln in CBOR serialisiert. Unterstützt Anzeige-Widgets (label,depth) und interaktive Steuerelemente (toggle,slider,select) miton_read/on_write-Callbacks.on_readist ein optionales aufrufbares Objekton_read(channel), das aufgerufen wird, bevor der Kanal für den Host serialisiert wird. Verwenden Sie es, um Feldwerte zu aktualisieren.on_writeist ein optionales aufrufbares Objekton_write(channel, name, value), das aufgerufen wird, wenn der Host einen neuen Wert für ein benanntes Feld schreibt.- 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¶
Fügt dem Kanal ein benanntes Feld hinzu.
nameist der Anzeigename; muss innerhalb dieses Kanals eindeutig sein.typeist der Widget-Typ:"label","toggle","slider","select"oder"depth".valueist der Anfangswert. Der Standardwert hängt vontypeab.unitist die Einheitenzeichenkette fürlabel/slider(z. B."Cel","%RH").minist der Minimalwert (Schieberegler-Bereich oder Tiefenbereich).maxist der Maximalwert (Schieberegler-Bereich oder Tiefenbereich).stepist die Schrittweite (Schieberegler).optionsist die Liste der Optionszeichenketten (Auswahl).widthist die Breite in Pixeln (Tiefe).heightist die Höhe in Pixeln (Tiefe).
- __getitem__(name: str) object¶
Gibt den aktuellen Wert des benannten Feldes zurück. Bei
depth-Feldern wird der Binärdatenpuffer zurückgegeben, andernfalls der Skalarwert.
- __setitem__(name: str, value: Any) None¶
Setzt den Wert des benannten Feldes. Bei
slider-Feldern aktualisiert ein(min, max, value)-Tupel den Bereich und den aktuellen Wert gleichzeitig. Beidepth-Feldern istvalueder Binärdatenpuffer.
- poll() bool¶
Methode der Backend-Schnittstelle. Gibt
Truezurück, wenn serialisierte Daten für den Host verfügbar sind.
- size() int¶
Methode der Backend-Schnittstelle. Ruft
on_readauf (falls gesetzt) und gibt die Größe des serialisierten Puffers zurück.
Konstanten¶
Kanal-Flag-Bits (bitweise kombiniert; an protocol.register über flags übergeben oder automatisch anhand der Methoden des Backends gesetzt).
- protocol.CHANNEL_FLAG_PHYSICAL: int¶
Der Kanal stellt einen physischen Transport dar (im Gegensatz zu einem logischen Datenkanal).
Integrierte Kanalkennungen.