13.3.1.6. API 參考

openmv 套件的公開介面是用於與相機通訊的 Camera 類別,以及用於處理通訊協定錯誤的 OMVException 階層。兩者皆記錄於本頁。

13.3.1.6.1. Camera 類別

class openmv.Camera(port: str, *, baudrate: int = 921600, crc: bool = True, seq: bool = True, ack: bool = True, events: bool = True, timeout: float = 1.0, max_retry: int = 3, max_payload: int = 4096, drop_rate: float = 0.0)

透過 USB 序列埠連接 OpenMV 相機的主機端代理。

參數:
  • port -- 序列裝置路徑。在 Linux 上,USB CDC 為 /dev/ttyACMx,USB 轉 UART 橋接器為 /dev/ttyUSBx。在 macOS 上為 /dev/tty.usbmodem.../dev/cu.usbmodem...。在 Windows 上為 COMx

  • baudrate -- 序列鮑率。透過 USB 連線時,921600 是將相機從 MicroPython REPL 切換到 OpenMV 通訊協定的神奇值——在 USB 連結上使用任何其他值都會讓相機停留在 REPL 模式,因此必須使用預設值。透過 UART 連結時,此值為實際的線路鮑率,可在兩端自由設定。

  • crc -- 對每個封包啟用 CRC 驗證。

  • seq -- 啟用每個封包的序號。

  • ack -- 要求封包確認。

  • events -- 啟用來自相機的事件通知。

  • timeout -- 每次操作的逾時秒數。

  • max_retry -- 封包失敗時引發例外前的重試次數。

  • max_payload -- 協商後的最大酬載大小(位元組)。相機可能會向下協商。

  • drop_rate -- 僅供測試使用的丟棄封包機率,範圍為 [0.0, 1.0]。正式環境請保持為 0.0

此類別支援情境管理器協定;with Camera(port) as cam: 會在進入時呼叫 connect(),在離開時呼叫 disconnect()

13.3.1.6.2. 連線

Camera.connect() None

開啟序列埠並執行通訊協定交握。快取狀態(通道清單、系統資訊、版本資訊)會作為副作用一併填入。由情境管理器自動呼叫。

Camera.disconnect() None

關閉序列埠並釋放傳輸層。情境管理器離開時會自動呼叫。

Camera.is_connected() bool
回傳:

序列埠開啟時回傳 True

Camera.reset() None

重置相機。由於相機會重新開機,連線將會中斷。

Camera.boot() None

讓相機跳轉進入其 bootloader。由於相機會重新開機,連線將會中斷。

Camera.update_capabilities() None

與相機重新協商通訊協定能力(CRC、序號檢查、ACK、事件、最大酬載)。相機會回報其可處理的最大酬載;主機的請求會被截限至該值,並將協商後的設定推回。由 connect() 自動呼叫——除非需要在現有連線上以建構子旗標重新協商,否則沒有理由在使用者程式碼中呼叫它。

Camera.poll_events() None

執行傳輸層的接收路徑一次,以在不傳送指令的情況下消耗來自相機的任何待處理事件。對於數分鐘內沒有其他 I/O、並希望及時呈現通道註冊事件的長時間執行程式相當有用。

13.3.1.6.3. 指令碼執行

Camera.exec(script: str) None

script(Python 原始碼字串)上傳到相機的 stdin 緩衝區並開始執行。

參數:

script -- 要執行的 MicroPython 原始碼。

Camera.stop() None

中斷執行中的指令碼。等同於 IDE 的「停止」按鈕。

Camera.read_stdout() str | None

讀取執行中的指令碼自上次呼叫以來寫入 stdout 的所有位元組。

回傳:

解碼後的輸出字串,若無資料等待則為 None

13.3.1.6.4. 串流

Camera.streaming(enable: bool, raw: bool = False, resolution: tuple[int, int] | None = None) None

開啟或關閉影格串流,並選擇傳輸線上的格式。

參數:
  • enable -- True 啟用串流,False 停用串流。

  • raw -- 為 False(預設)時,相機會先對每個影格進行 JPEG 壓縮再放入串流通道,並由 read_frame() 在主機端解壓縮。為 True 時,相機會以未壓縮方式傳送擷取的像素緩衝區——這是不具硬體 JPEG 支援的相機的正確選擇,因為軟體壓縮是迴圈中最慢的步驟。

  • resolution -- 相機在傳送前將每個原始影格縮放到的目標 (width, height),因為未壓縮影格遠大於 JPEG 壓縮的影格。當 raw=True 時為必填;否則會被忽略。

Camera.read_frame() dict | None

從串流通道讀取最新的影格。

回傳:

若無影格等待則為 None,否則為一個字典,包含下列鍵值:widthint,像素)、heightint,像素)、formatint,相機宣告的像素格式識別碼)、depthint,JPEG/PNG 影格的壓縮影像大小(位元組);未壓縮格式不使用)、databytes,長度為 width * height * 3 的 RGB888),以及 raw_sizeint,相機在解碼前透過 USB 傳送的位元組數)。

13.3.1.6.5. 自訂通道

Camera.has_channel(name: str) bool
回傳:

若相機上存在以 name 註冊的通道則為 True

Camera.channel_size(name: str) int
回傳:

具名通道目前可用的位元組數,當通道為空或不存在時為 0

Camera.channel_read(name: str, size: int | None = None) bytes | None

從自訂通道讀取。

參數:
  • name -- 由相機端指令碼註冊的通道名稱。

  • size -- 要讀取的位元組數,或傳入 None 以讀取所有可用資料。

回傳:

讀取的位元組,若通道不存在則為 None

Camera.channel_write(name: str, data: bytes) bool

data 寫入自訂通道。超過酬載大小的寫入會自動分割成多個封包。

參數:
  • name -- 由相機端指令碼註冊的通道名稱。

  • data -- 要傳送的類位元組酬載。

回傳:

若通道存在且寫入已送出則為 True,否則為 False

Camera.read_status() dict[str, bool]

輪詢每個已註冊的通道。

回傳:

將通道名稱對應到布林值「資料已準備好可讀取」的字典。

Camera.update_channels() None

從相機重新整理快取的通道清單。在通道註冊事件抵達後,下次執行依名稱查詢通道時會自動執行;想要立即得知新註冊通道的應用程式可直接呼叫此方法。

Camera.get_channel(name: str | None = None, channel_id: int | None = None) int | str | None

依名稱(回傳其數字 ID)或依 ID(回傳其名稱)查詢通道。若有待處理的通道註冊事件,會先透過 update_channels() 重新整理通道快取。

參數:
  • name -- 要解析為 ID 的通道名稱。

  • channel_id -- 要解析為名稱的通道 ID。

回傳:

對應的 ID 或名稱,若通道不存在則為 Nonenamechannel_id 必須提供其一。

13.3.1.6.6. 裝置自我檢視

Camera.version() dict

回傳相機的通訊協定、bootloader 與韌體版本三元組。在 connect() 之後快取。每個三元組為 int(major, minor, patch) 元組:

  • protocol_version——相機實作的 OpenMV 線路通訊協定版本。

  • bootloader_version——常駐於快閃記憶體中的 bootloader 映像檔。

  • firmware_version——目前執行中的 MicroPython 韌體。

Camera.system_info() dict

回傳相機的硬體能力與記憶體資訊。在 connect() 之後快取。回傳的字典鍵值分為四組。

識別

  • cpu_id——32 位元 CPU 識別碼。

  • device_id——由三個 32 位元字組成的元組,即燒錄於晶片中的唯一裝置序號。

  • chip_id——由三個 32 位元字組成的元組,每個連接到相機的影像感測器各一筆。

  • usb_vid——USB 廠商 ID。

  • usb_pid——USB 產品 ID。

記憶體大小(皆以 KB 為單位)

  • flash_size_kb——內部快閃記憶體總量。

  • ram_size_kb——RAM 總量。

  • framebuffer_size_kb——保留供影像擷取使用的 RAM。

  • stream_buffer_size_kb——保留供將影格傳送至主機的串流通道使用的 RAM。

能力旗標(每項功能一個布林值,皆命名為 <feature>_present

  • gpu_present——圖形處理單元。

  • npu_present——神經處理單元。

  • isp_present——影像訊號處理器。

  • venc_present——視訊編碼器。

  • jpeg_present——JPEG 硬體編碼器。

  • dram_present——外部 DRAM。

  • crc_present——CRC 加速器。

  • pmu_present——效能監控單元。

  • wifi_present——Wi-Fi 無線電。

  • bt_present——藍牙無線電。

  • sd_present——SD 卡插槽。

  • eth_present——乙太網路 PHY。

  • multicore_present——多個 CPU 核心。

其他

  • usb_highspeed——布林值,當 USB 以高速模式(USB 2.0 HS,480 Mbps)列舉時為 True

  • pmu_eventcnt——可用的 PMU 事件計數器數量;無 PMU 時為 0

Camera.print_system_info() None

將格式化的系統資訊區塊以 INFO 等級記錄到 logging。CLI 在連線時會使用此方法。

13.3.1.6.7. 診斷

Camera.host_stats() dict
回傳:

主機端追蹤的傳輸層計數器:sentreceivedchecksumsequence

Camera.device_stats() dict
回傳:

相機端追蹤的傳輸層計數器:sentreceivedchecksumsequenceretransmittransportsent_eventsmax_ack_queue_depth

13.3.1.6.8. 分析器

分析器會回報已插樁的韌體模組——目前為 imagemlulab——的每個函式呼叫次數,以及最小/最大/總執行時間。函式的進入與離開在編譯時被攔截;執行階段在每次進出時對單調遞增的微秒計數器取樣,依函式累加結果,並透過 profile 通道將此表格揭露給主機。

只有在傳遞 PROFILE_ENABLE=1make 時,分析器才會內建於韌體中。標準韌體映像檔不包含它——建置時為被追蹤模組加入的 -finstrument-functions 旗標具有不可忽視的執行階段額外負擔,因此分析建置是針對需要它的特定除錯工作從原始碼產生的。當韌體未以該旗標建置時,profile 通道不會註冊,且本頁的每個分析器方法都會靜默回傳而不執行任何操作。

Arm 效能監控單元(PMU)是 Cortex-M55 的硬體計數器區塊——一組可設定的小型計數器,可在不拖慢受測程式碼的情況下追蹤週期數、快取命中與未命中、分支行為,以及其他架構定義的事件。在具備 PMU 的相機上——AE3 與 N6,這兩款是 OpenMV 產品線中環繞 M55 打造的相機——分析器會在取得計時資料的同時對這些計數器取樣,事件總計則出現在每個函式記錄中。不具 PMU 的相機仍會產生計時記錄;事件欄位會回傳為零,且 profiler_event() 為無操作。

Camera.profiler_mode(exclusive: bool = False) None

在包含式與排除式計時之間切換。包含式計時將被呼叫者的時間計入呼叫者;排除式計時則不會。

參數:

exclusive -- True 選擇排除式計時,False 選擇包含式計時。

Camera.profiler_reset(config: list | None = None) None

清除所有分析計數器。config=None 也會還原預設的 PMU 事件指派。

參數:

config -- 保留供未來的個別計數器設定覆寫使用。傳入 None 以保留預設值。

Camera.profiler_event(counter_num: int, event_id: int) None

將其中一個 PMU 計數器插槽繫結到特定的硬體事件。

參數:
  • counter_num -- 計數器索引。

  • event_id -- 架構定義的事件識別碼。

Camera.read_profile() list[dict] | None

回傳自上次重置以來收集的每函式分析記錄。每筆記錄為一個字典,包含 addresscallercall_countmin_ticksmax_tickstotal_tickstotal_cycles,以及一個大小符合相機 pmu_eventcntevents 元組。

回傳:

記錄字典的清單,若分析通道不可用或尚未收集到資料則為 None

13.3.1.6.9. 子類別化與通道內部機制

上述記錄的方法涵蓋了套件的所有常見用法。少數模式——處理主機想要回應的相機端事件、為多步驟交換鎖定通道、與承載結構化資料而非位元組串流的通道通訊,或驅動通道專屬的控制指令——需要 Camera 以底線前綴保留的方法。這些名稱依慣例為私有(Python 並不會對它們進行名稱重整),需要使用它們的應用程式預期應子類別化 Camera 或直接呼叫這些方法。

子類別化以回應事件。 相機發出的每個事件都會透過 Camera._handle_event() 抵達。子類別化 Camera 並覆寫該方法是應用程式回應其相機端指令碼所引發事件的方式;事件 頁面完整說明了此模式。

Camera._handle_event(channel_id: int, event: int) None

派發來自相機的一個事件。每當事件封包抵達時由傳輸層呼叫。在子類別中覆寫以加入應用程式專屬的處理;呼叫 super()._handle_event(...) 以保留預設行為(在 CHANNEL_REGISTERED 時重新整理通道清單、在 stream 通道上追蹤影格就緒狀態、stdin 通道的啟動/停止記錄)。

參數:
  • channel_id -- 系統事件為 0,否則為已註冊的通道 ID。

  • event -- 事件識別碼;系統事件的值來自 EventType 列舉,通道事件的值則來自相機端通道後端所選擇的值。

若子類別加入自己的通訊協定方法,應以 retry_if_failed() 加以裝飾,使它們繼承本頁每個出貨方法所具備的相同重新同步與重試行為。

static Camera.retry_if_failed(func)

裝飾器。包裝實例方法,使其在傳輸層引發 ResyncException 時重試一次。任何呼叫 _send_cmd_wait_resp()(直接呼叫或透過某個 _channel_* 包裝器)的方法都應帶有此裝飾器:

class MyCamera(Camera):
    @Camera.retry_if_failed
    def my_custom_command(self, payload):
        return self._send_cmd_wait_resp(Opcode.MY_CMD,
                                        0, payload)

通道鎖定可確保通道狀態不會在兩個相關操作之間改變(例如在持續附加資料的通道上,_channel_size() 之後接著 _channel_read())。read_frame()read_profile() 在內部使用此機制;以多步驟存取驅動自訂通道的應用程式也應如此。

Camera._channel_lock(channel_id: int) bool

取得通道的互斥鎖。對同一通道的其他主機操作會封鎖,直到鎖被釋放。

參數:

channel_id -- 數字通道 ID,通常以 get_channel() 解析。

回傳:

鎖被授予時為 True

Camera._channel_unlock(channel_id: int) bool

釋放先前以 _channel_lock() 取得的鎖。務必與鎖定呼叫成對使用;使用 tryfinally 確保即使中間的讀取引發例外,解鎖仍會發生。

參數:

channel_id -- 數字通道 ID,通常以 get_channel() 解析。

形狀化通道承載結構化記錄而非平坦的位元組串流。分析器通道是出貨的範例:其形狀為 (record_count, record_size),想知道有多少筆記錄等待的主機會讀取形狀而非位元組大小。

Camera._channel_shape(channel_id: int) tuple[int, ...]

讀取通道的形狀描述子。

參數:

channel_id -- 數字通道 ID,通常以 get_channel() 解析。

回傳:

描述通道配置的無號 32 位元整數元組。其意義為通道專屬。

通道專屬的控制指令——啟動、停止、重置、設定——皆搭載於單一作業碼(CHANNEL_IOCTL)之上,並帶有通道專屬的指令編號與選用的 struct.pack 酬載。像 stop()exec()streaming() 這類出貨方法都是針對 stdinstream 通道的 _channel_ioctl() 呼叫的輕薄包裝;定義自己 ioctl 選單的自訂相機端通道也以相同方式驅動。

Camera._channel_ioctl(channel_id: int, cmd: int, fmt: str | None = None, *args) bytes | None

對通道發出 ioctl 指令。

參數:
  • channel_id -- 數字通道 ID,通常以 get_channel() 解析。

  • cmd -- 由相機端通道後端定義的指令編號。

  • fmt -- 引數元組的選用 struct 格式字串。對不接受引數的 ioctl 傳入 None

  • args -- 符合 fmt 的值。

回傳:

通道回傳的任何酬載,或 None

公開通道方法的依 ID 位元組串流變體會略過名稱到 ID 的查詢,並接受明確的位元組 offset——對於從大型緩衝區中間讀取一段資料(例如 profile 通道記錄)相當有用。

Camera._channel_size(channel_id: int) int
參數:

channel_id -- 數字通道 ID,通常以 get_channel() 解析。

回傳:

通道上目前可用的位元組數。

Camera._channel_read(channel_id: int, offset: int, length: int) bytes

offset 開始讀取 length 個位元組。多封包讀取會自動重組。

參數:
  • channel_id -- 數字通道 ID,通常以 get_channel() 解析。

  • offset -- 開始讀取的位元組偏移量。

  • length -- 要讀取的位元組數。

Camera._channel_write(channel_id: int, data: bytes, offset: int = 0) None

在給定的 offset 寫入 data。多封包寫入會自動分割成多個封包。

參數:
  • channel_id -- 數字通道 ID,通常以 get_channel() 解析。

  • data -- 要寫入的類位元組酬載。

  • offset -- 開始寫入的位元組偏移量。

通訊協定原語是此類別所揭露的最低層級——上述所有功能最終都建構於其上的原始送出指令、擷取原始通道清單,以及手動重新同步項目。當應用程式要送出類別尚未包裝的作業碼,或在子類別中實作自訂復原時,便會用到它們。

Camera._send_cmd_wait_resp(opcode: int, channel: int = 0, data: bytes = b'') bytes | None

送出通訊協定指令並等待相機的回應。本節中所有其他方法皆建構於此原語之上。

參數:
  • opcode -- 指令編號。出貨的 Opcode 列舉列出了韌體隨附的代碼,但此參數只是一個整數——自訂韌體建置可定義並回應自己的代碼。

  • channel -- 通道 ID,系統指令則為 0

  • data -- 指令專屬的酬載。

回傳:

回應酬載,對於像 Opcode.SYS_RESETOpcode.SYS_BOOT 這類會中斷連線的指令則為 None

Camera._channel_list() dict

從相機擷取目前的通道清單,但不觸及 update_channels() 所填入的快取 channels_by_idchannels_by_name 字典。對於想要直接檢視相機通道狀態的子類別相當有用。

回傳:

將通道 ID 對應到 {'name': str, 'flags': int} 的字典。

Camera._resync() None

從頭重新執行通訊協定交握。由 connect() 在初次連線時自動呼叫,並由每個從傳輸層捕捉到 OMVException 的公開方法呼叫。在子類別中實作自身復原迴圈的應用程式可在處理底層錯誤後直接呼叫此方法。

13.3.1.6.10. 例外

exception openmv.OMVException

所有通訊協定層級錯誤的基底類別。下列三個子類別皆繼承自它,因此單一個 except OMVException 即可涵蓋整個錯誤範圍。

exception openmv.TimeoutException

相機未在設定的逾時內回應。OMVException 的子類別。

exception openmv.ChecksumException

封包的 CRC 不相符。在通訊協定耗盡其重試額度後引發。OMVException 的子類別。

exception openmv.SequenceException

重試後抵達的封包帶有非預期的序號。OMVException 的子類別。