13.1.10. Itsenäiset terminaali-ikkunat

Tools → Open Terminal avaa itsenäisiä terminaali-ikkunoita – jokainen on pienoiskoinen OpenMV IDE -istunto omassa ikkunassaan, jossa on kehyspuskurin katselin, histogrammi ja vuorovaikutteinen terminaali, yhdistettynä valitsemasi siirtotien yli. Pääikkunan yhteyteen tämä ei vaikuta, joten itsenäisen terminaalin avulla voit tarkkailla toista kameraa ensimmäisen pysyessä yhdistettynä, tai vianetsiä kameraa verkon toisella puolella.

Itsenäinen terminaali-ikkuna: vuorovaikutteinen terminaali vasemmalla työkalupalkkeineen, kehyspuskuri ja histogrammi oikealla

Itsenäinen terminaali-ikkuna sarjaportin yli: vuorovaikutteinen terminaali vasemmalla run / stop / reset -työkalupalkkineen, kehyspuskuri ja histogrammi oikealla – ne heräävät eloon, kun kamera lähettää kehyksiä virrassa.

New Terminal pyytää valitsemaan yhden kolmesta siirtotiestä:

  • Serial port – mikä tahansa sarjaportti millä tahansa siirtonopeudella (oletus 115 200). Tämä kattaa toisen kameran USB-portin, USB-to-UART-sillan kautta kytketyn kameran, Bluetooth-sarjayhteyden (joka näkyy tavallisena sarjaporttina) tai minkä tahansa muun kuin OpenMV-sarjalaitteen, joka tarvitsee terminaalin. USB-portissa siirtonopeus ei rajoita nopeutta – data liikkuu aina USB-yhteyden nopeudella – mutta kameran USB-portissa vältä arvoja 921 600 ja 12 000 000, jotka vaihtavat kameran REPL-tilasta IDE:n vianetsintäprotokollaan.

  • TCP – yhdistä palvelimeen valitulla isäntänimellä ja portilla, tai kuuntele itse palvelimena valitussa portissa.

  • UDP – sama roolipari, UDP:n yli.

IDE muistaa kymmenen viimeisintä kokoonpanoa ja listaa ne Open Terminal -alivalikkoon yhden klikkauksen uudelleenavaamista varten; Clear Menu unohtaa ne.

Toisin kuin pääikkunan pelkästään tulosteen näyttävä ruutu, itsenäinen terminaali on täysin vuorovaikutteinen: se on REPL. Kirjoita kehotteeseen ja Python suorittaa koodin yhdistetyssä kamerassa rivi riviltä, MicroPythonin itsensä tarjoamalla historialla ja sarkaintäydennyksellä. Työkalupalkki lisää yhden klikkauksen vastineet tavallisille ohjaussekvensseille – suorita nykyinen editorin skripti, pysäytä käynnissä oleva skripti ja tee pehmeä uudelleenkäynnistys – sekä samat tyhjennys-, tallennus- ja rivitysohjaimet kuin pääterminaaliruudussa.

Terminaalin yläpuolella oleva kehyspuskuri on myös elävä. Kun yhdistetty kamera lähettää pakattuja kehyksiä virrassa – upotettuna samaan virtaan kuin tulosteensa – terminaali purkaa ja näyttää ne, ja Record- ja Zoom-painikkeet toimivat täsmälleen kuten pääikkunassa. Tämä yhdistelmä on IDE:n verkkovianetsinnän tarina: kamera, joka tarjoaa REPL:nsä Wi-Fin yli, saa täyden edit-run-preview-silmukan ilman ainuttakaan USB-kaapelia.

13.1.10.1. Kehysten lähettäminen virrassa

Koodaus, jonka terminaali ymmärtää, on yksinkertainen: 0xFE-tavu aloittaa kehyksen, toinen 0xFE sulkee sen, ja jokaisella niiden välisellä hyötykuormatavulla on ylin bittinsä asetettuna ja se kantaa kuusi bittiä pakattua kuvaa – kolmesta kuvatavusta tulee neljä hyötykuormatavua. Tavallinen teksti ei koskaan käytä näitä tavuarvoja, joten kehykset ja print()-tuloste jakavat virran törmäämättä: terminaali näyttää tekstin ja näyttää kehykset.

Alla oleva skripti ottaa tilannekuvan, muuntaa kunkin kehyksen JPEG-muotoon ja tulostaa sen tässä muodossa. Bittien pakkaus tapahtuu ulab-kirjaston kautta (jossa ei ole siirto-operaattoreita, joten siirrot on kirjoitettu kertolaskuina ja jakolaskuina), ja se on riittävän nopea pysyäkseen kameran tahdissa:

import csi
import sys
import time
from ulab import numpy as np

csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QVGA)

clock = time.clock()


def encode_for_ide(data):
    n = len(data)
    n3 = n - (n % 3)
    m = (n3 // 3) * 4
    out = bytearray(((n * 8) + 5) // 6 + 2)
    out[0] = 0xFE
    out[-1] = 0xFE
    if n3:
        src = np.frombuffer(data, dtype=np.uint8)
        dst = np.frombuffer(out, dtype=np.uint8)
        b0 = src[0:n3:3]
        b1 = src[1:n3:3]
        b2 = src[2:n3:3]
        dst[1:m + 1:4] = (b0 & 0x3F) | 0x80
        dst[2:m + 2:4] = (b0 // 64) | ((b1 & 0x0F) * 4) | 0x80
        dst[3:m + 3:4] = (b1 // 16) | ((b2 & 0x03) * 16) | 0x80
        dst[4:m + 4:4] = (b2 // 4) | 0x80
    if n % 3 == 2:
        x = data[n - 2] | (data[n - 1] << 8)
        out[m + 1] = 0x80 | (x & 0x3F)
        out[m + 2] = 0x80 | ((x >> 6) & 0x3F)
        out[m + 3] = 0x80 | ((x >> 12) & 0x3F)
    elif n % 3 == 1:
        out[m + 1] = 0x80 | (data[n - 1] & 0x3F)
        out[m + 2] = 0x80 | (data[n - 1] >> 6)
    return out


while True:
    clock.tick()
    img = csi0.snapshot().to_jpeg(quality=80)
    sys.stdout.write(encode_for_ide(img.bytearray()))
    print(clock.fps())

Tämä toimii itsenäisessä terminaalissa, koska REPL:n tulostus odottaa: kamera estyy, kunnes terminaali on ottanut datan vastaan, joten jokainen kehyksen tavu saapuu perille, ja JPEG liikkuu nopeasti USB:n full-speed- tai high-speed-yhteyden yli. Sama skripti toimii muuttamattomana TCP-terminaalin yli, mikä on edellä kuvattu verkkovianetsinnän reitti. Ainoa paikka, jossa se ei toimi, on IDE:n pääasiallinen vianetsintäyhteys, jonka tulostuskanava nollaa itsensä ylivuodon sattuessa odottamisen sijaan – siellä kehyspuskurin katselin näyttää jo kameran kehykset natiivisti, joten mitään ei jää huomaamatta.