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).الكاميرا
حجم المخزن
أقصى حمولة
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.is_active() bool¶
يُرجع
Trueإذا كان هناك مضيف متصل حاليًا وحزمة البروتوكول نشطة، وإلا فيُرجعFalse.
- 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إذا تعذّر تسجيل القناة (مثلًا عدم وجود فتحات قنوات شاغرة).
الأصناف¶
- class protocol.ProtocolChannel¶
المقبض الذي تُرجعه
protocol.register. لا تُنشأ النسخ مباشرة.
واجهة الخلفية¶
قد يطبّق كائن الخلفية الممرَّر إلى protocol.register أي مجموعة جزئية من الدوال التالية. تُربط فقط الدوال الموجودة على الكائن بطبقة بروتوكول C؛ أما الدوال الغائبة فتترك القدرة المقابلة معطّلة.
- 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_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هي القيمة الدنيا (مجال المنزلق أو مجال العمق).maxهي القيمة القصوى (مجال المنزلق أو مجال العمق).stepهو حجم الخطوة (المنزلق).optionsهي قائمة سلاسل الخيارات (select).widthهو العرض بالبكسل (depth).heightهو الارتفاع بالبكسل (depth).
- __getitem__(name: str) object¶
يُرجع القيمة الحالية للحقل المسمّى. بالنسبة لحقول
depthيُرجع مخزن البيانات الثنائية، وإلا فالقيمة العددية.
الثوابت¶
بتات أعلام القناة (تُدمج بعملية ثنائية على البتات؛ وتُمرَّر إلى protocol.register عبر flags أو تُضبط تلقائيًا بناءً على دوال الخلفية).
معرّفات القنوات المدمجة.