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, stream en, indien meegecompileerd, profile). Genereert een RuntimeError als de initialisatie mislukt. De firmware start op met een standaard USB-protocolstack die al draait, dus het aanroepen hiervan is alleen nodig om het transport te wijzigen of de standaard framingparameters te overschrijven.

crc schakelt CRC-validatie van protocolframes in.

seq schakelt het bijhouden van volgnummers in.

ack schakelt bevestigingen per frame in.

events schakelt kanaalgebeurtenis-notificaties in.

max_payload is de maximale payloadgrootte in bytes. Indien weggelaten wordt de onderstaande standaardwaarde per camera gebruikt; deze is afgeleid van de protocolbuffergrootte van elk board als buffer - 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_retries is het aantal hertransmissiepogingen. Standaard 3.

rtx_timeout_ms is de hertransmissie-timeout in milliseconden (verdubbeld na elke timeout). Standaard 500.

lock_interval_ms is het minimale vergrendelingsinterval in milliseconden. Standaard 10.

poll_ms is het polling-interval in milliseconden. 0 (de standaardwaarde) schakelt timer-polling uit.

protocol.is_active() bool

Retourneert True als er momenteel een host verbonden is en de protocolstack actief is, anders False.

protocol.register(name: str, *, backend: object, flags: int = 0) ProtocolChannel

Registreert een Python backend object als een nieuw logisch kanaal en retourneert een ProtocolChannel handle. De beschikbare methoden van het backend object (zie Backend-interface hieronder) bepalen de mogelijkheden van het kanaal; protocol.CHANNEL_FLAG_READ, protocol.CHANNEL_FLAG_WRITE en protocol.CHANNEL_FLAG_LOCK worden automatisch aan flags toegevoegd wanneer de bijbehorende methoden zijn geïmplementeerd.

name is de kanaalnaam als string. Afgekapt tot de buffergrootte van de kanaalnaam in de firmware. Vereist.

backend is het Python-object dat de backend-interface implementeert. Vereist. Wordt doorgaans via een keyword doorgegeven (backend=...).

flags zijn aanvullende kanaalvlagbits (zie de CHANNEL_FLAG_* constanten). Optioneel; standaard 0.

Genereert een RuntimeError als 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.

event is de gebeurtenis-identifier (geheel getal).

wait_ack indien True blokkeert totdat de host de gebeurtenis bevestigt.

Genereert een RuntimeError als 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.register wordt 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 None is; een uitzondering of ontbrekende retourwaarde wordt als een fout behandeld.

poll() bool

Retourneert True als het kanaal gegevens klaar heeft om door de host te worden gelezen.

lock() bool

Vergrendelt het kanaal voor een overdracht. Retourneert True bij succes.

unlock() bool

Geeft het kanaal vrij na een overdracht. Retourneert True bij succes.

size() int

Retourneert het aantal bytes dat momenteel uit het kanaal kan worden gelezen.

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 None is.

read(offset: int, size: int) bytes

Retourneert maximaal size bytes vanaf offset als een bytes-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 data op offset. data is een bytearray die rechtstreeks naar de C-buffer verwijst. Retourneert het aantal geschreven bytes, of 0 bij standaard succes.

ioctl(cmd: int, length: int, arg: bytearray | None) int

Handelt een ioctl af. arg is None als length nul is, anders een bytearray die naar de C-buffer verwijst. Retourneert 0 of None bij succes, of een negatief geheel getal bij een fout.

is_active() bool

Retourneert voor transportkanalen True als het onderliggende transport momenteel verbonden is.

class protocol.CBORChannel(on_read: Callable | None = None, on_write: Callable | None = None)

Een Python-backend op een hoger niveau (geleverd door het ingevroren protocol pakket) dat benoemde velden serialiseert naar CBOR met behulp van SenML-compatibele integer-sleutels. Ondersteunt weergavewidgets (label, depth) en interactieve besturingselementen (toggle, slider, select) met on_read/on_write callbacks.

on_read is een optionele aanroepbare on_read(channel) die wordt aangeroepen voordat het kanaal voor de host wordt geserialiseerd. Gebruik het om veldwaarden te vernieuwen.

on_write is een optionele aanroepbare on_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) None

Voegt een benoemd veld toe aan het kanaal.

name is de weergavenaam; moet uniek zijn binnen dit kanaal.

type is het widgettype: "label", "toggle", "slider", "select", of "depth".

value is de beginwaarde. De standaardwaarde hangt af van type.

unit is de eenheidsstring voor label/slider (bijv. "Cel", "%RH").

min is de minimumwaarde (sliderbereik of dieptebereik).

max is de maximumwaarde (sliderbereik of dieptebereik).

step is de stapgrootte (slider).

options is de lijst met optiestrings (select).

width is de breedte in pixels (depth).

height is de hoogte in pixels (depth).

__getitem__(name: str) object

Retourneert de huidige waarde van het benoemde veld. Voor depth velden wordt de binaire gegevensbuffer geretourneerd, anders de scalaire waarde.

__setitem__(name: str, value: Any) None

Stelt de waarde van het benoemde veld in. Voor slider velden werkt een (min, max, value) tuple het bereik en de huidige waarde tegelijkertijd bij. Voor depth velden is value de binaire gegevensbuffer.

poll() bool

Methode van de backend-interface. Retourneert True wanneer er geserialiseerde gegevens beschikbaar zijn voor de host.

size() int

Methode van de backend-interface. Roept on_read aan (indien ingesteld) en retourneert de grootte van de geserialiseerde buffer.

read(offset: int, size: int) bytes

Methode van de backend-interface. Retourneert een segment van de geserialiseerde buffer.

write(offset: int, data: bytearray) int

Methode van de backend-interface. Decodeert een CBOR-updatelijst en past waarden toe op overeenkomende benoemde velden, waarbij voor elke on_write wordt aangeroepen.

Constanten

Kanaalvlagbits (bitsgewijs gecombineerd; doorgegeven aan protocol.register via flags of automatisch ingesteld op basis van de methoden van de backend).

protocol.CHANNEL_FLAG_READ: int

Het kanaal ondersteunt leesbewerkingen.

protocol.CHANNEL_FLAG_WRITE: int

Het kanaal ondersteunt schrijfbewerkingen.

protocol.CHANNEL_FLAG_LOCK: int

Het kanaal implementeert lock/unlock.

protocol.CHANNEL_FLAG_PHYSICAL: int

Het kanaal vertegenwoordigt een fysiek transport (in tegenstelling tot een logisch datakanaal).

Ingebouwde kanaal-identifiers.

protocol.CHANNEL_ID_TRANSPORT: int

Gereserveerde kanaal-ID voor het actieve transport.

protocol.CHANNEL_ID_STDIN: int

Kanaal-ID van het ingebouwde stdin kanaal.

protocol.CHANNEL_ID_STDOUT: int

Kanaal-ID van het ingebouwde stdout kanaal.

protocol.CHANNEL_ID_STREAM: int

Kanaal-ID van het ingebouwde stream kanaal.

protocol.CHANNEL_ID_PROFILE: int

Kanaal-ID van het ingebouwde profiler-kanaal (alleen aanwezig wanneer de firmware met de profiler ingeschakeld is gebouwd).