protocol --- Các kênh giao thức OpenMV¶
Mô-đun protocol cung cấp giao thức máy chủ OpenMV cho Python. Nó cho phép ngăn xếp giao thức phía firmware được khởi tạo và cấu hình, đồng thời cho phép mã người dùng đăng ký các kênh logic tùy chỉnh được hỗ trợ bởi một đối tượng Python triển khai giao diện kênh (read, write, size, poll, v.v.). Đây là thứ mà các công cụ đồng hành trên máy tính để bàn nói chuyện khi chúng truyền trực tiếp dữ liệu ảnh hoặc hiển thị các tiện ích tương tác cho camera đã kết nối.
Ví dụ¶
Truyền trực tiếp ảnh RGB565 tới công cụ máy chủ sử dụng backend tùy chỉnh triển khai giao diện kênh thô (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
Tập lệnh phía máy chủ tương ứng, sử dụng gói Python openmv (pip install openmv) để kết nối, đẩy tập lệnh trên camera và kéo từng khung hình:
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()
Thay /dev/ttyACM0 bằng cổng serial của camera (ví dụ: COM3 trên Windows). Hàm khởi tạo openmv.camera.Camera chấp nhận các tham số giao thức tương tự như init (crc / seq / ack / events / max_payload / max_retry / timeout) khi ngăn xếp phía camera đã được cấu hình lại để khớp.
Hàm¶
- 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¶
Khởi tạo (hoặc cấu hình lại) ngăn xếp giao thức và đăng ký các kênh dữ liệu logic mặc định (
stdin,stdout,streamvà, nếu được biên dịch vào,profile). Phát sinhRuntimeErrornếu khởi tạo thất bại. Firmware khởi động với ngăn xếp giao thức USB mặc định đã chạy, vì vậy chỉ cần gọi hàm này khi muốn thay đổi phương tiện truyền tải hoặc ghi đè các tham số đóng khung mặc định.crcbật kiểm tra CRC trên các khung giao thức.seqbật theo dõi số thứ tự.ackbật xác nhận từng khung.eventsbật thông báo sự kiện kênh.max_payloadlà kích thước tải trọng tối đa tính bằng byte. Nếu bỏ qua, giá trị mặc định của từng camera bên dưới sẽ được sử dụng; nó được lấy từ kích thước bộ đệm giao thức của mỗi bo mạch theo công thứcbuffer - 10 (header) - 4 (CRC).Camera
Kích thước bộ đệm
Tải trọng tối đa
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_retrieslà số lần thử truyền lại. Mặc định là3.rtx_timeout_mslà thời gian chờ truyền lại tính bằng mili giây (tăng gấp đôi sau mỗi lần hết thời gian chờ). Mặc định là500.lock_interval_mslà khoảng thời gian khóa tối thiểu tính bằng mili giây. Mặc định là10.poll_mslà khoảng thời gian thăm dò tính bằng mili giây.0(mặc định) vô hiệu hóa thăm dò bằng bộ định thời.
- protocol.is_active() bool¶
Trả về
Truenếu máy chủ đang kết nối và ngăn xếp giao thức đang hoạt động, ngược lại trả vềFalse.
- protocol.register(name: str, *, backend: object, flags: int = 0) ProtocolChannel¶
Đăng ký đối tượng Python
backendnhư một kênh logic mới và trả về handleProtocolChannel. Các phương thức khả dụng của đối tượngbackend(xem Giao diện Backend bên dưới) xác định khả năng của kênh;protocol.CHANNEL_FLAG_READ,protocol.CHANNEL_FLAG_WRITEvàprotocol.CHANNEL_FLAG_LOCKđược tự động thêm vàoflagskhi các phương thức tương ứng được triển khai.namelà tên kênh dưới dạng chuỗi. Bị cắt ngắn theo kích thước bộ đệm tên kênh của firmware. Bắt buộc.backendlà đối tượng Python triển khai giao diện backend. Bắt buộc. Thường được truyền theo từ khóa (backend=...).flagslà các bit cờ kênh bổ sung (xem hằng sốCHANNEL_FLAG_*). Tùy chọn; mặc định là0.Phát sinh
RuntimeErrornếu kênh không thể được đăng ký (ví dụ: không còn khe kênh trống).
Lớp¶
- class protocol.ProtocolChannel¶
Handle được trả về bởi
protocol.register. Các thực thể không được khởi tạo trực tiếp.
Giao diện Backend¶
Đối tượng backend được truyền tới protocol.register có thể triển khai bất kỳ tập hợp con nào của các phương thức sau. Chỉ các phương thức hiện diện trên đối tượng mới được kết nối với lớp giao thức C; các phương thức bị thiếu sẽ để khả năng tương ứng bị vô hiệu hóa.
- class protocol.backend¶
Đối tượng backend kênh được truyền tới
protocol.register. Các phương thức bên dưới mô tả giao diện tùy chọn mà một backend Python có thể triển khai.- init() object¶
Được gọi một lần khi kênh được khởi tạo. Trả về bất kỳ giá trị nào khác
Nonekhi thành công; ngoại lệ hoặc thiếu giá trị trả về được coi là lỗi.
- shape() tuple¶
Trả về một tuple gồm tối đa bốn số nguyên mô tả hình dạng dữ liệu (ví dụ: kích thước ảnh). Tối đa bốn phần tử được lớp giao thức sử dụng.
- read(offset: int, size: int) bytes¶
Trả về tối đa
sizebyte bắt đầu từoffsetdưới dạng đối tượng giốngbyteshỗ trợ giao thức bộ đệm.
- readp(offset: int, size: int) bytes¶
Biến thể không sao chép của
read. Trả về bộ đệm có bộ nhớ cơ bản được lớp giao thức đọc trực tiếp; bộ đệm phải hợp lệ trong suốt quá trình truyền.
- write(offset: int, data: bytearray) int¶
Ghi
datatạioffset.datalàbytearraytham chiếu trực tiếp tới bộ đệm C. Trả về số byte đã ghi, hoặc0khi thành công mặc định.
- class protocol.CBORChannel(on_read: Callable | None = None, on_write: Callable | None = None)¶
Một backend Python cấp cao hơn (được cung cấp bởi gói
protocolđóng băng) để tuần tự hóa các trường có tên thành CBOR bằng khóa nguyên số tương thích SenML. Hỗ trợ tiện ích hiển thị (label,depth) và điều khiển tương tác (toggle,slider,select) với hàm gọi lạion_read/on_write.on_readlà callable tùy chọnon_read(channel)được gọi trước khi kênh được tuần tự hóa cho máy chủ. Dùng để làm mới giá trị trường.on_writelà callable tùy chọnon_write(channel, name, value)được gọi khi máy chủ ghi giá trị mới cho một trường có tên.- 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¶
Thêm một trường có tên vào kênh.
namelà tên hiển thị; phải là duy nhất trong kênh này.typelà loại tiện ích:"label","toggle","slider","select", hoặc"depth".valuelà giá trị ban đầu. Giá trị mặc định phụ thuộc vàotype.unitlà chuỗi đơn vị cholabel/slider(ví dụ:"Cel","%RH").minlà giá trị tối thiểu (phạm vi slider hoặc phạm vi depth).maxlà giá trị tối đa (phạm vi slider hoặc phạm vi depth).steplà kích thước bước (slider).optionslà danh sách các chuỗi tùy chọn (select).widthlà chiều rộng tính bằng điểm ảnh (depth).heightlà chiều cao tính bằng điểm ảnh (depth).
- __getitem__(name: str) object¶
Trả về giá trị hiện tại của trường có tên. Đối với trường
depth, bộ đệm dữ liệu nhị phân được trả về; ngược lại là giá trị vô hướng.
- __setitem__(name: str, value: Any) None¶
Đặt giá trị của trường có tên. Đối với trường
slider, một tuple(min, max, value)cập nhật phạm vi và giá trị hiện tại cùng lúc. Đối với trườngdepth,valuelà bộ đệm dữ liệu nhị phân.
- poll() bool¶
Phương thức giao diện backend. Trả về
Truekhi dữ liệu đã tuần tự hóa sẵn sàng cho máy chủ.
- size() int¶
Phương thức giao diện backend. Gọi
on_read(nếu được đặt) và trả về kích thước của bộ đệm đã tuần tự hóa.
Hằng số¶
Các bit cờ kênh (kết hợp theo bit; được truyền tới protocol.register qua flags hoặc được đặt tự động dựa trên các phương thức của backend).
- protocol.CHANNEL_FLAG_PHYSICAL: int¶
Kênh đại diện cho một phương tiện truyền tải vật lý (khác với kênh dữ liệu logic).
Định danh kênh tích hợp sẵn.