protocol --- OpenMV 協定通道¶
protocol 模組將 OpenMV 主機協定開放給 Python 使用。它允許初始化與設定韌體端的協定堆疊,並讓使用者程式碼註冊由實作通道介面(read、write、size、poll 等)的 Python 物件支援的自訂邏輯通道。當桌面端的搭配工具串流影像資料,或向已連線的相機開放互動式小工具時,所溝通的就是此協定。
範例¶
使用實作原始通道介面(backend.size()、backend.shape()、backend.poll()、backend.read())的自訂後端,將 RGB565 影像串流至主機工具::
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
對應的主機端指令碼,使用 openmv Python 套件(pip install openmv)來連線、推送相機端指令碼,並拉取每一個影格::
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()
請將 /dev/ttyACM0 替換為相機的序列埠(例如在 Windows 上為 COM3)。當相機端的堆疊已重新設定為相符時,openmv.camera.Camera 建構式接受與 init 相同的協定參數(crc / seq / ack / events / max_payload / max_retry / timeout)。
函式¶
- 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¶
初始化(或重新設定)協定堆疊,並註冊預設的邏輯資料通道(
stdin、stdout、stream,以及若有編譯進來的profile)。若初始化失敗則引發RuntimeError。韌體開機時已執行預設的 USB 協定堆疊,因此只有在要變更傳輸方式或覆寫預設的訊框參數時才需要呼叫此函式。crc啟用協定訊框上的 CRC 驗證。seq啟用序號追蹤。ack啟用每訊框的確認。events啟用通道事件通知。max_payload為以位元組計的最大酬載大小。若省略則使用下方各相機的預設值;該值由每塊板子的協定緩衝區大小推導而來,計算方式為buffer - 10 (header) - 4 (CRC)。相機
緩衝區大小
最大酬載
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為重傳嘗試次數。預設為3。rtx_timeout_ms為以毫秒計的重傳逾時時間(每次逾時後加倍)。預設為500。lock_interval_ms為以毫秒計的最小鎖定間隔。預設為10。poll_ms為以毫秒計的輪詢間隔。0(預設值)會停用計時器輪詢。
- protocol.register(name: str, *, backend: object, flags: int = 0) ProtocolChannel¶
將一個 Python
backend物件註冊為新的邏輯通道,並回傳一個ProtocolChannel控制代碼。backend物件可用的方法(見下方 後端介面)決定該通道的能力;當對應方法有實作時,protocol.CHANNEL_FLAG_READ、protocol.CHANNEL_FLAG_WRITE與protocol.CHANNEL_FLAG_LOCK會自動加入flags。name為字串形式的通道名稱。會被截斷至韌體的通道名稱緩衝區大小。必填。backend為實作後端介面的 Python 物件。必填。通常以關鍵字傳入(backend=...)。flags為額外的通道旗標位元(見CHANNEL_FLAG_*常數)。選填;預設為0。若無法註冊通道(例如沒有空閒的通道槽)則引發
RuntimeError。
類別¶
後端介面¶
傳入 protocol.register 的後端物件可以實作下列方法的任何子集。只有該物件上實際存在的方法會接到 C 協定層;缺少的方法會使對應能力停用。
- class protocol.backend¶
傳入
protocol.register的通道後端物件。下列方法描述 Python 後端可實作的選用介面。- write(offset: int, data: bytearray) int¶
在
offset處寫入data。data為直接參照 C 緩衝區的bytearray。回傳寫入的位元組數,或在預設成功時回傳0。
- class protocol.CBORChannel(on_read: Callable | None = None, on_write: Callable | None = None)¶
一個較高階的 Python 後端(由凍結的
protocol套件提供),會使用相容於 SenML 的整數鍵將具名欄位序列化為 CBOR。支援顯示小工具(label、depth)與互動式控制項(toggle、slider、select),並具備on_read/on_write回呼函式。on_read為選用的可呼叫物件on_read(channel),會在通道為主機序列化之前被呼叫。可用它來重新整理欄位值。on_write為選用的可呼叫物件on_write(channel, name, value),會在主機寫入某具名欄位的新值時被呼叫。- 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¶
在通道中加入一個具名欄位。
name為顯示名稱;在此通道內必須唯一。type為小工具類型:"label"、"toggle"、"slider"、"select"或"depth"。value為初始值。預設值取決於type。unit為label/slider的單位字串(例如"Cel"、"%RH")。min為最小值(slider 範圍或 depth 範圍)。max為最大值(slider 範圍或 depth 範圍)。step為步進大小(slider)。options為選項字串清單(select)。width為像素寬度(depth)。height為像素高度(depth)。
常數¶
通道旗標位元(以位元方式組合;透過 flags 傳入 protocol.register,或依後端的方法自動設定)。
內建通道識別碼。