13.1.9. มุมมอง Channels#

เฟรมบัฟเฟอร์แสดงสิ่งที่กล้อง เห็น; มุมมอง Channels แสดงสิ่งที่สคริปต์ วัดและตัดสินใจ สคริปต์เผยแพร่ค่าที่มีชื่อผ่านโปรโตคอลดีบัก -- อุณหภูมิ จำนวนการตรวจจับ รูปคลื่นไมโครโฟน แผนที่ความลึก time-of-flight หรือตัวควบคุมที่มันต้องการให้ผู้ใช้เปลี่ยนได้ -- และ IDE แสดงผลแต่ละค่าแบบสดเป็นวิดเจ็ต กราฟ หรือแผนที่ในแผงใต้เฟรมบัฟเฟอร์ ไม่ต้องวาดอะไรลงบนภาพหรือแยกวิเคราะห์จากเทอร์มินัล ฝั่งกล้องคือโค้ดไม่กี่บรรทัดด้วย protocol.CBORChannel; ฝั่ง IDE คือรายการ Channels ของ ตัวเลือกของแผง

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

ตัวควบคุมของสคริปต์กล้องความร้อน: ค่าอ่านอุณหภูมิสองค่า สวิตช์สลับสำหรับโหมดการวัด และแถบเลื่อนสำหรับช่วงอุณหภูมิ การเปลี่ยนค่าใดค่าหนึ่งจะส่งค่าใหม่ไปยังสคริปต์#

มุมมองจัดระเบียบตามแชนเนล แต่ละแชนเนลที่สคริปต์ลงทะเบียนจะกลายเป็นส่วนที่มีชื่อแชนเนลเป็นหัวข้อ และแต่ละเรคคอร์ดในแชนเนลจะกลายเป็นแถวใต้ส่วนนั้น ตามลำดับที่สคริปต์เพิ่มเข้ามา เมื่อสคริปต์ลงทะเบียนแชนเนลหรือเปลี่ยนรูปร่างของแชนเนล มุมมองจะสร้างตัวเองใหม่; เมื่อสคริปต์หยุด ค่าล่าสุดจะยังคงอยู่บนหน้าจอ โดยตัวควบคุมถูกปิดใช้งาน จนกว่าสคริปต์ถัดไปจะเริ่ม

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 เพิ่มบรรทัด min / max / RMS; และเมนูคลิกขวาบันทึกพล็อตเป็นรูปภาพ

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

เรคคอร์ดรูปคลื่นสองรายการเลื่อนแบบสด: ร่องรอยไมโครโฟนและร่องรอย IMU สามชุดข้อมูล#

ฟิลด์ waveform รับอัตราสุ่มตัวอย่าง และสำหรับหลายสัญญาณพร้อมกัน รับจำนวน series ที่สลับกันและชื่อของพวกมัน; การอัปเดตแต่ละครั้งคือไบต์ดิบของ array ของตัวอย่างใน typecode ของฟิลด์:

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 คือกริดของระยะทาง -- เฟรมที่เซ็นเซอร์ time-of-flight สร้างขึ้น -- และมุมมองจะวาดมันเป็นแผนที่สีเทียมที่ขยายขึ้นให้เท่าความสูงของกราฟ แถบเครื่องมือเลือกวิธีการแสดงผล: พาเลตต์ (พาเลตต์ Depth, Rainbow และ Ironbow ของกล้องเอง รวมถึงพาเลตต์สว่างและมืดสำหรับกล้องเหตุการณ์), ฟิลเตอร์ปรับขนาด ที่ขยายกริดเซ็นเซอร์ขนาดเล็ก (bicubic สำหรับพื้นผิวเรียบ, bilinear หรือ nearest สำหรับหนึ่งบล็อกต่อหนึ่งพิกเซลเซ็นเซอร์) และ การแมปโทน ที่เปลี่ยนระยะทางเป็นสี: Script Range ใช้ช่วงที่สคริปต์ประกาศไว้, Auto Range ยืดสีให้ครอบคลุมระยะทางที่มีอยู่จริงในแต่ละเฟรม (โดยไม่นับค่าผิดปกติไม่กี่เปอร์เซ็นต์) และ Equalize กระจายสีตามการแจกแจงของเฟรม ฉากที่แบนราบจึงยังแสดงรายละเอียดได้ ส่วนหัวรายงานขนาดของแผนที่ ช่วงที่ประกาศไว้ และค่าต่ำสุด สูงสุด และค่าเฉลี่ยของเฟรม; การวางเมาส์เหนือแผนที่จะอ่านค่าระยะทางใต้เคอร์เซอร์ และ Save Image เขียนแผนที่ที่แสดงผลแล้วเป็นไฟล์ 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

แผนที่ความลึกแบบ time-of-flight ของมือที่อยู่หน้าเซ็นเซอร์ พร้อมตัวเลือกพาเลตต์ การปรับขนาด และการแมปโทนในแถบเครื่องมือ#

ฟิลด์ depth ประกาศขนาดกริดและช่วงของมัน; การอัปเดตแต่ละครั้งคือกริดในรูปทศนิยม 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 ขอข้อมูลแชนเนลใหม่จากกล้องบ่อยเพียงใด; ค่าเริ่มต้นเหมาะกับสคริปต์ที่เผยแพร่ไม่กี่ครั้งต่อวินาที และสคริปต์ที่สตรีมเสียงจะได้ประโยชน์จากช่วงเวลาที่สั้นลง

See also

protocol.CBORChannel สำหรับฝั่งสคริปต์ -- ชนิดของเรคคอร์ด อาร์กิวเมนต์ของแต่ละชนิด และคอลแบ็ก on_write -- และตัวอย่าง 12-Protocol ภายใต้ File → Examples สำหรับสคริปต์ที่ใช้งานได้จริงซึ่งเผยแพร่ค่าอ่าน ตัวควบคุม และแผนที่ความลึก