protocol — Kanály protokolu OpenMV#
Modul protocol zpřístupňuje hostitelský protokol OpenMV jazyku Python. Umožňuje inicializaci a konfiguraci protokolového zásobníku na straně firmwaru a dovoluje uživatelskému kódu registrovat vlastní logické kanály podpořené objektem Python, který implementuje rozhraní kanálu (read, write, size, poll atd.). S tím komunikují doprovodné nástroje na počítači, když streamují obrazová data nebo zpřístupňují interaktivní widgety připojené kameře.
Příklady#
Stream obrazu RGB565 do hostitelského nástroje pomocí vlastního backendu, který implementuje rozhraní surového kanálu (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
Odpovídající skript na straně hostitele, který používá balíček Python openmv (pip install openmv) k připojení, nahrání skriptu do kamery a stažení každého snímku:
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()
Nahraďte /dev/ttyACM0 sériovým portem kamery (např. COM3 ve Windows). Konstruktor openmv.camera.Camera přijímá stejné parametry protokolu jako init (crc / seq / ack / events / max_payload / max_retry / timeout), pokud byl zásobník na straně kamery překonfigurován tak, aby jim odpovídal.
Funkce#
- 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#
Inicializuje (nebo překonfiguruje) protokolový zásobník a zaregistruje výchozí logické datové kanály (
stdin,stdout,streama, je-li zakompilován,profile). VyvoláRuntimeError, pokud inicializace selže. Firmware se spouští s již běžícím výchozím protokolovým zásobníkem přes USB, takže toto volání je potřeba pouze pro změnu přenosu nebo přepsání výchozích parametrů rámcování. Opětovné volání zásobník znovu inicializuje: předchozí časovač dotazování se odstraní a kanály se zaregistrují znovu.crcpovoluje ověřování CRC u rámců protokolu.seqpovoluje sledování sekvenčních čísel.ackpovoluje potvrzování jednotlivých rámců.eventspovoluje oznámení událostí kanálu.max_payloadje maximální velikost užitečného zatížení v bajtech. Pokud je vynechána, použije se níže uvedená výchozí hodnota pro danou kameru; ta je odvozena z velikosti protokolového bufferu každé desky jakobuffer - 10 (header) - 4 (CRC).Kamera
Velikost bufferu
Max. užitečné zatížení
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_retriesje počet pokusů o opětovné odeslání. Výchozí hodnota3.rtx_timeout_msje časový limit opětovného odeslání v milisekundách (po každém vypršení se zdvojnásobí). Výchozí hodnota500.lock_interval_msje minimální interval zámku v milisekundách. Výchozí hodnota10.poll_msje interval dotazování v milisekundách.0(výchozí) zakazuje dotazování pomocí časovače.
- protocol.is_active() bool#
Vrací
True, pokud je aktuálně připojen hostitel a protokolový zásobník je aktivní, jinakFalse.
- protocol.poll() int#
Provede jednu iteraci úlohy protokolu: vyprázdní přijímací buffer přenosu, zpracuje všechny kompletní rámce, rozešle příkazy a obslouží události kanálů. Firmware to za vás běžně provádí z přerušení USB a z časovače
poll_ms, takže je to potřeba jen pro vlastní přenosy, které nejsou řízeny ani jedním z nich – například kdyžpoll_ms=0a přenos je dotazován z hlavní smyčky skriptu.Vrací
0při úspěchu a-1, pokud není zaregistrován žádný aktivní přenos nebo bylo volání provedeno z kontextu přerušení.
- protocol.register(name: str, *, backend: object, flags: int = 0) ProtocolChannel#
Registruje objekt Python
backendjako nový logický kanál a vrátí úchytProtocolChannel. Dostupné metody objektubackend(viz Rozhraní backendu níže) určují schopnosti kanálu;protocol.CHANNEL_FLAG_READ,protocol.CHANNEL_FLAG_WRITEaprotocol.CHANNEL_FLAG_LOCKjsou doflagspřidány automaticky, když jsou odpovídající metody implementovány.nameje název kanálu jako řetězec. Zkrácen na velikost bufferu pro názvy kanálů ve firmwaru. Povinné.backendje objekt Python implementující rozhraní backendu. Povinné. Obvykle předáván klíčovým slovem (backend=...).flagsjsou další příznakové bity kanálu (viz konstantyCHANNEL_FLAG_*). Nepovinné; výchozí hodnota0.Vyvolá
RuntimeError, pokud kanál nelze zaregistrovat (např. žádné volné sloty kanálů).
Třídy#
- class protocol.ProtocolChannel#
Úchyt vrácený funkcí
protocol.register. Instance se nevytvářejí přímo.
Rozhraní backendu#
Objekt backendu předaný funkci protocol.register může implementovat libovolnou podmnožinu následujících metod. K protokolové vrstvě C jsou napojeny pouze metody přítomné na objektu; chybějící metody ponechávají odpovídající schopnost vypnutou.
- class protocol.backend#
Objekt backendu kanálu předaný funkci
protocol.register. Níže uvedené metody popisují volitelné rozhraní, které může backend Python implementovat.- init() object#
Voláno jednou při inicializaci kanálu. Při úspěchu vrací libovolnou hodnotu různou od
None; výjimka nebo chybějící návratová hodnota je považována za chybu.
- shape() tuple#
Vrací n-tici až čtyř celých čísel popisujících tvar dat (např. rozměry obrazu). Protokolová vrstva spotřebuje až čtyři prvky.
- flush() object#
Vyprázdní veškerá čekající data. Při úspěchu vrací libovolnou hodnotu různou od
None.
- read(offset: int, size: int) bytes#
Vrací až
sizebajtů počínaje odoffsetjako objekt podobnýbytes, který podporuje buffer protocol.
- readp(offset: int, size: int) bytes#
Varianta
readbez kopírování (zero-copy). Vrací buffer, jehož podkladovou paměť čte protokolová vrstva přímo; buffer musí zůstat platný po celou dobu trvání přenosu.
- write(offset: int, data: bytearray) int#
Zapíše
datanaoffset.datajebytearrayodkazující přímo na buffer C. Vrací počet zapsaných bajtů, nebo0při výchozím úspěchu.
- class protocol.CBORChannel(on_read: Callable | None = None, on_write: Callable | None = None)#
Backend Pythonu vyšší úrovně (poskytovaný zmrazeným balíčkem
protocol), který serializuje pojmenovaná pole do CBOR pomocí celočíselných klíčů kompatibilních se SenML. Podporuje zobrazovací widgety (label,text,depth,waveform) a interaktivní ovládací prvky (toggle,pushbutton,slider,spinbox,select,radio,lineedit) s callbackyon_read/on_write.on_readje nepovinný volatelný objekton_read(channel)vyvolaný před serializací kanálu pro hostitele. Použijte jej k obnovení hodnot polí.on_writeje nepovinný volatelný objekton_write(channel, name, value)vyvolaný, když hostitel zapíše novou hodnotu pro pojmenované pole.- 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#
Přidá do kanálu pojmenované pole.
nameje zobrazovaný název; musí být v rámci tohoto kanálu jedinečný.typeje typ widgetu:"label"– číselné zobrazení pouze pro čtení s volitelnou jednotkouunit."text"– zobrazení řetězce pouze pro čtení."toggle"– logický přepínač."pushbutton"– okamžitá akce (spuštění, kalibrace, …). Hostitel při kliknutí zapíšeTruea nezobrazuje žádný stav."slider"– číselný ovládací prvek smin/max/step."spinbox"– přesné krokované zadávání čísel; sdílí pole slideru a formu aktualizace n-ticí(min, max, value)."select"– rozbalovací seznam řetězcůoptions."radio"–optionsvykreslené jako skupina přepínacích tlačítek."lineedit"– zapisovatelný řetězcový vstup."depth"– 2D zobrazení hloubkové mapy o rozměrechwidthxheight."waveform"– 1D graf časové řady prokládaných vzorků.
valueje počáteční hodnota. Výchozí hodnota závisí natype:0prolabel,""protext/lineedit/select/radio,Falseprotoggle/pushbutton,minproslider/spinbox.unitje řetězec jednotky prolabel/slider/spinbox/waveform(např."Cel","%RH").minje minimální hodnota (rozsah slideru/spinboxu, nebo rozsah zobrazení pro depth/waveform).maxje maximální hodnota (rozsah slideru/spinboxu, nebo rozsah zobrazení pro depth/waveform).stepje velikost kroku (slider/spinbox).optionsje seznam řetězců voleb (select/radio), nebo seznam názvů jednotlivých řad (waveform).widthje šířka v pixelech (depth).heightje výška v pixelech (depth).sample_rateje vzorkovací frekvence ve vzorcích za sekundu (waveform). Hostiteli se odesílá jako perioda vzorkování.seriesje počet prokládaných řad v každém bloku vzorků (waveform), např.3pro záznam akcelerometru XYZ.typecodeje typový kódarrayvzorků waveformu (např."H","h","f"). Výchozí je"H"(16bitové bez znaménka).
- __getitem__(name: str) object#
Vrátí aktuální hodnotu pojmenovaného pole. Pro pole
depthawaveformse vrací binární datový buffer, jinak skalární hodnota.
- __setitem__(name: str, value: Any) None#
Nastaví hodnotu pojmenovaného pole. U polí
slideraspinboxn-tice(min, max, value)aktualizuje rozsah a aktuální hodnotu současně. U polídepthjevaluebinární datový buffer. U políwaveformjevalueblok bajtů (bytes-like) prokládaných vzorků vtypecodedaného pole; počet vzorků na řadu se odvodí z jeho délky a připojí se monotónní časové razítko (v mikrosekundách, akumulované ztime.ticks_us()), aby hostitel mohl blok umístit na svou časovou osu.
- poll() bool#
Metoda rozhraní backendu. Vrací
True, když jsou pro hostitele k dispozici serializovaná data.
Konstanty#
Příznakové bity kanálu (kombinované bitově; předávané funkci protocol.register přes flags nebo nastavované automaticky na základě metod backendu).
- protocol.CHANNEL_FLAG_PHYSICAL: int#
Kanál představuje fyzický přenos (na rozdíl od logického datového kanálu).
Vestavěné identifikátory kanálů.