13.1.10. Cửa sổ terminal độc lập

Tools → Open Terminal mở các cửa sổ terminal độc lập -- mỗi cửa sổ là một phiên OpenMV IDE thu nhỏ trong cửa sổ riêng của nó, với trình xem bộ đệm khung hình, biểu đồ tần suất và terminal tương tác, kết nối qua giao thức truyền tải do bạn chọn. Kết nối của cửa sổ chính không bị ảnh hưởng, vì vậy terminal độc lập cho phép bạn theo dõi camera thứ hai trong khi camera đầu tiên vẫn kết nối, hoặc gỡ lỗi một camera ở phía bên kia mạng.

A standalone terminal window: interactive terminal on the left with its toolbar, frame buffer and histogram on the right

Một cửa sổ terminal độc lập qua cổng serial: terminal tương tác ở bên trái với thanh công cụ chạy / dừng / đặt lại, bộ đệm khung hình và biểu đồ tần suất ở bên phải -- chúng sẽ hiển thị khi camera phát trực tiếp các khung hình trong luồng.

New Terminal yêu cầu một trong ba giao thức truyền tải:

  • Cổng Serial -- bất kỳ cổng serial nào với bất kỳ tốc độ baud nào (mặc định 115.200). Điều này bao gồm cổng USB của camera thứ hai, camera được kết nối qua bộ chuyển đổi USB-to-UART, liên kết serial Bluetooth (hiển thị như một cổng serial thông thường), hoặc bất kỳ thiết bị serial không phải OpenMV nào cần terminal. Trên cổng USB, tốc độ baud không giới hạn tốc độ -- dữ liệu luôn di chuyển ở tốc độ liên kết USB -- nhưng trên cổng USB của camera, hãy tránh 921.600 và 12.000.000, vì chúng chuyển camera từ REPL sang giao thức gỡ lỗi của IDE.

  • TCP -- kết nối đến máy chủ tại host và cổng được chọn, hoặc lắng nghe trên một cổng được chọn.

  • UDP -- cùng hai vai trò đó, qua UDP.

IDE lưu nhớ mười cấu hình cuối cùng và liệt kê chúng trong submenu Open Terminal để mở lại bằng một cú nhấp; Clear Menu sẽ xóa chúng.

Không giống như bảng chỉ xuất của cửa sổ chính, terminal độc lập hoàn toàn tương tác: nó là một REPL. Gõ tại dấu nhắc và Python thực thi trên camera đang kết nối từng dòng một, với lịch sử và hoàn thành tab được cung cấp bởi chính MicroPython. Thanh công cụ thêm các phím tắt tương đương cho các chuỗi điều khiển thông thường -- chạy tập lệnh hiện tại trong trình soạn thảo, dừng tập lệnh đang chạy và soft reset -- và cùng các điều khiển xóa, lưu và gói văn bản như bảng terminal chính.

Bộ đệm khung hình phía trên terminal cũng hoạt động trực tiếp. Khi camera đang kết nối phát trực tiếp các khung hình nén trong luồng -- nhúng trong cùng luồng với đầu ra print của nó -- terminal giải mã và hiển thị chúng, và các nút Record và Zoom hoạt động chính xác như trong cửa sổ chính. Sự kết hợp đó là giải pháp gỡ lỗi qua mạng của IDE: camera hiển thị REPL qua Wi-Fi sẽ có vòng lặp chỉnh sửa-chạy-xem trước đầy đủ mà không cần cáp USB.

13.1.10.1. Phát trực tiếp khung hình trong luồng

Mã hóa mà terminal hiểu là đơn giản: một byte 0xFE mở một khung hình, 0xFE thứ hai đóng nó, và mỗi byte tải trọng giữa chúng có bit cao nhất được đặt và mang sáu bit của ảnh nén -- ba byte ảnh trở thành bốn byte tải trọng. Văn bản thuần túy không bao giờ sử dụng các giá trị byte đó, vì vậy các khung hình và đầu ra print() chia sẻ luồng mà không xung đột: terminal hiển thị văn bản và hiển thị các khung hình.

Tập lệnh dưới đây chụp ảnh, chuyển đổi từng khung hình thành JPEG và in nó theo dạng đó. Quá trình đóng gói bit chạy qua ulab (không có toán tử dịch bit, vì vậy các phép dịch được viết dưới dạng nhân và chia), và đủ nhanh để theo kịp camera:

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())

Điều này hoạt động trong terminal độc lập vì việc in REPL phải chờ: camera chặn cho đến khi terminal đã nhận dữ liệu, vì vậy mỗi byte của khung hình đều đến, và JPEG di chuyển nhanh qua liên kết USB full-speed hoặc high-speed. Cùng tập lệnh hoạt động không thay đổi qua terminal TCP, đây là con đường gỡ lỗi qua mạng ở trên. Một nơi nó không hoạt động là kết nối gỡ lỗi chính của IDE, có kênh đầu ra tự đặt lại khi tràn thay vì chờ -- ở đó trình xem bộ đệm khung hình đã hiển thị các khung hình của camera theo cách gốc, vì vậy không có gì bị bỏ lỡ.