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

Initiera (eller omkonfigurera) protokollstacken och registrera standardlogiska datakanaler (stdin, stdout, stream och, om inkompilerad, profile). Höjer RuntimeError om initieringen misslyckas. Den fasta programvaran startar med en standard-USB-protokollstack som redan körs, så detta anrop behövs endast för att byta transport eller åsidosätta standardparametrarna för ramning.

crc aktiverar CRC-validering på protokollramar.

seq aktiverar spårning av sekvensnummer.

ack aktiverar bekräftelser per ram.

events aktiverar 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 som buffer - 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. Standard 3.

rtx_timeout_ms är återsändningstimeouten i millisekunder (fördubblas efter varje timeout). Standard 500.

lock_interval_ms är det minsta låsintervallet i millisekunder. Standard 10.

poll_ms är pollningsintervallet i millisekunder. 0 (standard) inaktiverar timerbaserad pollning.

protocol.is_active() bool

Returnerar True om en värd är ansluten för närvarande och protokollstacken är aktiv, annars False.

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

Registrera ett Python-backend-objekt som en ny logisk kanal och returnera ett ProtocolChannel-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_WRITE och protocol.CHANNEL_FLAG_LOCK läggs till i flags automatiskt 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 konstanterna CHANNEL_FLAG_*). Valfri; standardvärdet är 0.

Höjer RuntimeError om kanalen inte kan registreras (t.ex. inga lediga kanalplatser).

Klasser

class protocol.ProtocolChannel

Handtag som returneras av protocol.register. Instanser konstrueras inte direkt.

send_event(event: int, wait_ack: bool = False) None

Skicka en avisering om en kanalhändelse till värden.

event är händelseidentifieraren (heltal).

wait_ack om True blockerar tills värden bekräftar händelsen.

Höjer RuntimeError om sändningen av händelsen misslyckas.

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 None vid lyckat resultat; ett undantag eller en utebliven retur behandlas som ett fel.

poll() bool

Returnerar True om kanalen har data redo att läsas av värden.

lock() bool

Förvärva kanalen för en överföring. Returnera True vid lyckat resultat.

unlock() bool

Frigör kanalen efter en överföring. Returnera True vid lyckat resultat.

size() int

Returnerar antalet byte som för närvarande är läsbara från kanalen.

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 None vid lyckat resultat.

read(offset: int, size: int) bytes

Returnerar upp till size byte från och med offset som ett bytes-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 data vid offset. data är en bytearray som refererar direkt till C-bufferten. Returnera antalet skrivna byte, eller 0 vid standardmässigt lyckat resultat.

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

Hantera en ioctl. arg är None om length är noll, annars en bytearray som refererar till C-bufferten. Returnera 0 eller None vid lyckat resultat, eller ett negativt heltal vid fel.

is_active() bool

För transportkanaler, returnera True om den underliggande transporten är ansluten för närvarande.

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

En Python-backend på högre nivå (tillhandahållen av det frysta paketet protocol) som serialiserar namngivna fält till CBOR med SenML-kompatibla heltalsnycklar. Stöder visningswidgetar (label, depth) och interaktiva kontroller (toggle, slider, select) med on_read/on_write-återanrop.

on_read är ett valfritt anropbart objekt on_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 objekt on_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) None

Lägg till ett namngivet fält i kanalen.

name är visningsnamnet; måste vara unikt inom denna kanal.

type är widgettypen: "label", "toggle", "slider", "select" eller "depth".

value är startvärdet. Standardvärdet beror på type.

unit är enhetssträngen för label/slider (t.ex. "Cel", "%RH").

min är minimivärdet (skjutreglagets intervall eller djupintervall).

max är maxvärdet (skjutreglagets intervall eller djupintervall).

step är stegstorleken (skjutreglage).

options är listan med alternativsträngar (select).

width är pixelbredden (depth).

height är pixelhöjden (depth).

__getitem__(name: str) object

Returnerar det aktuella värdet för det namngivna fältet. För depth-fält returneras den binära databufferten, annars skalärvärdet.

__setitem__(name: str, value: Any) None

Sätt värdet för det namngivna fältet. För slider-fält uppdaterar en tupel (min, max, value) intervallet och det aktuella värdet samtidigt. För depth-fält är value den binära databufferten.

poll() bool

Metod i backend-gränssnittet. Returnerar True nä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.

read(offset: int, size: int) bytes

Metod i backend-gränssnittet. Returnerar en del av den serialiserade bufferten.

write(offset: int, data: bytearray) int

Metod i backend-gränssnittet. Avkodar en CBOR-uppdateringslista och tillämpar värden på matchande namngivna fält, varvid on_write anropas för vart och ett.

Konstanter

Kanalflaggbitar (kombineras bitvis; skickas till protocol.register via flags eller sätts automatiskt baserat på backendens metoder).

protocol.CHANNEL_FLAG_READ: int

Kanalen stöder läsningar.

protocol.CHANNEL_FLAG_WRITE: int

Kanalen stöder skrivningar.

protocol.CHANNEL_FLAG_LOCK: int

Kanalen implementerar lock/unlock.

protocol.CHANNEL_FLAG_PHYSICAL: int

Kanalen representerar en fysisk transport (till skillnad från en logisk datakanal).

Inbyggda kanalidentifierare.

protocol.CHANNEL_ID_TRANSPORT: int

Reserverat kanal-ID för den aktiva transporten.

protocol.CHANNEL_ID_STDIN: int

Kanal-ID för den inbyggda stdin-kanalen.

protocol.CHANNEL_ID_STDOUT: int

Kanal-ID för den inbyggda stdout-kanalen.

protocol.CHANNEL_ID_STREAM: int

Kanal-ID för den inbyggda stream-kanalen.

protocol.CHANNEL_ID_PROFILE: int

Kanal-ID för den inbyggda profilerarkanalen (finns endast när den fasta programvaran är byggd med profileraren aktiverad).