13.1.9. La vue Canaux#

Le tampon d’image montre ce que la caméra voit ; la vue Canaux montre ce que le script mesure et décide. Un script publie des valeurs nommées via le protocole de débogage – une température, un nombre de détections, la forme d’onde d’un microphone, une carte de profondeur temps de vol, ou une commande qu’il veut laisser l’utilisateur modifier – et l’IDE affiche chacune en direct sous forme de widget, de graphe ou de carte dans le volet sous le tampon d’image. Rien n’a besoin d’être dessiné sur l’image ni extrait du terminal. Côté caméra, ce sont quelques lignes avec protocol.CBORChannel ; côté IDE, c’est l’entrée Canaux du sélecteur du volet.

The Channels view showing a thermal camera script's controls channel: FPA and AUX temperature readouts with their unit, Measurement and High Temp toggles, Temp Min and Temp Max sliders, and H-Mirror and V-Flip toggles

Les commandes d’un script de caméra thermique : deux relevés de température, des bascules pour les modes de mesure et des curseurs pour la plage de température. Modifier l’une d’elles envoie la nouvelle valeur au script.#

La vue est organisée par canal. Chaque canal que le script enregistre devient une section avec le nom du canal pour titre, et chaque enregistrement du canal devient une ligne en dessous, dans l’ordre où le script les a ajoutés. Lorsque le script enregistre un canal ou change la forme de l’un d’eux, la vue se reconstruit ; lorsque le script s’arrête, les dernières valeurs restent à l’écran, avec les commandes désactivées, jusqu’au démarrage du script suivant.

13.1.9.1. Widgets#

Les relevés et les commandes prennent les formes attendues. Un label est une valeur en lecture seule avec son unité ; un enregistrement text est un bloc de texte enrichi statique pour les titres et les explications. Les types modifiables renvoient leur nouvelle valeur au script dès que vous la changez, où le rappel on_write du script reçoit le nom de l’enregistrement et la valeur : un toggle est un interrupteur, un slider et un spinbox fixent un nombre dans la plage et le pas du script (la spin box pour une saisie précise), les boutons radio et un select choisissent l’une des options du script, un lineedit est un champ de texte libre, et un pushbutton déclenche une action momentanée. La vue garde votre modification à l’écran plutôt que de la ramener à la dernière valeur publiée par la caméra pendant que l’écriture est en cours.

Côté script, l’ensemble est un protocol.CBORChannel avec un add par widget et un rappel pour les écritures:

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)

Exécutez-le et basculez le volet sur Canaux : une section nommée controls apparaît avec les cinq widgets, et déplacer le curseur imprime dans le terminal. Les autres types de widget – spinbox, radio, lineedit, text – sont un add de plus chacun ; le chapitre sur le protocole hôte les passe tous en revue.

13.1.9.2. Graphes de formes d’onde#

Un enregistrement waveform est un bloc d’échantillons entrelacés avec une fréquence d’échantillonnage – de l’audio, les axes d’un accéléromètre, une trace d’ADC – et la vue le trace sous forme de graphe défilant, une série par axe, nommée par le script. Les commandes du graphe se trouvent dans sa barre d’outils et sur le tracé lui-même :

  • Faites glisser pour un panoramique et utilisez la molette pour zoomer ; double-cliquez pour revenir au suivi du bord en direct. Historique définit la quantité de données passées conservées pour que vous puissiez y remonter.

  • Échelle auto ajuste l’axe vertical aux données ; désactivé, l’axe est la plage déclarée par le script.

  • Cliquez avec le bouton droit sur le tracé pour déposer un marqueur et lire l’heure et la valeur exactes d’un échantillon, ou pour définir un niveau de déclenchement. Avec un Déclenchement armé, le graphe reste immobile jusqu’à ce que le signal franchisse le niveau sur un front montant ou descendant – la méthode de l’oscilloscope pour attraper un transitoire – et Réarmer attend le suivant.

  • Spectre bascule le graphe vers un tracé fréquentiel des mêmes données, avec un choix de fenêtre (Hann, Hamming, Blackman, rectangulaire), Moyennage et Maintien des pics d’une trame à l’autre, et un axe Fréquence log. Le relevé sous le tracé nomme la fréquence de crête et son niveau.

  • Pause fige le graphe sans affecter un enregistrement ; Stats ajoute une ligne min / max / RMS ; et le menu contextuel enregistre le tracé en image.

The Channels view with two waveform records scrolling live: a 16 kHz microphone trace and a three-series accelerometer trace with its X, Y, and Z legend, each with its Record, Spectrum, Pause, and Stats buttons

Deux enregistrements de forme d’onde défilant en direct : une trace de microphone et une trace d’IMU à trois séries.#

Un champ waveform prend la fréquence d’échantillonnage et, pour plusieurs signaux à la fois, le nombre de series entrelacées et leurs noms ; chaque mise à jour est constituée des octets bruts d’un array d’échantillons dans le typecode du champ:

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. Cartes de profondeur#

Un enregistrement depth est une grille de distances – les trames que produit un capteur temps de vol – et la vue le dessine comme une carte en fausses couleurs agrandie à la hauteur du graphe. La barre d’outils choisit le rendu : la palette (les palettes Profondeur, Arc-en-ciel et Ironbow propres à la caméra, plus des palettes claire et sombre pour les caméras à événements), le filtre de mise à l’échelle qui agrandit la petite grille du capteur (bicubique pour une surface lisse, bilinéaire, ou plus proche voisin pour un bloc par pixel du capteur), et le mappage tonal qui transforme la distance en couleur : Plage du script utilise la plage déclarée par le script, Plage auto étire les couleurs sur les distances réellement présentes dans chaque trame (en ignorant les quelques pour cent extrêmes), et Égaliser les répartit sur la distribution de la trame pour qu’une scène plate montre encore ses détails. L’en-tête indique la taille de la carte, la plage déclarée et le minimum, le maximum et la moyenne de la trame ; survoler la carte relève la distance sous le curseur, et Enregistrer l’image écrit la carte rendue dans un PNG.

The Channels view showing an 8 x 8 time-of-flight depth map scaled up smoothly with the Depth palette, the palette, scaling, and tone-mapping selectors in its toolbar, and the header reporting the size, declared range, and the frame's minimum, maximum, and mean

Une carte de profondeur temps de vol d’une main devant le capteur, avec les sélecteurs de palette, de mise à l’échelle et de mappage tonal dans la barre d’outils.#

Un champ depth déclare la taille de sa grille et sa plage ; chaque mise à jour est la grille sous forme de flottants 32 bits compactés, ce que produit le lecteur du module 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. Enregistrement#

Chaque graphe et chaque carte a un bouton Enregistrer, et un canal qui en compte plusieurs a une barre Tout enregistrer qui les lance ensemble. L’enregistrement écrit les données à mesure qu’elles arrivent – pas le rendu – dans un fichier dont le format suit l’extension que vous choisissez dans la boîte de dialogue d’enregistrement : CSV pour les tableurs et les outils de tracé, WAV pour les formes d’onde audio mono-canal, des tableaux NumPy .npy pour Python, et Edge Impulse JSON ou CBOR pour un envoi direct dans un projet Edge Impulse comme données d’entraînement, avec une étiquette facultative qui nomme les fichiers. Seuls les formats capables de contenir les données d’un enregistrement sont proposés ; une carte de profondeur, par exemple, ne peut pas être un fichier WAV. Une longue capture est découpée en parties numérotées pour qu’aucun fichier ne devienne encombrant, et un enregistrement survit à la réinscription de ses canaux par le script. Le relevé à côté du bouton suit le nombre d’échantillons écrits et la taille du fichier.

L’intervalle Interrogation des canaux du volet, dans la section protocole des préférences, définit la fréquence à laquelle l’IDE demande de nouvelles données de canal à la caméra ; la valeur par défaut convient aux scripts qui publient quelques fois par seconde, et un script diffusant de l’audio gagne à un intervalle plus court.

Voir aussi

protocol.CBORChannel pour le côté script – les types d’enregistrement, leurs arguments et le rappel on_write – et les exemples 12-Protocol sous File → Examples pour des scripts fonctionnels qui publient des relevés, des commandes et une carte de profondeur.