13.3.1.5. Sự kiện¶
Các trang cho đến nay gọi vào camera: tải lên tập lệnh, đọc một khung hình, ghi vào một kênh. Mọi thao tác đó đều được khởi tạo từ máy chủ -- máy chủ hỏi, camera phản hồi. Giao thức cũng chạy theo hướng ngược lại. Camera có thể đẩy sự kiện đến máy chủ mà không cần được hỏi, và SDK máy chủ chuyển mỗi sự kiện đến một hàm gọi lại mà ứng dụng có thể ghi đè.
Đây là công cụ phù hợp khi ứng dụng muốn phản ứng với điều gì đó mà camera nhận thấy trước khi được hỏi. Nếu không có sự kiện, cách duy nhất để tìm hiểu là tiếp tục gọi read_status() trong một vòng lặp.
13.3.1.5.1. Hàm gọi lại mặc định¶
Camera đã đăng ký sự kiện nội bộ. _handle_event() là hàm gọi lại mà transport chạy bất cứ khi nào một gói sự kiện đến. Mặc định xử lý ba sự kiện hệ thống:
CHANNEL_REGISTERED-- một kênh mới xuất hiện trên camera sau khi máy chủ kết nối. Framework làm mới bộ nhớ đệm kênh của nó để lần tra cứuhas_channel()tiếp theo tìm thấy nó.CHANNEL_UNREGISTERED-- một kênh đã biến mất.SOFT_REBOOT-- camera đã khởi động lại tự nó (watchdog, hard fault,machine.reset()có chủ ý).
Nó cũng theo dõi sự kiện frame-ready của kênh stream cho đường dẫn truyền phát và sự kiện bắt đầu/dừng tập lệnh của kênh stdin để đệm stdout. Mặc định events=True của constructor giữ tất cả điều này bật; một ứng dụng không muốn bất kỳ điều gì trong số đó có thể truyền events=False cho Camera và hệ thống con sự kiện vẫn im lặng.
13.3.1.5.2. Kế thừa để phản ứng¶
Để xử lý các sự kiện dành riêng cho ứng dụng mà camera nâng lên, hãy kế thừa Camera và ghi đè _handle_event(). Gọi parent trước để giữ hành vi mặc định, sau đó điều phối các sự kiện mà ứng dụng quan tâm:
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")
Chữ ký là (channel_id, event). channel_id là 0 cho các sự kiện hệ thống và nếu không thì là ID số của kênh đã nâng lên nó; event là một số nguyên mà tập lệnh phía camera đã chọn. Enum EventType đặt tên cho ba sự kiện hệ thống; các sự kiện kênh sử dụng bất cứ giá trị nào mà backend phía camera định nghĩa.
Các sự kiện kênh trả về được khóa bởi ID số, không phải tên. Dict channels_by_id được lưu trong bộ nhớ đệm là thứ mà phần ghi đè ở trên sử dụng để tra cứu tên; channels_by_name là bản phản chiếu của nó, được khóa theo hướng khác.
13.3.1.5.3. Nửa phía camera¶
Tập lệnh phía camera nâng lên một sự kiện bằng cách gọi send_event() trên handle được trả về từ 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)
Số sự kiện là một số nguyên được chọn bởi ứng dụng. Bất kỳ giá trị nào mà phần ghi đè của máy chủ sẵn sàng xử lý đều được chấp nhận; lớp giao thức coi nó là payload không minh bạch. Theo mặc định, cuộc gọi sẽ thực hiện và quên; truyền wait_ack=True để chặn cho đến khi máy chủ xác nhận, khi biết sự kiện đã đến quan trọng hơn độ trễ của chuyến đi khứ hồi.
Một kênh chỉ kích hoạt sự kiện và không mang dữ liệu có thể đọc là một mẫu hợp lệ -- size trả về 0 và read trả về byte rỗng. Thư viện giao thức vẫn cần cả hai phương thức hiện diện để đánh dấu kênh là có thể đọc; tập lệnh phía camera chỉ không bao giờ đặt dữ liệu vào đó.
13.3.1.5.4. Điều khiển đường dẫn nhận trong khi nhàn rỗi¶
Các sự kiện đến trên cùng kết nối như mọi thứ khác, vì vậy bất kỳ lần gọi máy chủ nào gửi hoặc nhận byte đều cho transport cơ hội xử lý các sự kiện đang chờ nội tuyến. Một vòng lặp thăm dò đã gọi read_status() hoặc read_frame() một lần mỗi chu kỳ không cần gì thêm.
Đối với các chương trình không có I/O khác trong nhiều phút, poll_events() chạy đường dẫn nhận một lần mà không gửi lệnh. Nó trả về ngay khi bộ đệm đến trống, vì vậy một vòng lặp chặt chẽ xung quanh nó -- hoặc một bộ định thời ngắn trong vòng lặp sự kiện GUI -- là thứ giữ cho các bộ xử lý phản ứng nhanh.
13.3.1.5.5. Một vòng lặp hoàn chỉnh¶
Từ đầu đến cuối, mẫu là: tập lệnh phía camera đăng ký một kênh và gọi send_event() khi có điều gì đó xảy ra; lớp con phía máy chủ ghi đè _handle_event() và điều phối. Một vòng lặp máy chủ chỉ làm gì ngoài việc phục vụ sự kiện trông như thế này:
with MyCamera('/dev/ttyACM0') as cam:
cam.stop()
cam.exec(open('motion_cam.py').read())
while True:
cam.poll_events()
Camera chụp, quyết định và nâng lên sự kiện. Máy chủ ngồi bên trong poll_events() cho đến khi có một sự kiện đến, sau đó on_motion chạy. Không có lần gọi read_status() nào chạy khi không có gì xảy ra, và không có khung hình nào được kéo qua USB khi camera không có gì để báo cáo.