protocol --- ช่องสัญญาณโปรโตคอล OpenMV¶
โมดูล protocol เปิดเผยโปรโตคอลโฮสต์ OpenMV สู่ Python ช่วยให้สามารถเริ่มต้นและกำหนดค่าสแต็กโปรโตคอลฝั่งเฟิร์มแวร์ได้ และให้โค้ดผู้ใช้ลงทะเบียนช่องสัญญาณเชิงตรรกะแบบกำหนดเองที่รองรับด้วยออบเจกต์ Python ที่ใช้อินเทอร์เฟซช่องสัญญาณ (read, write, size, poll เป็นต้น) นี่คือสิ่งที่เครื่องมือคู่หูบนเดสก์ท็อปพูดถึงเมื่อสตรีมข้อมูลภาพหรือแสดงวิดเจ็ตแบบโต้ตอบกับกล้องที่เชื่อมต่อ
ตัวอย่าง¶
สตรีมภาพ RGB565 ไปยังเครื่องมือโฮสต์โดยใช้แบ็กเอนด์แบบกำหนดเองที่ใช้อินเทอร์เฟซช่องสัญญาณดิบ (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
สคริปต์ฝั่งโฮสต์ที่ตรงกัน โดยใช้แพ็กเกจ Python openmv (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 ด้วยพอร์ตซีเรียลของกล้อง (เช่น COM3 บน Windows) ตัวสร้าง 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)Camera
ขนาดบัฟเฟอร์
เพย์โหลดสูงสุด
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คือจำนวนครั้งในการส่งซ้ำ ค่าเริ่มต้นคือ3rtx_timeout_msคือช่วงเวลาหมดเวลาการส่งซ้ำในมิลลิวินาที (เพิ่มเป็นสองเท่าหลังจากแต่ละการหมดเวลา) ค่าเริ่มต้นคือ500lock_interval_msคือช่วงเวลาล็อกขั้นต่ำในมิลลิวินาที ค่าเริ่มต้นคือ10poll_msคือช่วงเวลาโพลในมิลลิวินาที0(ค่าเริ่มต้น) ปิดการใช้งานการโพลแบบตัวจับเวลา
- protocol.is_active() bool¶
ส่งคืน
Trueหากโฮสต์เชื่อมต่ออยู่ในขณะนี้และสแต็กโปรโตคอลทำงานอยู่ มิฉะนั้นจะส่งคืนFalse
- protocol.register(name: str, *, backend: object, flags: int = 0) ProtocolChannel¶
ลงทะเบียนออบเจกต์ Python
backendเป็นช่องสัญญาณเชิงตรรกะใหม่และส่งคืน handleProtocolChannelเมธอดที่มีอยู่ของออบเจกต์backend(ดู อินเทอร์เฟซแบ็กเอนด์ ด้านล่าง) จะกำหนดความสามารถของช่องสัญญาณ โดยprotocol.CHANNEL_FLAG_READ,protocol.CHANNEL_FLAG_WRITEและprotocol.CHANNEL_FLAG_LOCKจะถูกเพิ่มในflagsโดยอัตโนมัติเมื่อมีการใช้งานเมธอดที่เกี่ยวข้องnameคือชื่อช่องสัญญาณเป็นสตริง จะถูกตัดให้สั้นลงตามขนาดบัฟเฟอร์ชื่อช่องสัญญาณของเฟิร์มแวร์ จำเป็นbackendคือออบเจกต์ Python ที่ใช้อินเทอร์เฟซแบ็กเอนด์ จำเป็น โดยทั่วไปส่งผ่านโดยคีย์เวิร์ด (backend=...)flagsคือบิตแฟล็กช่องสัญญาณเพิ่มเติม (ดูค่าคงที่CHANNEL_FLAG_*) ไม่บังคับ ค่าเริ่มต้นคือ0ยกข้อผิดพลาด
RuntimeErrorหากไม่สามารถลงทะเบียนช่องสัญญาณได้ (เช่น ไม่มีช่องสัญญาณว่าง)
คลาส¶
- class protocol.ProtocolChannel¶
Handle ที่ส่งคืนโดย
protocol.registerไม่สร้าง Instance โดยตรง
อินเทอร์เฟซแบ็กเอนด์¶
ออบเจกต์แบ็กเอนด์ที่ส่งไปยัง protocol.register อาจใช้เมธอดย่อยใดก็ได้จากต่อไปนี้ มีเฉพาะเมธอดที่มีอยู่ในออบเจกต์เท่านั้นที่จะถูกเชื่อมต่อกับชั้น C protocol เมธอดที่หายไปจะปิดใช้งานความสามารถที่เกี่ยวข้อง
- class protocol.backend¶
ออบเจกต์แบ็กเอนด์ช่องสัญญาณที่ส่งไปยัง
protocol.registerเมธอดด้านล่างอธิบายอินเทอร์เฟซเสริมที่แบ็กเอนด์ Python อาจใช้งาน- init() object¶
เรียกใช้ครั้งเดียวเมื่อช่องสัญญาณถูกเริ่มต้น ส่งคืนค่าที่ไม่ใช่
Noneใดก็ได้เพื่อบ่งชี้ความสำเร็จ ข้อยกเว้นหรือการขาดค่าส่งคืนจะถูกถือเป็นข้อผิดพลาด
- shape() tuple¶
ส่งคืน tuple ของจำนวนเต็มสูงสุดสี่ตัวที่อธิบายรูปร่างของข้อมูล (เช่น มิติของภาพ) โดยโปรโตคอลเลเยอร์จะใช้สูงสุดสี่องค์ประกอบ
- read(offset: int, size: int) bytes¶
ส่งคืนสูงสุด
sizeไบต์เริ่มต้นที่offsetเป็นออบเจกต์คล้ายbytesที่รองรับโปรโตคอลบัฟเฟอร์
- readp(offset: int, size: int) bytes¶
ตัวแปร zero-copy ของ
readส่งคืนบัฟเฟอร์ที่หน่วยความจำพื้นฐานถูกอ่านโดยตรงโดยชั้นโปรโตคอล บัฟเฟอร์ต้องยังคงใช้งานได้ตลอดระยะเวลาการถ่ายโอน
- write(offset: int, data: bytearray) int¶
เขียน
dataที่offsetโดยdataคือbytearrayที่อ้างอิงบัฟเฟอร์ C โดยตรง ส่งคืนจำนวนไบต์ที่เขียน หรือ0เมื่อสำเร็จตามค่าเริ่มต้น
- class protocol.CBORChannel(on_read: Callable | None = None, on_write: Callable | None = None)¶
แบ็กเอนด์ Python ระดับสูงกว่า (จัดเตรียมโดยแพ็กเกจ
protocolที่ถูกฝัง) ซึ่งจัดลำดับฟิลด์ที่มีชื่อเป็น CBOR โดยใช้คีย์จำนวนเต็มที่เข้ากันได้กับ SenML รองรับวิดเจ็ตแสดงผล (label,depth) และตัวควบคุมแบบโต้ตอบ (toggle,slider,select) พร้อมคอลแบ็กon_read/on_writeon_readคือ callable เสริมon_read(channel)ที่เรียกใช้ก่อนที่ช่องสัญญาณจะถูกจัดลำดับสำหรับโฮสต์ ใช้เพื่อรีเฟรชค่าฟิลด์on_writeคือ callable เสริม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คือค่าเริ่มต้น ค่าเริ่มต้นขึ้นอยู่กับtypeunitคือสตริงหน่วยสำหรับlabel/slider(เช่น"Cel","%RH")minคือค่าต่ำสุด (ช่วง slider หรือช่วง depth)maxคือค่าสูงสุด (ช่วง slider หรือช่วง depth)stepคือขนาดขั้นตอน (slider)optionsคือรายการสตริงตัวเลือก (select)widthคือความกว้างเป็นพิกเซล (depth)heightคือความสูงเป็นพิกเซล (depth)
- __getitem__(name: str) object¶
ส่งคืนค่าปัจจุบันของฟิลด์ที่มีชื่อ สำหรับฟิลด์
depthจะส่งคืนบัฟเฟอร์ข้อมูลไบนารี มิฉะนั้นจะส่งคืนค่าสเกลาร์
- __setitem__(name: str, value: Any) None¶
กำหนดค่าของฟิลด์ที่มีชื่อ สำหรับฟิลด์
slidertuple(min, max, value)จะอัปเดตช่วงและค่าปัจจุบันพร้อมกัน สำหรับฟิลด์depthvalueคือบัฟเฟอร์ข้อมูลไบนารี
- size() int¶
เมธอดอินเทอร์เฟซแบ็กเอนด์ เรียกใช้
on_read(หากตั้งค่าไว้) และส่งคืนขนาดของบัฟเฟอร์ที่จัดลำดับแล้ว
ค่าคงที่¶
บิตแฟล็กช่องสัญญาณ (รวมกันแบบ bitwise ส่งไปยัง protocol.register ผ่าน flags หรือตั้งค่าโดยอัตโนมัติตามเมธอดของแบ็กเอนด์)
- protocol.CHANNEL_FLAG_PHYSICAL: int¶
ช่องสัญญาณแทนการขนส่งทางกายภาพ (ตรงกันข้ามกับช่องสัญญาณข้อมูลเชิงตรรกะ)
ตัวระบุช่องสัญญาณในตัว