13.1.9. Die Kanäle-Ansicht#
Der Framebuffer zeigt, was die Kamera sieht; die Kanäle-Ansicht zeigt, was das Skript misst und entscheidet. Ein Skript veröffentlicht benannte Werte über das Debug-Protokoll – eine Temperatur, eine Erkennungsanzahl, eine Mikrofon-Wellenform, eine Time-of-Flight-Tiefenkarte oder ein Steuerelement, das der Benutzer ändern können soll –, und die IDE stellt jeden davon live als Widget, Diagramm oder Karte im Bereich unter dem Framebuffer dar. Nichts muss auf das Bild gezeichnet oder aus dem Terminal herausgelesen werden. Auf der Kameraseite sind es ein paar Zeilen mit protocol.CBORChannel; auf der IDE-Seite ist es der Eintrag Kanäle der Bereichsauswahl.

Die Steuerelemente eines Wärmebildkamera-Skripts: zwei Temperaturanzeigen, Schalter für die Messmodi und Schieberegler für den Temperaturbereich. Jede Änderung sendet den neuen Wert an das Skript.#
Die Ansicht ist nach Kanälen gegliedert. Jeder Kanal, den das Skript registriert, wird zu einem Abschnitt mit dem Kanalnamen als Überschrift, und jeder Record im Kanal wird zu einer Zeile darunter, in der Reihenfolge, in der das Skript sie hinzugefügt hat. Wenn das Skript einen Kanal registriert oder die Form eines Kanals ändert, baut sich die Ansicht neu auf; wenn das Skript stoppt, bleiben die letzten Werte mit deaktivierten Steuerelementen auf dem Bildschirm, bis das nächste Skript startet.
13.1.9.1. Widgets#
Anzeigen und Steuerelemente nehmen die naheliegenden Formen an. Ein label ist ein schreibgeschützter Wert mit seiner Einheit; ein text-Record ist ein Block statischen Rich Texts für Überschriften und Erklärungen. Die beschreibbaren Arten senden ihren neuen Wert in dem Moment an das Skript zurück, in dem Sie ihn ändern, wo der on_write-Callback des Skripts den Record-Namen und den Wert empfängt: ein toggle ist ein Schalter, ein slider und eine spinbox stellen eine Zahl innerhalb von Bereich und Schrittweite des Skripts ein (das Drehfeld für präzise Eingabe), radio-Buttons und ein select wählen eine der Optionen des Skripts, ein lineedit ist ein Freitextfeld, und ein pushbutton löst eine einmalige Aktion aus. Die Ansicht behält Ihre Eingabe auf dem Bildschirm, statt sie auf den zuletzt von der Kamera veröffentlichten Wert zurückspringen zu lassen, während der Schreibvorgang unterwegs ist.
Auf der Skriptseite ist der ganze Satz ein protocol.CBORChannel mit einem add pro Widget und einem Callback für die Schreibvorgänge:
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)
Führen Sie es aus und schalten Sie den Bereich auf Kanäle um: Ein Abschnitt namens controls erscheint mit den fünf Widgets, und das Bewegen des Schiebereglers gibt im Terminal etwas aus. Die anderen Widget-Typen – spinbox, radio, lineedit, text – sind je ein weiteres add; das Kapitel zum Host-Protokoll geht sie alle durch.
13.1.9.2. Wellenformdiagramme#
Ein Wellenform-Record ist ein Block verschachtelter Samples mit einer Abtastrate – Audio, Beschleunigungsachsen, eine ADC-Spur –, und die Ansicht zeichnet ihn als laufendes Diagramm, eine Reihe pro Achse, benannt vom Skript. Die Diagrammsteuerung sitzt in seiner Symbolleiste und auf dem Plot selbst:
Ziehen Sie zum Verschieben und scrollen Sie zum Zoomen; ein Doppelklick kehrt zum Verfolgen des Live-Rands zurück. Verlauf legt fest, wie viele vergangene Daten behalten werden, damit Sie darin zurückblättern können.
Auto-Skalierung passt die vertikale Achse an die Daten an; ausgeschaltet ist die Achse der vom Skript deklarierte Bereich.
Klicken Sie mit der rechten Maustaste auf den Plot, um einen Marker zu setzen und die exakte Zeit und den Wert eines Samples abzulesen, oder um einen Trigger-Pegel festzulegen. Mit einem scharfgeschalteten Trigger hält das Diagramm still, bis das Signal den Pegel auf einer steigenden oder fallenden Flanke kreuzt – die Oszilloskop-Methode, einen Transienten einzufangen –, und Neu scharfschalten wartet auf den nächsten.
Spektrum schaltet das Diagramm auf eine Frequenzdarstellung derselben Daten um, mit wählbarem Fenster (Hann, Hamming, Blackman, Rechteck), Mittelung und Spitzenwert halten über Frames hinweg sowie einer Achse mit Log. Frequenz. Die Anzeige unter dem Plot nennt die Spitzenfrequenz und ihren Pegel.
Pause friert das Diagramm ein, ohne eine Aufzeichnung zu beeinflussen; Statistik fügt eine Zeile mit Min / Max / RMS hinzu; und das Kontextmenü speichert den Plot als Bild.

Zwei live laufende Wellenform-Records: eine Mikrofonspur und eine dreireihige IMU-Spur.#
Ein Wellenformfeld nimmt die Abtastrate und, für mehrere Signale auf einmal, die Anzahl der verschachtelten series und ihre Namen entgegen; jede Aktualisierung besteht aus den rohen Bytes eines array aus Samples im typecode des Feldes:
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. Tiefenkarten#
Ein Tiefen-Record ist ein Raster aus Entfernungen – die Frames, die ein Time-of-Flight-Sensor erzeugt –, und die Ansicht zeichnet ihn als Falschfarbenkarte, hochskaliert auf die Diagrammhöhe. Die Symbolleiste bestimmt die Darstellung: die Palette (die kameraeigenen Paletten Depth, Rainbow und Ironbow sowie helle und dunkle Paletten für Event-Kameras), den Skalierungsfilter, der das kleine Sensorraster vergrößert (bikubisch für eine glatte Oberfläche, bilinear oder Nächster Nachbar für einen Block pro Sensorpixel), und das Tone-Mapping, das Entfernung in Farbe umsetzt: Skript-Bereich verwendet den vom Skript deklarierten Bereich, Auto-Bereich spannt die Farben über die in jedem Frame tatsächlich vorhandenen Entfernungen (unter Ausschluss der wenigen Prozent Ausreißer), und Angleichen verteilt sie über die Verteilung des Frames, sodass eine flache Szene trotzdem ihre Details zeigt. Die Kopfzeile meldet die Größe der Karte, den deklarierten Bereich sowie Minimum, Maximum und Mittelwert des Frames; beim Überfahren der Karte wird die Entfernung unter dem Cursor angezeigt, und Bild speichern schreibt die gerenderte Karte in eine PNG-Datei.

Eine Time-of-Flight-Tiefenkarte einer Hand vor dem Sensor, mit den Auswahlschaltern für Palette, Skalierung und Tone-Mapping in der Symbolleiste.#
Ein Tiefenfeld deklariert seine Rastergröße und seinen Bereich; jede Aktualisierung ist das Raster als gepackte 32-Bit-Floats, also genau das, was der Reader des tof-Moduls erzeugt:
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. Aufzeichnung#
Jedes Diagramm und jede Karte hat eine Schaltfläche Aufnehmen, und ein Kanal mit mehr als einem davon hat eine Leiste Alle aufzeichnen, die sie gemeinsam startet. Die Aufzeichnung schreibt die Daten, wie sie eintreffen – nicht die Darstellung –, in eine Datei, deren Format der Erweiterung folgt, die Sie im Speicherdialog wählen: CSV für Tabellenkalkulationen und Plot-Werkzeuge, WAV für einkanalige Audio-Wellenformen, NumPy-.npy-Arrays für Python und Edge Impulse JSON oder CBOR zum direkten Hochladen in ein Edge-Impulse-Projekt als Trainingsdaten, mit einem optionalen Label, das die Dateien benennt. Es werden nur die Formate angeboten, die die Daten eines Records aufnehmen können; eine Tiefenkarte etwa kann keine WAV-Datei sein. Eine lange Aufnahme wird in nummerierte Teile aufgeteilt, damit keine einzelne Datei unhandlich wird, und eine Aufzeichnung übersteht es, wenn das Skript seine Kanäle neu registriert. Die Anzeige neben der Schaltfläche verfolgt, wie viele Samples geschrieben wurden, und die Dateigröße.
Das Intervall Channel Polling des Bereichs, im Protokollabschnitt der Einstellungen, legt fest, wie oft die IDE die Kamera nach neuen Kanaldaten fragt; der Standardwert passt zu Skripten, die einige Male pro Sekunde veröffentlichen, und ein Skript, das Audio streamt, profitiert von einem kürzeren Intervall.
Siehe auch
protocol.CBORChannel für die Skriptseite – die Record-Typen, ihre Argumente und der on_write-Callback – sowie die 12-Protocol-Beispiele unter File → Examples für funktionierende Skripte, die Anzeigen, Steuerelemente und eine Tiefenkarte veröffentlichen.