protocol — OpenMV-protokollakanavat#

protocol-moduuli tuo OpenMV-isäntäprotokollan Pythonin käyttöön. Sen avulla laiteohjelmiston puoleinen protokollapino voidaan alustaa ja konfiguroida, ja käyttäjän koodi voi rekisteröidä omia loogisia kanavia, joiden taustalla on Python-olio, joka toteuttaa kanavarajapinnan (read, write, size, poll jne.). Tähän työpöydän kumppanityökalut ottavat yhteyden, kun ne suoratoistavat kuvadataa tai tarjoavat interaktiivisia komponentteja yhdistetylle kameralle.

Esimerkkejä#

Suoratoista RGB565-kuva isäntätyökalulle käyttäen omaa taustajärjestelmää, joka toteuttaa raakakanavarajapinnan (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

Vastaava isäntäpuolen skripti, joka käyttää openmv-Python-pakettia (pip install openmv) yhteyden muodostamiseen, kameralla ajettavan skriptin lähettämiseen ja kunkin kehyksen hakemiseen:

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()

Korvaa /dev/ttyACM0 kameran sarjaportilla (esim. COM3 Windowsissa). openmv.camera.Camera-konstruktori hyväksyy samat protokollaparametrit kuin init (crc / seq / ack / events / max_payload / max_retry / timeout), kun kameran puoleinen pino on konfiguroitu vastaamaan niitä.

Funktiot#

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#

Alustaa (tai konfiguroi uudelleen) protokollapinon ja rekisteröi oletusarvoiset loogiset datakanavat (stdin, stdout, stream ja, jos se on käännetty mukaan, profile). Nostaa RuntimeError-poikkeuksen, jos alustus epäonnistuu. Laiteohjelmisto käynnistyy oletusarvoinen USB-protokollapino jo käynnissä, joten tätä tarvitsee kutsua vain siirtolinkin vaihtamiseksi tai oletusarvoisten kehystysparametrien ohittamiseksi. Uusi kutsu alustaa pinon uudelleen: edellinen kyselyajastin poistetaan ja kanavat rekisteröidään uudestaan.

crc ottaa käyttöön CRC-tarkistuksen protokollakehyksille.

seq ottaa käyttöön järjestysnumeroiden seurannan.

ack ottaa käyttöön kehyskohtaiset kuittaukset.

events ottaa käyttöön kanavatapahtumien ilmoitukset.

max_payload on suurin hyötykuorman koko tavuina. Jos se jätetään pois, käytetään alla olevaa kamerakohtaista oletusarvoa; se johdetaan kunkin kortin protokollapuskurin koosta kaavalla buffer - 10 (header) - 4 (CRC).

Kamera

Puskurin koko

Suurin hyötykuorma

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 on uudelleenlähetysyritysten määrä. Oletus 3.

rtx_timeout_ms on uudelleenlähetyksen aikakatkaisu millisekunteina (kaksinkertaistetaan jokaisen aikakatkaisun jälkeen). Oletus 500.

lock_interval_ms on pienin lukitusväli millisekunteina. Oletus 10.

poll_ms on pollausväli millisekunteina. 0 (oletus) poistaa ajastinpollauksen käytöstä.

protocol.is_active() → bool#

Palauttaa True, jos isäntä on tällä hetkellä yhdistetty ja protokollapino on aktiivinen, muuten False.

protocol.poll() → int#

Suorittaa protokollatehtävän yhden iteraation: tyhjentää siirtolinkin vastaanottopuskurin, jäsentää valmiit kehykset, välittää komennot ja käsittelee kanavatapahtumat. Laiteohjelmisto tekee tämän normaalisti puolestasi USB-keskeytyksestä ja poll_ms-ajastimesta, joten tätä tarvitaan vain mukautetuille siirtolinkeille, joita kumpikaan ei ohjaa – esimerkiksi kun poll_ms=0 ja siirtolinkkiä kysellään skriptin pääsilmukasta.

Palauttaa 0 onnistuessaan ja -1, jos aktiivista siirtolinkkiä ei ole rekisteröity tai kutsu tehtiin keskeytyskontekstista.

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

Rekisteröi Python-olion backend uudeksi loogiseksi kanavaksi ja palauttaa ProtocolChannel-kahvan. backend-olion käytettävissä olevat metodit (katso Taustajärjestelmän rajapinta alla) määrittävät kanavan ominaisuudet; protocol.CHANNEL_FLAG_READ, protocol.CHANNEL_FLAG_WRITE ja protocol.CHANNEL_FLAG_LOCK lisätään flags-arvoon automaattisesti, kun vastaavat metodit on toteutettu.

name on kanavan nimi merkkijonona. Lyhennetään laiteohjelmiston kanavanimipuskurin kokoon. Pakollinen.

backend on Python-olio, joka toteuttaa taustajärjestelmän rajapinnan. Pakollinen. Tyypillisesti välitetään avainsanalla (backend=...).

flags on lisäkanavalippubittejä (katso CHANNEL_FLAG_*-vakiot). Valinnainen; oletusarvo 0.

Nostaa poikkeuksen RuntimeError, jos kanavaa ei voida rekisteröidä (esim. ei vapaita kanavapaikkoja).

Luokat#

class protocol.ProtocolChannel#

Kahva, jonka protocol.register palauttaa. Ilmentymiä ei muodosteta suoraan.

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

Lähettää kanavatapahtuman ilmoituksen isännälle.

event on tapahtuman tunniste (kokonaisluku).

wait_ack jos True, estää suorituksen kunnes isäntä kuittaa tapahtuman.

Nostaa poikkeuksen RuntimeError, jos tapahtuman lähetys epäonnistuu.

Taustajärjestelmän rajapinta#

Funktiolle protocol.register välitetty taustajärjestelmäolio voi toteuttaa minkä tahansa osajoukon seuraavista metodeista. Vain oliossa läsnä olevat metodit kytketään C-protokollakerrokseen; puuttuvat metodit jättävät vastaavan ominaisuuden pois käytöstä.

class protocol.backend#

Funktiolle protocol.register välitetty kanavan taustajärjestelmäolio. Alla olevat metodit kuvaavat valinnaisen rajapinnan, jonka Python-taustajärjestelmä voi toteuttaa.

init() → object#

Kutsutaan kerran, kun kanava alustetaan. Palauta mikä tahansa arvo, joka ei ole None, onnistumisen merkiksi; poikkeus tai puuttuva paluuarvo tulkitaan virheeksi.

poll() → bool#

Palauttaa True, jos kanavalla on dataa valmiina isännän luettavaksi.

lock() → bool#

Varaa kanavan siirtoa varten. Palauta True onnistuessa.

unlock() → bool#

Vapauttaa kanavan siirron jälkeen. Palauta True onnistuessa.

size() → int#

Palauttaa kanavalta tällä hetkellä luettavissa olevien tavujen määrän.

shape() → tuple#

Palauttaa enintään neljän kokonaisluvun monikon, joka kuvaa datan muotoa (esim. kuvan mitat). Protokollakerros käyttää enintään neljä elementtiä.

flush() → object#

Tyhjentää mahdollisen odottavan datan. Palauta mikä tahansa arvo, joka ei ole None, onnistumisen merkiksi.

read(offset: int, size: int) → bytes#

Palauttaa enintään size tavua alkaen kohdasta offset bytes-tyyppisenä oliona, joka tukee puskuriprotokollaa.

readp(offset: int, size: int) → bytes#

Zero-copy-muunnelma metodista read. Palauttaa puskurin, jonka taustalla oleva muisti luetaan suoraan protokollakerroksesta; puskurin on pysyttävä voimassa koko siirron ajan.

write(offset: int, data: bytearray) → int#

Kirjoittaa data kohtaan offset. data on bytearray, joka viittaa suoraan C-puskuriin. Palauta kirjoitettujen tavujen määrä tai 0 oletusarvoisen onnistumisen merkiksi.

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

Käsittelee ioctl-kutsun. arg on None, jos length on nolla, muuten bytearray, joka viittaa C-puskuriin. Palauta 0 tai None onnistuessa tai negatiivinen kokonaisluku virheen merkiksi.

is_active() → bool#

Siirtokanavien tapauksessa palauta True, jos taustalla oleva siirtotie on tällä hetkellä yhdistetty.

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

Korkeamman tason Python-taustatoteutus (jonka jäädytetty protocol-paketti tarjoaa), joka sarjallistaa nimetyt kentät CBOR-muotoon SenML-yhteensopivilla kokonaislukuavaimilla. Tukee näyttöwidgettejä (label, text, depth, waveform) ja interaktiivisia säätimiä (toggle, pushbutton, slider, spinbox, select, radio, lineedit) on_read/on_write-takaisinkutsuineen.

on_read on valinnainen kutsuttava on_read(channel), joka kutsutaan ennen kuin kanava sarjallistetaan isännälle. Käytä sitä kenttäarvojen päivittämiseen.

on_write on valinnainen kutsuttava on_write(channel, name, value), joka kutsutaan, kun isäntä kirjoittaa uuden arvon nimetylle kentälle.

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#

Lisää kanavalle nimetyn kentän.

name on näyttönimi; sen on oltava yksilöllinen tämän kanavan sisällä.

type on widgetin tyyppi:

  • "label" – vain luettava numeerinen näyttö, jolla on valinnainen unit.

  • "text" – vain luettava merkkijononäyttö.

  • "toggle" – totuusarvokytkin.

  • "pushbutton" – hetkellinen toiminto (laukaisu, kalibrointi, …). Isäntä kirjoittaa napsautettaessa arvon True eikä näytä tilaa.

  • "slider" – numeerinen säädin, jolla on min/max/step.

  • "spinbox" – tarkka askeleittainen numeerinen syöttö; jakaa liukusäätimen kentät ja (min, max, value)-monikkopäivitysmuodon.

  • "select" – pudotusvalikko options-merkkijonoista.

  • "radio" – options näytettynä valintanappiryhmänä.

  • "lineedit" – kirjoitettava merkkijonosyöte.

  • "depth" – 2D-syvyyskarttanäyttö, jonka koko on width x height.

  • "waveform" – 1D-aikasarjakuvaaja lomitetuista näytteistä.

value on alkuarvo. Oletus riippuu type-arvosta: 0 tyypille label, "" tyypeille text/lineedit/select/ radio, False tyypeille toggle/pushbutton, min tyypeille slider/spinbox.

unit on yksikkömerkkijono tyypeille label/slider/spinbox/ waveform (esim. "Cel", "%RH").

min on vähimmäisarvo (slider/spinbox-alue tai depth/waveform-näyttöalue).

max on enimmäisarvo (slider/spinbox-alue tai depth/waveform-näyttöalue).

step on askelkoko (slider/spinbox).

options on lista vaihtoehtomerkkijonoista (select/radio) tai lista sarjakohtaisista nimistä (waveform).

width on pikselileveys (depth).

height on pikselikorkeus (depth).

sample_rate on näytteenottotaajuus näytteinä sekunnissa (waveform). Lähetetään isännälle näytejaksona.

series on lomitettujen sarjojen määrä kussakin näytelohkossa (waveform), esim. 3 XYZ-kiihtyvyysanturin käyrälle.

typecode on aaltomuotonäytteiden array-tyyppikoodi (esim. "H", "h", "f"). Oletus on "H" (etumerkitön 16-bittinen).

__getitem__(name: str) → object#

Palauttaa nimetyn kentän nykyisen arvon. depth- ja waveform-kentille palautetaan binaaridatapuskuri, muuten skalaariarvo.

__setitem__(name: str, value: Any) → None#

Asettaa nimetyn kentän arvon. slider- ja spinbox-kentille (min, max, value)-monikko päivittää alueen ja nykyisen arvon samanaikaisesti. depth-kentille value on binaaridatapuskuri. waveform-kentille value on tavumainen lohko lomitettuja näytteitä kentän typecode-tyyppikoodissa; näytteiden määrä sarjaa kohti johdetaan sen pituudesta, ja mukaan liitetään monotoninen aikaleima (mikrosekunteina, kerrytettynä funktiosta time.ticks_us()), jotta isäntä voi sijoittaa lohkon aika-akselilleen.

poll() → bool#

Taustajärjestelmän rajapintametodi. Palauttaa True, kun sarjallistettua dataa on saatavilla isännälle.

size() → int#

Taustajärjestelmän rajapintametodi. Kutsuu on_read (jos asetettu) ja palauttaa sarjallistetun puskurin koon.

read(offset: int, size: int) → bytes#

Taustajärjestelmän rajapintametodi. Palauttaa siivun sarjallistetusta puskurista.

write(offset: int, data: bytearray) → int#

Taustajärjestelmän rajapintametodi. Purkaa CBOR-päivityslistan ja soveltaa arvot vastaaviin nimettyihin kenttiin kutsuen on_write jokaiselle.

Vakiot#

Kanavalippubitit (yhdistetään bittioperaatioin; välitetään funktiolle protocol.register parametrilla flags tai asetetaan automaattisesti taustajärjestelmän metodien perusteella).

protocol.CHANNEL_FLAG_READ: int#

Kanava tukee lukuoperaatioita.

protocol.CHANNEL_FLAG_WRITE: int#

Kanava tukee kirjoitusoperaatioita.

protocol.CHANNEL_FLAG_LOCK: int#

Kanava toteuttaa metodit lock/unlock.

protocol.CHANNEL_FLAG_PHYSICAL: int#

Kanava edustaa fyysistä siirtotietä (toisin kuin loogista datakanavaa).

Sisäänrakennettujen kanavien tunnisteet.

protocol.CHANNEL_ID_TRANSPORT: int#

Aktiivisen siirtotien varattu kanavatunniste.

protocol.CHANNEL_ID_STDIN: int#

Sisäänrakennetun stdin-kanavan kanavatunniste.

protocol.CHANNEL_ID_STDOUT: int#

Sisäänrakennetun stdout-kanavan kanavatunniste.

protocol.CHANNEL_ID_STREAM: int#

Sisäänrakennetun stream-kanavan kanavatunniste.

protocol.CHANNEL_ID_PROFILE: int#

Sisäänrakennetun profilointikanavan kanavatunniste (läsnä vain, kun laiteohjelmisto on käännetty profiloinnin ollessa käytössä).