13.1.9. Channels 檢視#
影格緩衝區顯示相機看到什麼;Channels 檢視則顯示指令碼測量與決定了什麼。指令碼透過除錯協定發布具名的數值——溫度、偵測計數、麥克風波形、飛時測距深度圖,或它希望使用者能夠變更的控制項——IDE 會在影格緩衝區下方的窗格中,將每一項即時呈現為小工具、圖表或深度圖。不需要在影像上繪製任何東西,也不需要從終端機中剖析任何內容。在相機端,只需用 protocol.CBORChannel 寫幾行程式;在 IDE 端,則是 窗格選擇器 的 Channels 項目。

熱像儀指令碼的控制項:兩個溫度讀數、測量模式的切換開關,以及溫度範圍的滑桿。變更其中任何一項都會將新值傳送給指令碼。#
檢視依通道組織。指令碼註冊的每個通道都會成為一個以通道名稱為標題的區段,而通道中的每筆記錄都會成為其下的一列,順序依指令碼加入的順序。當指令碼註冊通道或變更通道的結構時,檢視會自行重建;當指令碼停止時,最後的數值會保留在畫面上,控制項則停用,直到下一個指令碼啟動為止。
13.1.9.1. 小工具#
讀數與控制項採用顯而易見的形式。label 是帶有單位的唯讀數值;text 記錄是一段靜態的 rich text,用於標題與說明。可寫入的種類會在你變更的那一刻將新值傳回指令碼,由指令碼的 on_write 回呼接收記錄名稱與數值:toggle 是一個開關,slider 與 spinbox 在指令碼的範圍與步進內設定一個數字(微調方塊供精確輸入),radio 按鈕與 select 從指令碼的選項中擇一,lineedit 是自由文字欄位,而 pushbutton 則觸發一次性的動作。在寫入進行期間,檢視會將你的編輯保留在畫面上,而不是把它彈回相機最後發布的數值。
在指令碼端,整組內容是一個 protocol.CBORChannel,每個小工具一個 add,再加上一個處理寫入的回呼:
import time
import protocol
from protocol import CBORChannel
def on_write(ch, name, value):
print(name, "=", value) # every change lands here
ch = CBORChannel(on_write=on_write)
ch.add("Status", type="label", value="starting")
ch.add("Enable", type="toggle", value=True)
ch.add("Threshold", type="slider", min=0, max=100,
step=1, value=50, unit="%")
ch.add("Mode", type="select",
options=["Idle", "Track", "Record"], value="Idle")
ch.add("Calibrate", type="pushbutton")
protocol.register(name="controls", backend=ch)
while True:
if ch["Enable"]: # read a control back
ch["Status"] = "threshold %d%%" % ch["Threshold"]
time.sleep_ms(100)
執行它並將窗格切換至 Channels:會出現一個名為 controls 的區段,包含五個小工具,而移動滑桿會在終端機中列印。其他小工具類型——spinbox、radio、lineedit、text——各只需多一個 add;主機協定章節 會逐一介紹它們。
13.1.9.2. 波形圖#
waveform(波形)記錄是一段具有取樣率的交錯取樣資料——音訊、加速度計軸、ADC 軌跡——檢視會將它繪製為捲動圖表,每個軸一條序列,名稱由指令碼指定。圖表的控制項位於其工具列與圖表本身上:
拖曳可平移,捲動可縮放;按兩下可回到跟隨即時邊緣。History 設定保留多少過去的資料,讓你可以向後平移瀏覽。
Auto Scale 會讓垂直軸符合資料範圍;關閉時,軸的範圍即為指令碼宣告的範圍。
在圖表上按右鍵可放置一個 marker(標記)以讀取某個取樣的精確時間與數值,或設定一個 trigger level(觸發位準)。Trigger 備妥後,圖表會保持靜止,直到訊號以上升或下降緣越過該位準為止——這是示波器捕捉暫態的方式——而 Re-arm 則等待下一次觸發。
Spectrum 會將圖表切換為同一資料的頻率圖,可選擇窗函數(Hann、Hamming、Blackman、矩形)、跨影格的 Averaging 與 Peak Hold,以及 Log Frequency 軸。圖表下方的讀數會標明峰值頻率及其位準。
Pause 會凍結圖表而不影響錄製;Stats 會加上一行最小/最大/RMS 值;右鍵選單則可將圖表儲存為影像。

兩個即時捲動的波形記錄:一條麥克風軌跡與一條三序列 IMU 軌跡。#
波形欄位接受取樣率,以及在同時傳送多個訊號時交錯的 series 數量與其名稱;每次更新都是以欄位 typecode 表示的 array 取樣原始位元組:
import math
import time
import protocol
from array import array
from protocol import CBORChannel
RATE, CHUNK = 1000, 100 # 1 kHz, 100 ms per update
ch = CBORChannel()
ch.add("IMU", type="waveform", sample_rate=RATE, series=3,
typecode="f", min=-2.0, max=2.0,
options=["X", "Y", "Z"], unit="g")
protocol.register(name="signals", backend=ch)
t = 0
while True:
block = array("f")
for i in range(CHUNK):
phase = 2 * math.pi * 2 * (t + i) / RATE
block.extend((math.sin(phase), math.cos(phase), 1.0))
ch["IMU"] = bytes(block) # interleaved X, Y, Z
t += CHUNK
time.sleep_ms(100)
13.1.9.3. 深度圖#
depth(深度)記錄是一個距離網格——飛時測距感測器所產生的影格——檢視會將它繪製為放大至圖表高度的偽色彩圖。工具列用來選擇呈現方式:palette(調色盤;相機自有的 Depth、Rainbow 與 Ironbow 調色盤,再加上供事件相機使用的淺色與深色調色盤)、放大小型感測器網格的 scaling filter(縮放濾鏡;bicubic 可得到平滑的表面、bilinear,或 nearest 讓每個感測器像素對應一個方塊),以及將距離轉換為色彩的 tone mapping(色調映射):Script Range 使用指令碼宣告的範圍,Auto Range 會將色彩拉伸至每張影格中實際存在的距離範圍(忽略離群的少數百分比),而 Equalize 則依影格的分布將色彩展開,使平坦的場景仍能顯現細節。標頭會回報深度圖的大小、宣告的範圍,以及影格的最小值、最大值與平均值;將滑鼠停留在圖上可讀出游標下的距離,Save Image 則會將呈現的圖寫入 PNG。

感測器前方一隻手的飛時測距深度圖,工具列中有調色盤、縮放與色調映射選擇器。#
深度欄位宣告其網格大小與範圍;每次更新都是以緊密排列的 32 位元浮點數表示的網格,這正是 tof 模組的讀取器所產生的資料:
import struct
import time
import tof
import protocol
from protocol import CBORChannel
tof.init()
ch = CBORChannel()
ch.add("depth", type="depth", width=tof.width(),
height=tof.height(), min=0, max=1000)
protocol.register(name="ToF", backend=ch)
while True:
try:
d, dmin, dmax = tof.read_depth(vflip=True, hmirror=True)
except RuntimeError:
continue
ch["depth"] = struct.pack("<%df" % len(d), *d)
time.sleep_ms(50)
13.1.9.4. 錄製#
每個圖表與深度圖都有一個 Record 按鈕,而擁有多個圖表的通道則有一個 Record All 列可一起啟動它們。錄製會在資料抵達時寫入資料本身——而非呈現結果——寫入的檔案格式依你在儲存對話框中選擇的副檔名而定:CSV 適用於試算表與繪圖工具,WAV 適用於單通道音訊波形,NumPy .npy 陣列適用於 Python,而 Edge Impulse JSON 或 CBOR 則可直接上傳至 Edge Impulse 專案作為訓練資料,並可選擇性加上用來為檔案命名的標籤。只會提供能容納該記錄資料的格式;例如深度圖就不能是 WAV 檔案。長時間的擷取會分割為編號的分段,因此不會有單一檔案變得過於龐大,而錄製也能在指令碼重新註冊其通道後繼續。按鈕旁的讀數會追蹤已寫入的取樣數與檔案大小。
窗格的 Channel Polling 間隔位於偏好設定的協定區段中,用來設定 IDE 向相機要求新通道資料的頻率;預設值適合每秒發布幾次的指令碼,而串流音訊的指令碼則會受益於較短的間隔。
也參考
protocol.CBORChannel 說明指令碼端——記錄類型、其引數與 on_write 回呼——而 File → Examples 下的 12-Protocol 範例則提供可發布讀數、控制項與深度圖的可運作指令碼。