protocol --- Saluran Protokol OpenMV#
Modul protocol mengekspos protokol host OpenMV ke Python. Modul ini memungkinkan tumpukan protokol sisi firmware untuk diinisialisasi dan dikonfigurasi, serta memungkinkan kode pengguna mendaftarkan saluran logis kustom yang didukung oleh objek Python yang mengimplementasikan antarmuka saluran (read, write, size, poll, dll.). Inilah yang digunakan alat pendamping desktop ketika mereka melakukan streaming data citra atau mengekspos widget interaktif ke kamera yang terhubung.
Contoh#
Melakukan streaming citra RGB565 ke alat host menggunakan backend kustom yang mengimplementasikan antarmuka saluran mentah (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
Skrip sisi host yang sesuai, menggunakan paket Python openmv (pip install openmv) untuk terhubung, mendorong skrip di kamera, dan menarik setiap bingkai:
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()
Ganti /dev/ttyACM0 dengan port serial kamera (misalnya COM3 di Windows). Konstruktor openmv.camera.Camera menerima parameter protokol yang sama dengan init (crc / seq / ack / events / max_payload / max_retry / timeout) ketika tumpukan sisi kamera telah dikonfigurasi ulang agar sesuai.
Fungsi#
- 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#
Menginisialisasi (atau mengonfigurasi ulang) tumpukan protokol dan mendaftarkan saluran data logis default (
stdin,stdout,streamdan, jika dikompilasi,profile). MemunculkanRuntimeErrorjika inisialisasi gagal. Firmware melakukan boot dengan tumpukan protokol USB default yang sudah berjalan, sehingga pemanggilan ini hanya diperlukan untuk mengganti transport atau menimpa parameter framing default. Memanggilnya lagi akan menginisialisasi ulang tumpukan: timer polling sebelumnya dihapus dan saluran-saluran didaftarkan kembali dari awal.crcmengaktifkan validasi CRC pada bingkai protokol.seqmengaktifkan pelacakan nomor urutan.ackmengaktifkan pengakuan per bingkai.eventsmengaktifkan notifikasi event saluran.max_payloadadalah ukuran payload maksimum dalam byte. Jika dihilangkan, default per kamera di bawah ini digunakan; ini diturunkan dari ukuran buffer protokol setiap board sebagaibuffer - 10 (header) - 4 (CRC).Kamera
Ukuran buffer
Payload maksimum
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_retriesadalah jumlah upaya retransmisi. Default3.rtx_timeout_msadalah timeout retransmisi dalam milidetik (digandakan setelah setiap timeout). Default500.lock_interval_msadalah interval kunci minimum dalam milidetik. Default10.poll_msadalah interval polling dalam milidetik.0(default) menonaktifkan polling timer.
- protocol.is_active() bool#
Mengembalikan
Truejika host saat ini terhubung dan tumpukan protokol aktif, jika tidakFalse.
- protocol.poll() int#
Menjalankan satu iterasi tugas protokol: mengosongkan buffer penerimaan transport, mem-parsing setiap frame yang lengkap, mendispatch perintah, dan melayani event saluran. Firmware biasanya melakukan ini untuk Anda dari interupsi USB dan dari timer
poll_ms, sehingga ini hanya diperlukan untuk transport kustom yang tidak digerakkan oleh keduanya -- misalnya ketikapoll_ms=0dan transport di-polling dari loop utama skrip.Mengembalikan
0jika berhasil dan-1jika tidak ada transport aktif yang terdaftar atau pemanggilan dilakukan dari konteks interupsi.
- protocol.register(name: str, *, backend: object, flags: int = 0) ProtocolChannel#
Mendaftarkan objek Python
backendsebagai saluran logis baru dan mengembalikan handleProtocolChannel. Metode yang tersedia pada objekbackend(lihat Antarmuka Backend di bawah) menentukan kemampuan saluran;protocol.CHANNEL_FLAG_READ,protocol.CHANNEL_FLAG_WRITEdanprotocol.CHANNEL_FLAG_LOCKditambahkan keflagssecara otomatis ketika metode yang sesuai diimplementasikan.nameadalah nama saluran sebagai string. Dipotong ke ukuran buffer nama saluran firmware. Wajib.backendadalah objek Python yang mengimplementasikan antarmuka backend. Wajib. Biasanya diteruskan melalui kata kunci (backend=...).flagsadalah bit flag saluran tambahan (lihat konstantaCHANNEL_FLAG_*). Opsional; default ke0.Memunculkan
RuntimeErrorjika saluran tidak dapat didaftarkan (misalnya tidak ada slot saluran yang kosong).
Kelas#
- class protocol.ProtocolChannel#
Handle yang dikembalikan oleh
protocol.register. Instance tidak dibuat secara langsung.
Antarmuka Backend#
Objek backend yang diteruskan ke protocol.register dapat mengimplementasikan subset dari metode berikut. Hanya metode yang ada pada objek yang dihubungkan ke lapisan protokol C; metode yang hilang membuat kemampuan yang sesuai dinonaktifkan.
- class protocol.backend#
Objek backend saluran yang diteruskan ke
protocol.register. Metode di bawah ini menjelaskan antarmuka opsional yang dapat diimplementasikan oleh backend Python.- init() object#
Dipanggil sekali ketika saluran diinisialisasi. Kembalikan nilai non-
Noneapa pun jika berhasil; pengecualian atau pengembalian yang hilang diperlakukan sebagai error.
- shape() tuple#
Mengembalikan tuple hingga empat integer yang mendeskripsikan bentuk data (misalnya dimensi citra). Hingga empat elemen dikonsumsi oleh lapisan protokol.
- flush() object#
Membuang semua data yang tertunda. Mengembalikan nilai non-
Noneapa pun jika berhasil.
- read(offset: int, size: int) bytes#
Mengembalikan hingga
sizebyte mulai darioffsetsebagai objek sepertibytesyang mendukung protokol buffer.
- readp(offset: int, size: int) bytes#
Varian tanpa salinan dari
read. Mengembalikan buffer yang memori dasarnya dibaca langsung oleh lapisan protokol; buffer harus tetap valid selama durasi transfer.
- write(offset: int, data: bytearray) int#
Menulis
datapadaoffset.dataadalahbytearrayyang merujuk buffer C secara langsung. Mengembalikan jumlah byte yang ditulis, atau0untuk keberhasilan default.
- class protocol.CBORChannel(on_read: Callable | None = None, on_write: Callable | None = None)#
Backend Python tingkat lebih tinggi (disediakan oleh paket
protocolbeku) yang menyerialisasi kolom bernama ke CBOR menggunakan kunci integer yang kompatibel dengan SenML. Mendukung widget tampilan (label,text,depth,waveform) dan kontrol interaktif (toggle,pushbutton,slider,spinbox,select,radio,lineedit) dengan callbackon_read/on_write.on_readadalah callable opsionalon_read(channel)yang dipanggil sebelum saluran diserialisasi untuk host. Gunakan untuk menyegarkan nilai field.on_writeadalah callable opsionalon_write(channel, name, value)yang dipanggil ketika host menulis nilai baru untuk field bernama.- 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#
Menambahkan field bernama ke saluran.
nameadalah nama tampilan; harus unik dalam saluran ini.typeadalah tipe widget:"label"-- tampilan numerik hanya-baca denganunitopsional."text"-- tampilan string hanya-baca."toggle"-- sakelar boolean."pushbutton"-- aksi sesaat (trigger, kalibrasi, ...). Host menulisTruesaat diklik dan tidak menampilkan status apa pun."slider"-- kontrol numerik denganmin/max/step."spinbox"-- entri numerik bertahap yang presisi; berbagi kolom yang sama dengan slider serta bentuk pembaruan tuple(min, max, value)."select"-- drop-down dari stringoptions."radio"--optionsyang ditampilkan sebagai sekelompok tombol radio."lineedit"-- input string yang dapat ditulis."depth"-- tampilan peta kedalaman 2D berukuranwidthxheight."waveform"-- plot deret waktu 1D dari sampel yang di-interleave.
valueadalah nilai awal. Nilai default bergantung padatype:0untuklabel,""untuktext/lineedit/select/radio,Falseuntuktoggle/pushbutton,minuntukslider/spinbox.unitadalah string satuan untuklabel/slider/spinbox/waveform(misalnya"Cel","%RH").minadalah nilai minimum (rentang slider/spinbox, atau rentang tampilan depth/waveform).maxadalah nilai maksimum (rentang slider/spinbox, atau rentang tampilan depth/waveform).stepadalah ukuran langkah (slider/spinbox).optionsadalah daftar string opsi (select/radio), atau daftar nama per-seri (waveform).widthadalah lebar piksel (depth).heightadalah tinggi piksel (depth).sample_rateadalah laju sampel dalam sampel per detik (waveform). Dikirim ke host sebagai periode sampel.seriesadalah jumlah seri yang di-interleave dalam setiap blok sampel (waveform), misalnya3untuk jejak akselerometer XYZ.typecodeadalah typecodearraydari sampel waveform (misalnya"H","h","f"). Default-nya"H"(16-bit tanpa tanda).
- __getitem__(name: str) object#
Mengembalikan nilai saat ini dari kolom bernama. Untuk kolom
depthdanwaveform, buffer data biner yang dikembalikan; selain itu, nilai skalarnya.
- __setitem__(name: str, value: Any) None#
Mengatur nilai kolom bernama. Untuk kolom
sliderdanspinbox, tuple(min, max, value)memperbarui rentang dan nilai saat ini secara bersamaan. Untuk kolomdepth,valueadalah buffer data biner. Untuk kolomwaveform,valueadalah blok bytes-like berisi sampel yang di-interleave dalamtypecodekolom tersebut; jumlah sampel per seri diturunkan dari panjangnya dan stempel waktu monotonik (dalam mikrodetik, diakumulasikan daritime.ticks_us()) dilampirkan agar host dapat menempatkan potongan data tersebut pada sumbu waktunya.
- poll() bool#
Metode antarmuka backend. Mengembalikan
Trueketika data yang diserialisasi tersedia untuk host.
- size() int#
Metode antarmuka backend. Memanggil
on_read(jika diatur) dan mengembalikan ukuran buffer yang diserialisasi.
Konstanta#
Bit flag saluran (digabungkan secara bitwise; diteruskan ke protocol.register melalui flags atau diatur secara otomatis berdasarkan metode backend).
- protocol.CHANNEL_FLAG_PHYSICAL: int#
Saluran mewakili transport fisik (sebagai lawan dari saluran data logis).
Pengenal saluran bawaan.