protocol — OpenMV-protokollkanaler#
Modulen protocol exponerar OpenMV-värdprotokollet till Python. Den gör det möjligt att initiera och konfigurera protokollstacken på fast programvara-sidan, och låter användarkod registrera anpassade logiska kanaler som backas av ett Python-objekt som implementerar kanalgränssnittet (read, write, size, poll osv.). Det är detta som följeslagarverktyg på skrivbordet kommunicerar med när de strömmar bilddata eller exponerar interaktiva widgetar mot en ansluten kamera.
Exempel#
Strömma en RGB565-bild till ett värdverktyg med en anpassad backend som implementerar det råa kanalgränssnittet (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
Det matchande värdskriptet, som använder Python-paketet openmv (pip install openmv) för att ansluta, skicka skriptet till kameran och hämta varje bildruta:
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()
Ersätt /dev/ttyACM0 med kamerans serieport (t.ex. COM3 på Windows). Konstruktorn openmv.camera.Camera accepterar samma protokollparametrar som init (crc / seq / ack / events / max_payload / max_retry / timeout) när stacken på kamerasidan har omkonfigurerats för att matcha.
Funktioner#
- 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#
Initierar (eller omkonfigurerar) protokollstacken och registrerar de logiska standarddatakanalerna (
stdin,stdout,streamoch, om den är inkompilerad,profile). UtlöserRuntimeErrorom initieringen misslyckas. Firmwaren startar med en USB-protokollstack som redan körs som standard, så detta behöver bara anropas för att byta transport eller åsidosätta standardparametrarna för ramning. Anropas den igen initieras stacken om: den tidigare pollningstimern tas bort och kanalerna registreras på nytt.crcaktiverar CRC-validering på protokollramar.seqaktiverar spårning av sekvensnummer.ackaktiverar bekräftelser per ram.eventsaktiverar aviseringar om kanalhändelser.max_payloadär den maximala nyttolaststorleken i byte. Om den utelämnas används standardvärdet per kamera nedan; det härleds från varje korts protokollbuffertstorlek sombuffer - 10 (header) - 4 (CRC).Kamera
Buffertstorlek
Max nyttolast
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är antalet återsändningsförsök. Standard3.rtx_timeout_msär återsändningstimeouten i millisekunder (fördubblas efter varje timeout). Standard500.lock_interval_msär det minsta låsintervallet i millisekunder. Standard10.poll_msär pollningsintervallet i millisekunder.0(standard) inaktiverar timerbaserad pollning.
- protocol.is_active() bool#
Returnerar
Trueom en värd är ansluten för närvarande och protokollstacken är aktiv, annarsFalse.
- protocol.poll() int#
Kör en iteration av protokolluppgiften: tömmer transportens mottagningsbuffert, tolkar alla kompletta ramar, skickar vidare kommandon och betjänar kanalhändelser. Normalt gör firmwaren detta åt dig från USB-avbrottet och från
poll_ms-timern, så detta behövs bara för anpassade transporter som inte drivs av någotdera – till exempel närpoll_ms=0och transporten pollas från skriptets huvudloop.Returnerar
0vid framgång och-1om ingen aktiv transport är registrerad eller om anropet gjordes från en avbrottskontext.
- protocol.register(name: str, *, backend: object, flags: int = 0) ProtocolChannel#
Registrera ett Python-
backend-objekt som en ny logisk kanal och returnera ettProtocolChannel-handtag. De metoder som finns tillgängliga påbackend-objektet (se Backend-gränssnitt nedan) bestämmer kanalens kapacitet;protocol.CHANNEL_FLAG_READ,protocol.CHANNEL_FLAG_WRITEochprotocol.CHANNEL_FLAG_LOCKläggs till iflagsautomatiskt när motsvarande metoder är implementerade.nameär kanalnamnet som en sträng. Trunkeras till storleken på den fasta programvarans kanalnamnsbuffert. Obligatorisk.backendär Python-objektet som implementerar backend-gränssnittet. Obligatorisk. Skickas vanligtvis med nyckelord (backend=...).flagsär ytterligare kanalflaggbitar (se konstanternaCHANNEL_FLAG_*). Valfri; standardvärdet är0.Höjer
RuntimeErrorom kanalen inte kan registreras (t.ex. inga lediga kanalplatser).
Klasser#
- class protocol.ProtocolChannel#
Handtag som returneras av
protocol.register. Instanser konstrueras inte direkt.
Backend-gränssnitt#
Ett backend-objekt som skickas till protocol.register kan implementera valfri delmängd av följande metoder. Endast de metoder som finns på objektet kopplas till C-protokolllagret; metoder som saknas lämnar motsvarande kapacitet inaktiverad.
- class protocol.backend#
Kanal-backend-objekt som skickas till
protocol.register. Metoderna nedan beskriver det valfria gränssnitt som en Python-backend kan implementera.- init() object#
Anropas en gång när kanalen initieras. Returnera ett värde som inte är
Nonevid lyckat resultat; ett undantag eller en utebliven retur behandlas som ett fel.
- shape() tuple#
Returnerar en tupel med upp till fyra heltal som beskriver dataformen (t.ex. bildmått). Upp till fyra element konsumeras av protokolllagret.
- flush() object#
Töm eventuell väntande data. Returnera ett värde som inte är
Nonevid lyckat resultat.
- read(offset: int, size: int) bytes#
Returnerar upp till
sizebyte från och medoffsetsom ettbytes-liknande objekt som stöder buffertprotokollet.
- readp(offset: int, size: int) bytes#
Nollkopieringsvariant av
read. Returnerar en buffert vars underliggande minne läses direkt av protokolllagret; bufferten måste förbli giltig under hela överföringen.
- write(offset: int, data: bytearray) int#
Skriv
datavidoffset.dataär enbytearraysom refererar direkt till C-bufferten. Returnera antalet skrivna byte, eller0vid standardmässigt lyckat resultat.
- class protocol.CBORChannel(on_read: Callable | None = None, on_write: Callable | None = None)#
En Python-backend på högre nivå (som tillhandahålls av det frysta
protocol-paketet) som serialiserar namngivna fält till CBOR med SenML-kompatibla heltalsnycklar. Stöder visningswidgetar (label,text,depth,waveform) och interaktiva kontroller (toggle,pushbutton,slider,spinbox,select,radio,lineedit) medon_read/on_write-återanrop.on_readär ett valfritt anropbart objekton_read(channel)som anropas innan kanalen serialiseras för värden. Använd det för att uppdatera fältvärden.on_writeär ett valfritt anropbart objekton_write(channel, name, value)som anropas när värden skriver ett nytt värde för ett namngivet fält.- 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#
Lägg till ett namngivet fält i kanalen.
nameär visningsnamnet; måste vara unikt inom denna kanal.typeär widgettypen:"label"– skrivskyddad numerisk visning med en valfriunit."text"– skrivskyddad strängvisning."toggle"– boolesk växlare."pushbutton"– momentan åtgärd (utlös, kalibrera, …). Värden skriverTruevid klick och visar inget tillstånd."slider"– numerisk kontroll medmin/max/step."spinbox"– exakt stegvis numerisk inmatning; delar skjutreglagets fält och uppdateringsformen med en(min, max, value)-tupel."select"– rullgardinsmeny med strängarna ioptions."radio"–optionsvisade som en grupp radioknappar."lineedit"– skrivbar stränginmatning."depth"– 2D-visning av en djupkarta med storlekenwidthxheight."waveform"– 1D-tidsseriediagram över sammanflätade sampel.
valueär startvärdet. Standardvärdet beror påtype:0förlabel,""förtext/lineedit/select/radio,Falseförtoggle/pushbutton,minförslider/spinbox.unitär enhetssträngen förlabel/slider/spinbox/waveform(t.ex."Cel","%RH").minär minimivärdet (intervall för slider/spinbox, eller visningsintervall för depth/waveform).maxär maximivärdet (intervall för slider/spinbox, eller visningsintervall för depth/waveform).stepär stegstorleken (slider/spinbox).optionsär listan med alternativsträngar (select/radio), eller listan med namn per serie (waveform).widthär pixelbredden (depth).heightär pixelhöjden (depth).sample_rateär samplingsfrekvensen i sampel per sekund (waveform). Skickas till värden som samplingsperiod.seriesär antalet sammanflätade serier i varje sampelblock (waveform), t.ex.3för en XYZ-accelerometerkurva.typecodeärarray-typkoden för vågformens sampel (t.ex."H","h","f"). Standard är"H"(16-bitars utan tecken).
- __getitem__(name: str) object#
Returnerar det aktuella värdet för det namngivna fältet. För
depth- ochwaveform-fält returneras den binära databufferten, annars skalärvärdet.
- __setitem__(name: str, value: Any) None#
Sätter värdet för det namngivna fältet. För
slider- ochspinbox-fält uppdaterar en(min, max, value)-tupel intervallet och det aktuella värdet samtidigt. Fördepth-fält ärvalueden binära databufferten. Förwaveform-fält ärvalueett bytes-liknande block av sammanflätade sampel i fältetstypecode; antalet sampel per serie härleds från dess längd och en monoton tidsstämpel (i mikrosekunder, ackumulerad fråntime.ticks_us()) bifogas så att värden kan placera blocket på sin tidsaxel.
- poll() bool#
Metod i backend-gränssnittet. Returnerar
Truenär serialiserad data är tillgänglig för värden.
- size() int#
Metod i backend-gränssnittet. Anropar
on_read(om den är satt) och returnerar storleken på den serialiserade bufferten.
Konstanter#
Kanalflaggbitar (kombineras bitvis; skickas till protocol.register via flags eller sätts automatiskt baserat på backendens metoder).
- protocol.CHANNEL_FLAG_PHYSICAL: int#
Kanalen representerar en fysisk transport (till skillnad från en logisk datakanal).
Inbyggda kanalidentifierare.