13.1.9. La vista Canali#
Il frame buffer mostra ciò che la camera vede; la vista Canali mostra ciò che lo script misura e decide. Uno script pubblica valori con nome tramite il protocollo di debug – una temperatura, un conteggio di rilevamenti, la forma d’onda di un microfono, una mappa di profondità time-of-flight, o un controllo che vuole che l’utente possa modificare – e l’IDE visualizza ciascuno in tempo reale come widget, grafico o mappa nel pannello sotto il frame buffer. Nulla deve essere disegnato sull’immagine o estratto dal terminale. Sul lato camera sono poche righe con protocol.CBORChannel; sul lato IDE è la voce Canali del selettore del pannello.

I controlli dello script di una camera termica: due letture di temperatura, interruttori per le modalità di misura e cursori per l’intervallo di temperatura. Modificarne uno qualsiasi invia il nuovo valore allo script.#
La vista è organizzata per canale. Ogni canale che lo script registra diventa una sezione con il nome del canale come intestazione, e ogni record del canale diventa una riga sotto di essa, nell’ordine in cui lo script li ha aggiunti. Quando lo script registra un canale o ne cambia la forma, la vista si ricostruisce; quando lo script si ferma, gli ultimi valori restano sullo schermo, con i controlli disabilitati, finché non parte lo script successivo.
13.1.9.1. Widget#
Letture e controlli assumono le forme ovvie. Una label è un valore di sola lettura con la sua unità; un record text è un blocco di rich text statico per titoli e spiegazioni. I tipi scrivibili rimandano il nuovo valore allo script nel momento in cui lo modifichi, dove il callback on_write dello script riceve il nome e il valore del record: un toggle è un interruttore, uno slider e uno spinbox impostano un numero entro l’intervallo e il passo dello script (la casella numerica per l’inserimento preciso), i pulsanti radio e un select scelgono una delle opzioni dello script, un lineedit è un campo di testo libero, e un pushbutton attiva un’azione momentanea. La vista mantiene la tua modifica sullo schermo invece di riportarla all’ultimo valore pubblicato dalla camera mentre la scrittura è in corso.
Sul lato script l’intero insieme è un protocol.CBORChannel con un add per widget e un callback per le scritture:
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)
Eseguilo e passa il pannello a Canali: compare una sezione chiamata controls con i cinque widget, e muovendo il cursore si stampa qualcosa nel terminale. Gli altri tipi di widget – spinbox, radio, lineedit, text – sono un add in più ciascuno; il capitolo sul protocollo host li illustra tutti.
13.1.9.2. Grafici di forme d’onda#
Un record waveform è un blocco di campioni interlacciati con una frequenza di campionamento – audio, gli assi di un accelerometro, una traccia ADC – e la vista lo traccia come un grafico a scorrimento, una serie per asse, con i nomi dati dallo script. I controlli del grafico sono nella sua barra degli strumenti e sul grafico stesso:
Trascina per fare una panoramica e scorri per lo zoom; fai doppio clic per tornare a seguire il bordo in tempo reale. Cronologia imposta quanti dati passati vengono conservati, così puoi tornare indietro con la panoramica.
Scala automatica adatta l’asse verticale ai dati; disattivata, l’asse è l’intervallo dichiarato dallo script.
Fai clic con il tasto destro sul grafico per posizionare un marcatore e leggere il tempo e il valore esatti di un campione, o per impostare un livello di trigger. Con un Trigger armato il grafico resta fermo finché il segnale non attraversa il livello su un fronte di salita o di discesa – il modo in cui un oscilloscopio cattura un transitorio – e Riarma attende il successivo.
Spettro trasforma il grafico in un grafico in frequenza degli stessi dati, con una scelta di finestra (Hann, Hamming, Blackman, rettangolare), Media e Mantieni picco tra i frame, e un asse a Frequenza logaritmica. La lettura sotto il grafico indica la frequenza di picco e il suo livello.
Pausa congela il grafico senza influire su una registrazione; Stat. aggiunge una riga con minimo / massimo / RMS; e il menu del tasto destro salva il grafico come immagine.

Due record waveform che scorrono in tempo reale: una traccia di un microfono e una traccia IMU a tre serie.#
Un campo waveform prende la frequenza di campionamento e, per più segnali insieme, il numero di series interlacciate e i loro nomi; ogni aggiornamento è costituito dai byte grezzi di un array di campioni nel typecode del campo:
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. Mappe di profondità#
Un record depth è una griglia di distanze – i frame prodotti da un sensore time-of-flight – e la vista lo disegna come una mappa in falsi colori ingrandita all’altezza del grafico. La barra degli strumenti sceglie la resa: la palette (le palette Depth, Rainbow e Ironbow proprie della camera, più una palette chiara e una scura per le camere a eventi), il filtro di scalatura che ingrandisce la piccola griglia del sensore (bicubica per una superficie liscia, bilineare, o più vicino per un blocco per ogni pixel del sensore) e la mappatura dei toni che trasforma la distanza in colore: Intervallo script usa l’intervallo dichiarato dallo script, Intervallo auto distende i colori sulle distanze effettivamente presenti in ogni frame (ignorando la piccola percentuale di valori estremi) ed Equalizza li distribuisce sulla distribuzione del frame, così una scena piatta mostra comunque i suoi dettagli. L’intestazione riporta la dimensione della mappa, l’intervallo dichiarato e il minimo, il massimo e la media del frame; passando il mouse sulla mappa si legge la distanza sotto il cursore, e Salva immagine scrive la mappa renderizzata in un PNG.

Una mappa di profondità time-of-flight di una mano davanti al sensore, con i selettori di palette, scalatura e mappatura dei toni nella barra degli strumenti.#
Un campo depth dichiara la dimensione della griglia e l’intervallo; ogni aggiornamento è la griglia come float a 32 bit impacchettati, che è ciò che produce il lettore del modulo 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. Registrazione#
Ogni grafico e mappa ha un pulsante Registra, e un canale con più di uno di essi ha una barra Registra tutto che li avvia insieme. La registrazione scrive i dati man mano che arrivano – non la resa grafica – in un file il cui formato segue l’estensione che scegli nella finestra di salvataggio: CSV per fogli di calcolo e strumenti di grafici, WAV per forme d’onda audio a canale singolo, array NumPy .npy per Python, ed Edge Impulse JSON o CBOR per il caricamento diretto in un progetto Edge Impulse come dati di addestramento, con un’etichetta opzionale che dà il nome ai file. Vengono offerti solo i formati che possono contenere i dati di un record; una mappa di profondità, per esempio, non può essere un file WAV. Un’acquisizione lunga viene suddivisa in parti numerate così che nessun singolo file diventi ingombrante, e una registrazione sopravvive alla ri-registrazione dei canali da parte dello script. La lettura accanto al pulsante tiene traccia di quanti campioni sono stati scritti e della dimensione del file.
L’intervallo Polling dei canali del pannello, nella sezione del protocollo delle preferenze, imposta quanto spesso l’IDE chiede alla camera nuovi dati dei canali; il valore predefinito va bene per gli script che pubblicano poche volte al secondo, e uno script che trasmette audio beneficia di un intervallo più breve.
Vedi anche
protocol.CBORChannel per il lato script – i tipi di record, i loro argomenti e il callback on_write – e gli esempi 12-Protocol in File → Examples per script funzionanti che pubblicano letture, controlli e una mappa di profondità.