13.1.10. نوافذ الطرفية المستقلة¶
يفتح Tools → Open Terminal نوافذ طرفية مستقلة -- كل واحدة منها جلسة OpenMV IDE مصغّرة في نافذتها الخاصة، مع عارض لمخزن الإطارات، ومدرج تكراري، وطرفية تفاعلية، متصلة عبر وسيلة نقل من اختيارك. ولا يتأثر اتصال النافذة الرئيسية بذلك، لذا تتيح لك الطرفية المستقلة مراقبة كاميرا ثانية بينما تبقى الأولى متصلة، أو تنقيح أخطاء كاميرا على الطرف البعيد من الشبكة.
نافذة طرفية مستقلة عبر منفذ تسلسلي: الطرفية التفاعلية على اليسار مع شريط أدوات التشغيل / الإيقاف / إعادة الضبط، ومخزن الإطارات والمدرج التكراري على اليمين -- وهما يضيئان عندما تبث الكاميرا الإطارات ضمن النطاق.¶
يطلب New Terminal إحدى وسائل النقل الثلاث:
المنفذ التسلسلي -- أي منفذ تسلسلي بأي معدل باود (الافتراضي 115,200). يشمل ذلك منفذ USB الخاص بكاميرا ثانية، أو كاميرا موصولة عبر جسر USB-to-UART، أو وصلة تسلسلية عبر Bluetooth (تظهر كمنفذ تسلسلي عادي)، أو أي جهاز تسلسلي غير تابع لـ OpenMV يحتاج إلى طرفية. على منفذ USB لا يحدّ معدل الباود السرعة -- إذ تنتقل البيانات دائمًا بسرعة وصلة USB -- لكن على منفذ USB الخاص بالكاميرا تجنّب 921,600 و12,000,000، اللذين يحوّلان الكاميرا من REPL إلى بروتوكول التنقيح الخاص بالـ IDE.
TCP -- الاتصال بخادم على مضيف ومنفذ مختارين، أو الإنصات كخادم على منفذ مختار.
UDP -- الزوج نفسه من الأدوار، عبر UDP.
يتذكر الـ IDE آخر عشر تكوينات ويسردها في القائمة الفرعية Open Terminal لإعادة فتحها بنقرة واحدة؛ ويمسحها Clear Menu.
خلافًا للجزء المخصّص للإخراج فقط في النافذة الرئيسية، فإن الطرفية المستقلة تفاعلية بالكامل: إنها REPL. اكتب عند المحث وستنفّذ Python على الكاميرا المتصلة سطرًا تلو الآخر، مع السجل وإكمال الجدولة (tab) اللذين توفرهما MicroPython نفسها. ويضيف شريط الأدوات مكافئات بنقرة واحدة لتسلسلات التحكم الشائعة -- تشغيل البرنامج النصي الحالي في المحرر، وإيقاف البرنامج النصي قيد التشغيل، وإعادة الضبط الناعمة -- إلى جانب عناصر التحكم نفسها للمسح والحفظ والالتفاف الموجودة في جزء الطرفية الرئيسي.
مخزن الإطارات فوق الطرفية حيّ أيضًا. فعندما تبث الكاميرا المتصلة إطارات مضغوطة ضمن النطاق -- مضمّنة في التيار نفسه الذي يحمل إخراج الطباعة -- تفك الطرفية ترميزها وتعرضها، ويعمل زرّا Record وZoom تمامًا كما في النافذة الرئيسية. هذه التركيبة هي قصة التنقيح عبر الشبكة في الـ IDE: كاميرا تعرض REPL الخاص بها عبر Wi-Fi تحصل على حلقة التحرير-التشغيل-المعاينة الكاملة دون أي كابل USB.
13.1.10.1. بث الإطارات ضمن النطاق¶
الترميز الذي تفهمه الطرفية بسيط: بايت 0xFE يفتح إطارًا، وبايت 0xFE ثانٍ يغلقه، وكل بايت حمولة بينهما يكون بِته الأعلى مضبوطًا ويحمل ست بِتات من الصورة المضغوطة -- فثلاثة بايتات من الصورة تصبح أربعة بايتات حمولة. النص العادي لا يستخدم تلك القيم البايتية أبدًا، لذا تتشارك الإطارات وإخراج print() التيار دون تصادم: تعرض الطرفية النص وتعرض الإطارات.
يلتقط البرنامج النصي أدناه الصورة، ويحوّل كل إطار إلى JPEG، ويطبعه بذلك الشكل. وتجري حزم البِتات عبر ulab (التي لا تملك عوامل إزاحة، لذا تُكتب الإزاحات على هيئة عمليات ضرب وقسمة)، وهي سريعة بما يكفي لمواكبة الكاميرا:
import csi
import sys
import time
from ulab import numpy as np
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QVGA)
clock = time.clock()
def encode_for_ide(data):
n = len(data)
n3 = n - (n % 3)
m = (n3 // 3) * 4
out = bytearray(((n * 8) + 5) // 6 + 2)
out[0] = 0xFE
out[-1] = 0xFE
if n3:
src = np.frombuffer(data, dtype=np.uint8)
dst = np.frombuffer(out, dtype=np.uint8)
b0 = src[0:n3:3]
b1 = src[1:n3:3]
b2 = src[2:n3:3]
dst[1:m + 1:4] = (b0 & 0x3F) | 0x80
dst[2:m + 2:4] = (b0 // 64) | ((b1 & 0x0F) * 4) | 0x80
dst[3:m + 3:4] = (b1 // 16) | ((b2 & 0x03) * 16) | 0x80
dst[4:m + 4:4] = (b2 // 4) | 0x80
if n % 3 == 2:
x = data[n - 2] | (data[n - 1] << 8)
out[m + 1] = 0x80 | (x & 0x3F)
out[m + 2] = 0x80 | ((x >> 6) & 0x3F)
out[m + 3] = 0x80 | ((x >> 12) & 0x3F)
elif n % 3 == 1:
out[m + 1] = 0x80 | (data[n - 1] & 0x3F)
out[m + 2] = 0x80 | (data[n - 1] >> 6)
return out
while True:
clock.tick()
img = csi0.snapshot().to_jpeg(quality=80)
sys.stdout.write(encode_for_ide(img.bytearray()))
print(clock.fps())
ينجح هذا في طرفية مستقلة لأن طباعة REPL تنتظر: تتوقف الكاميرا حتى تأخذ الطرفية البيانات، فيصل كل بايت من الإطار، وتنتقل صورة JPEG بسرعة عبر وصلة USB بالسرعة الكاملة أو العالية. ويعمل البرنامج النصي نفسه دون تغيير عبر طرفية TCP، وهو مسار التنقيح عبر الشبكة المذكور أعلاه. المكان الوحيد الذي لا ينجح فيه هو اتصال التنقيح الرئيسي للـ IDE، الذي تعيد قناة الإخراج فيه ضبط نفسها عند الفيض بدلًا من الانتظار -- وهناك يعرض عارض مخزن الإطارات إطارات الكاميرا أصلًا، فلا يفوت شيء.