13.3.1.5. เหตุการณ์¶
หน้าที่ผ่านมาเรียกใช้กล้อง: อัปโหลดสคริปต์ อ่านเฟรม เขียนไปยังช่องสัญญาณ ทุกการดำเนินการเหล่านั้นเริ่มต้นโดยโฮสต์ -- โฮสต์ถาม กล้องตอบ โปรโตคอลยังทำงานในทิศทางอื่นด้วย กล้องสามารถ push เหตุการณ์ไปยังโฮสต์โดยไม่ถูกถาม และ SDK โฮสต์ส่งแต่ละอันไปยังคอลแบ็กที่แอปพลิเคชันสามารถแทนที่ได้
นี่คือเครื่องมือที่เหมาะสมเมื่อแอปพลิเคชันต้องการตอบสนองต่อสิ่งที่กล้องสังเกตเห็นก่อนที่จะถาม หากไม่มีเหตุการณ์ วิธีเดียวที่จะหาคือต้องเรียก read_status() ในลูปต่อเนื่อง
13.3.1.5.1. คอลแบ็กเริ่มต้น¶
Camera สมัครสมาชิกเหตุการณ์ภายในแล้ว _handle_event() คือคอลแบ็กที่ transport รันเมื่อใดก็ตามที่แพ็กเก็ตเหตุการณ์มาถึง ค่าเริ่มต้นจัดการเหตุการณ์ระบบสาม:
CHANNEL_REGISTERED-- ช่องสัญญาณใหม่ปรากฏบนกล้องหลังจากโฮสต์เชื่อมต่อ framework รีเฟรชแคชช่องสัญญาณเพื่อให้การค้นหาhas_channel()ถัดไปพบมันCHANNEL_UNREGISTERED-- ช่องสัญญาณหายไปSOFT_REBOOT-- กล้องรีบูตเอง (watchdog, hard fault,machine.reset()ที่ตั้งใจ)
นอกจากนี้ยังติดตามเหตุการณ์เฟรมพร้อมของช่องสัญญาณ stream สำหรับเส้นทางสตรีมมิ่งและการเริ่ม/หยุดสคริปต์ของช่องสัญญาณ stdin สำหรับการบัฟเฟอร์ stdout ค่าเริ่มต้น events=True ของ constructor เปิดสิ่งนี้ทั้งหมด; แอปพลิเคชันที่ไม่ต้องการสิ่งใดสามารถส่ง events=False ไปยัง Camera และระบบย่อยเหตุการณ์จะเงียบ
13.3.1.5.2. การสร้าง subclass เพื่อตอบสนอง¶
เพื่อจัดการเหตุการณ์เฉพาะแอปพลิเคชันที่กล้องยกขึ้น ให้สร้าง subclass Camera และแทนที่ _handle_event() เรียก parent ก่อนเพื่อรักษาพฤติกรรมเริ่มต้น จากนั้น dispatch เหตุการณ์ที่แอปพลิเคชันสนใจ:
from openmv import Camera
class MyCamera(Camera):
def _handle_event(self, channel_id, event):
super()._handle_event(channel_id, event)
name = self.channels_by_id.get(
channel_id, {}).get('name')
if name == 'motion' and event == 1:
self.on_motion()
def on_motion(self):
print("motion detected")
ลายเซ็นคือ (channel_id, event) channel_id คือ 0 สำหรับเหตุการณ์ระบบและมิฉะนั้นเป็น ID ตัวเลขของช่องสัญญาณที่ยกมัน; event คือจำนวนเต็มที่สคริปต์ฝั่งกล้องเลือก enum EventType ตั้งชื่อให้กับเหตุการณ์ระบบสาม; เหตุการณ์ช่องสัญญาณใช้ค่าใดก็ตามที่ backend ฝั่งกล้องกำหนด
เหตุการณ์ช่องสัญญาณกลับมาโดยตรวจสอบด้วย ID ตัวเลข ไม่ใช่ชื่อ dict channels_by_id ที่แคชไว้คือสิ่งที่ override ข้างต้นใช้เพื่อค้นหาชื่อ; channels_by_name คือกระจกของมัน โดยมีกุญแจอีกทาง
13.3.1.5.3. ฝั่งกล้อง¶
สคริปต์ฝั่งกล้องยกเหตุการณ์โดยเรียก send_event() บน handle ที่ส่งคืนจาก protocol.register()
import protocol
class MotionChannel:
def size(self):
return 0
def read(self, offset, size):
return b''
def poll(self):
return False
ch = protocol.register(
name='motion', backend=MotionChannel())
while True:
if detect_motion():
ch.send_event(1)
หมายเลขเหตุการณ์เป็นจำนวนเต็มที่แอปพลิเคชันเลือก ค่าใดก็ตามที่ override ของโฮสต์พร้อมรองรับเป็นสิ่งที่ยอมรับได้; ชั้นโปรโตคอลถือว่ามันเป็นเพย์โหลดทึบ ตามค่าเริ่มต้นการเรียกจะ fire และลืม; ส่ง wait_ack=True เพื่อบล็อกจนกว่าโฮสต์จะยอมรับ เมื่อการรู้ว่าเหตุการณ์ถึงสำคัญกว่าเวลาแฝงของรอบ
ช่องสัญญาณที่ fire เหตุการณ์เท่านั้นและไม่มีข้อมูลที่อ่านได้เป็นรูปแบบที่ถูกต้อง -- size ส่งคืน 0 และ read ส่งคืนไบต์ว่าง ไลบรารีโปรโตคอลยังต้องการทั้งสองเมธอดเพื่อทำเครื่องหมายช่องสัญญาณว่าอ่านได้; สคริปต์ฝั่งกล้องเพียงแค่ไม่เคยใส่ข้อมูลในมัน
13.3.1.5.4. ขับเส้นทางรับขณะไม่ได้ใช้งาน¶
เหตุการณ์มาถึงบนการเชื่อมต่อเดิมกับทุกอย่างอื่น ดังนั้นการเรียกโฮสต์ใดก็ตามที่ส่งหรือรับไบต์ให้ transport มีโอกาสประมวลผลเหตุการณ์ที่รออยู่แบบ inline ลูปโพลที่เรียก read_status() หรือ read_frame() หนึ่งครั้งต่อรอบไม่ต้องการอะไรพิเศษ
สำหรับโปรแกรมที่ไปหลายนาทีโดยไม่มี I/O อื่น poll_events() รันเส้นทางรับหนึ่งครั้งโดยไม่ส่งคำสั่ง มันส่งคืนทันทีที่บัฟเฟอร์ขาเข้าว่าง ดังนั้นลูปที่แน่นรอบมัน -- หรือตัวจับเวลาสั้นในลูปเหตุการณ์ GUI -- คือสิ่งที่ทำให้ handler ตอบสนอง
13.3.1.5.5. ลูปสมบูรณ์¶
แบบ end-to-end รูปแบบคือ: สคริปต์ฝั่งกล้องลงทะเบียนช่องสัญญาณและเรียก send_event() เมื่อมีบางอย่างเกิดขึ้น; subclass ฝั่งโฮสต์แทนที่ _handle_event() และ dispatch ลูปโฮสต์ที่ไม่ทำอะไรนอกจากรับเหตุการณ์มีลักษณะดังนี้:
with MyCamera('/dev/ttyACM0') as cam:
cam.stop()
cam.exec(open('motion_cam.py').read())
while True:
cam.poll_events()
กล้องจับภาพ ตัดสิน และยกเหตุการณ์ โฮสต์นั่งใน poll_events() จนกว่าจะมาถึง จากนั้น on_motion รัน ไม่มีการเรียก read_status() เมื่อไม่มีอะไรเกิดขึ้น และไม่มีเฟรมถูกดึงข้าม USB เมื่อกล้องไม่มีอะไรรายงาน