protocol — OpenMV-protocolkanalen#
De protocol module stelt het OpenMV-hostprotocol beschikbaar aan Python. Het maakt het mogelijk om de protocolstack aan de firmwarezijde te initialiseren en te configureren, en laat gebruikerscode aangepaste logische kanalen registreren die worden ondersteund door een Python-object dat de kanaalinterface implementeert (read, write, size, poll, enz.). Dit is waar desktop-begeleidingstools mee communiceren wanneer ze afbeeldingsgegevens streamen of interactieve widgets beschikbaar maken aan een verbonden camera.
Voorbeelden#
Stream een RGB565-afbeelding naar een hosttool met behulp van een aangepaste backend die de raw-kanaalinterface implementeert (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
Het bijbehorende script aan de hostzijde, dat het openmv Python-pakket (pip install openmv) gebruikt om verbinding te maken, het script op de camera te pushen en elk frame op te halen:
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()
Vervang /dev/ttyACM0 door de seriële poort van de camera (bijv. COM3 op Windows). De openmv.camera.Camera constructor accepteert dezelfde protocolparameters als init (crc / seq / ack / events / max_payload / max_retry / timeout) wanneer de stack aan de camerazijde overeenkomstig is geherconfigureerd.
Functies#
- 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#
Initialiseert (of herconfigureert) de protocolstack en registreert de standaard logische datakanalen (
stdin,stdout,streamen, indien meegecompileerd,profile). GenereertRuntimeErrorals de initialisatie mislukt. De firmware start op met een standaard USB-protocolstack die al draait, dus deze aanroep is alleen nodig om het transport te wijzigen of de standaard framing-parameters te overschrijven. Opnieuw aanroepen herinitialiseert de stack: de vorige polling-timer wordt verwijderd en de kanalen worden opnieuw geregistreerd.crcschakelt CRC-validatie van protocolframes in.seqschakelt het bijhouden van volgnummers in.ackschakelt bevestigingen per frame in.eventsschakelt kanaalgebeurtenis-notificaties in.max_payloadis de maximale payloadgrootte in bytes. Indien weggelaten wordt de onderstaande standaardwaarde per camera gebruikt; deze is afgeleid van de protocolbuffergrootte van elk board alsbuffer - 10 (header) - 4 (CRC).Camera
Buffergrootte
Max. payload
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_retriesis het aantal hertransmissiepogingen. Standaard3.rtx_timeout_msis de hertransmissie-timeout in milliseconden (verdubbeld na elke timeout). Standaard500.lock_interval_msis het minimale vergrendelingsinterval in milliseconden. Standaard10.poll_msis het polling-interval in milliseconden.0(de standaardwaarde) schakelt timer-polling uit.
- protocol.is_active() bool#
Retourneert
Trueals er momenteel een host verbonden is en de protocolstack actief is, andersFalse.
- protocol.poll() int#
Voert één iteratie van de protocoltaak uit: leegt de ontvangstbuffer van het transport, parseert eventuele complete frames, verwerkt commando’s en handelt kanaalgebeurtenissen af. Normaal doet de firmware dit voor je vanuit de USB-interrupt en vanuit de
poll_ms-timer, dus dit is alleen nodig voor aangepaste transporten die door geen van beide worden aangestuurd – bijvoorbeeld wanneerpoll_ms=0en het transport vanuit de hoofdlus van het script wordt gepold.Retourneert
0bij succes en-1als er geen actief transport is geregistreerd of de aanroep vanuit een interrupt-context is gedaan.
- protocol.register(name: str, *, backend: object, flags: int = 0) ProtocolChannel#
Registreert een Python
backendobject als een nieuw logisch kanaal en retourneert eenProtocolChannelhandle. De beschikbare methoden van hetbackendobject (zie Backend-interface hieronder) bepalen de mogelijkheden van het kanaal;protocol.CHANNEL_FLAG_READ,protocol.CHANNEL_FLAG_WRITEenprotocol.CHANNEL_FLAG_LOCKworden automatisch aanflagstoegevoegd wanneer de bijbehorende methoden zijn geïmplementeerd.nameis de kanaalnaam als string. Afgekapt tot de buffergrootte van de kanaalnaam in de firmware. Vereist.backendis het Python-object dat de backend-interface implementeert. Vereist. Wordt doorgaans via een keyword doorgegeven (backend=...).flagszijn aanvullende kanaalvlagbits (zie deCHANNEL_FLAG_*constanten). Optioneel; standaard0.Genereert een
RuntimeErrorals het kanaal niet kan worden geregistreerd (bijv. geen vrije kanaalslots).
Klassen#
- class protocol.ProtocolChannel#
Handle die wordt geretourneerd door
protocol.register. Instanties worden niet rechtstreeks geconstrueerd.- send_event(event: int, wait_ack: bool = False) None#
Stuurt een kanaalgebeurtenis-notificatie naar de host.
eventis de gebeurtenis-identifier (geheel getal).wait_ackindienTrueblokkeert totdat de host de gebeurtenis bevestigt.Genereert een
RuntimeErrorals het verzenden van de gebeurtenis mislukt.
Backend-interface#
Een backend-object dat aan protocol.register wordt doorgegeven mag elke subset van de volgende methoden implementeren. Alleen de methoden die op het object aanwezig zijn worden gekoppeld aan de C-protocollaag; ontbrekende methoden laten de bijbehorende mogelijkheid uitgeschakeld.
- class protocol.backend#
Kanaal-backendobject dat aan
protocol.registerwordt doorgegeven. De onderstaande methoden beschrijven de optionele interface die een Python-backend mag implementeren.- init() object#
Wordt eenmalig aangeroepen wanneer het kanaal wordt geïnitialiseerd. Retourneert bij succes een waarde die niet
Noneis; een uitzondering of ontbrekende retourwaarde wordt als een fout behandeld.
- shape() tuple#
Retourneert een tuple van maximaal vier gehele getallen die de gegevensvorm beschrijven (bijv. afbeeldingsafmetingen). Maximaal vier elementen worden door de protocollaag verbruikt.
- flush() object#
Spoelt eventuele in behandeling zijnde gegevens door. Retourneert bij succes een waarde die niet
Noneis.
- read(offset: int, size: int) bytes#
Retourneert maximaal
sizebytes vanafoffsetals eenbytes-achtig object dat het bufferprotocol ondersteunt.
- readp(offset: int, size: int) bytes#
Zero-copy-variant van
read. Retourneert een buffer waarvan het onderliggende geheugen rechtstreeks door de protocollaag wordt gelezen; de buffer moet geldig blijven gedurende de overdracht.
- write(offset: int, data: bytearray) int#
Schrijft
dataopoffset.datais eenbytearraydie rechtstreeks naar de C-buffer verwijst. Retourneert het aantal geschreven bytes, of0bij standaard succes.
- class protocol.CBORChannel(on_read: Callable | None = None, on_write: Callable | None = None)#
Een Python-backend op hoger niveau (geleverd door het bevroren
protocol-pakket) die benoemde velden naar CBOR serialiseert met SenML-compatibele integer-sleutels. Ondersteunt weergavewidgets (label,text,depth,waveform) en interactieve bedieningselementen (toggle,pushbutton,slider,spinbox,select,radio,lineedit) meton_read/on_write-callbacks.on_readis een optionele aanroepbareon_read(channel)die wordt aangeroepen voordat het kanaal voor de host wordt geserialiseerd. Gebruik het om veldwaarden te vernieuwen.on_writeis een optionele aanroepbareon_write(channel, name, value)die wordt aangeroepen wanneer de host een nieuwe waarde voor een benoemd veld schrijft.- 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, sample_rate: float | None = None, series: int = 1, typecode: str | None = None) None#
Voegt een benoemd veld toe aan het kanaal.
nameis de weergavenaam; moet uniek zijn binnen dit kanaal.typeis het widgettype:"label"– alleen-lezen numerieke weergave met een optioneleunit."text"– alleen-lezen stringweergave."toggle"– booleaanse schakelaar."pushbutton"– kortstondige actie (trigger, kalibreren, …). De host schrijftTruebij een klik en toont geen toestand."slider"– numeriek bedieningselement metmin/max/step."spinbox"– nauwkeurige numerieke invoer in stappen; deelt de slider-velden en de update-vorm met een(min, max, value)-tuple."select"– keuzelijst (drop-down) vanoptions-strings."radio"–optionsweergegeven als een groep keuzerondjes."lineedit"– schrijfbare stringinvoer."depth"– 2D-dieptekaartweergave vanwidthxheight."waveform"– 1D-tijdreeksplot van interleaved samples.
valueis de beginwaarde. De standaardwaarde hangt af vantype:0voorlabel,""voortext/lineedit/select/radio,Falsevoortoggle/pushbutton,minvoorslider/spinbox.unitis de eenheidsstring voorlabel/slider/spinbox/waveform(bijv."Cel","%RH").minis de minimumwaarde (bereik van slider/spinbox, of weergavebereik van depth/waveform).maxis de maximumwaarde (bereik van slider/spinbox, of weergavebereik van depth/waveform).stepis de stapgrootte (slider/spinbox).optionsis de lijst met optiestrings (select/radio), of de lijst met namen per reeks (waveform).widthis de breedte in pixels (depth).heightis de hoogte in pixels (depth).sample_rateis de bemonsteringsfrequentie in samples per seconde (waveform). Wordt naar de host gestuurd als de sampleperiode.seriesis het aantal interleaved reeksen in elk sampleblok (waveform), bijv.3voor een XYZ-accelerometerspoor.typecodeis dearray-typecode van de waveform-samples (bijv."H","h","f"). Standaard"H"(unsigned 16-bit).
- __getitem__(name: str) object#
Retourneert de huidige waarde van het benoemde veld. Voor
depth- enwaveform-velden wordt de binaire databuffer geretourneerd, anders de scalaire waarde.
- __setitem__(name: str, value: Any) None#
Stelt de waarde van het benoemde veld in. Voor
slider- enspinbox-velden werkt een(min, max, value)-tuple het bereik en de huidige waarde tegelijk bij. Voordepth-velden isvaluede binaire databuffer. Voorwaveform-velden isvalueeen bytes-achtig blok interleaved samples in detypecodevan het veld; het aantal samples per reeks wordt uit de lengte afgeleid en er wordt een monotone tijdstempel (in microseconden, opgebouwd uittime.ticks_us()) aan gekoppeld zodat de host het blok op zijn tijdas kan plaatsen.
- poll() bool#
Methode van de backend-interface. Retourneert
Truewanneer er geserialiseerde gegevens beschikbaar zijn voor de host.
- size() int#
Methode van de backend-interface. Roept
on_readaan (indien ingesteld) en retourneert de grootte van de geserialiseerde buffer.
Constanten#
Kanaalvlagbits (bitsgewijs gecombineerd; doorgegeven aan protocol.register via flags of automatisch ingesteld op basis van de methoden van de backend).
- protocol.CHANNEL_FLAG_PHYSICAL: int#
Het kanaal vertegenwoordigt een fysiek transport (in tegenstelling tot een logisch datakanaal).
Ingebouwde kanaal-identifiers.