13.1.10. Fristående terminalfönster¶
Tools → Open Terminal öppnar oberoende terminalfönster – var och en en miniatyrsession av OpenMV IDE i sitt eget fönster, med en bildbuffertvisare, ett histogram och en interaktiv terminal, anslutna via en transport du själv väljer. Huvudfönstrets anslutning påverkas inte, så en fristående terminal låter dig titta på en andra kamera medan den första förblir ansluten, eller felsöka en kamera på andra sidan av ett nätverk.
Ett fristående terminalfönster över en seriell port: den interaktiva terminalen till vänster med sitt verktygsfält för kör/stopp/återställ, bildbufferten och histogrammet till höger – de tänds när kameran strömmar bildrutor in-band.¶
New Terminal frågar efter en av tre transporter:
Serial port – vilken seriell port som helst med vilken baudhastighet som helst (standard 115 200). Detta täcker en andra kameras USB-port, en kamera kopplad via en USB-till-UART-brygga, en seriell Bluetooth-länk (som visas som en vanlig seriell port), eller vilken icke-OpenMV-seriell enhet som helst som behöver en terminal. På en USB-port begränsar baudhastigheten inte hastigheten – data flyttas alltid med USB-länkens hastighet – men på en kameras USB-port bör du undvika 921 600 och 12 000 000, som växlar kameran från REPL till IDE:ns felsökningsprotokoll.
TCP – anslut till en server på en vald värd och port, eller lyssna som en på en vald port.
UDP – samma par av roller, över UDP.
IDE:n kommer ihåg de tio senaste konfigurationerna och listar dem i undermenyn Open Terminal för återöppning med ett klick; Clear Menu glömmer dem.
Till skillnad från huvudfönstrets ruta som endast visar utdata är en fristående terminal fullt interaktiv: den är en REPL. Skriv vid prompten så kör Python på den anslutna kameran rad för rad, med historik och tabbkomplettering som tillhandahålls av MicroPython självt. Verktygsfältet lägger till motsvarigheter med ett klick för de vanliga styrsekvenserna – kör det aktuella editorskriptet, stoppa det körande skriptet och mjuk återställning – samt samma kontroller för rensa, spara och radbrytning som huvudterminalrutan.
Bildbufferten ovanför terminalen är också live. När den anslutna kameran strömmar komprimerade bildrutor in-band – inbäddade i samma ström som dess utskrifter – avkodar och visar terminalen dem, och knapparna Record och Zoom fungerar precis som de gör i huvudfönstret. Den kombinationen är IDE:ns berättelse om nätverksfelsökning: en kamera som exponerar sin REPL över Wi-Fi får hela slingan redigera-kör-förhandsgranska utan att någon USB-kabel är inblandad.
13.1.10.1. Strömma bildrutor in-band¶
Kodningen som terminalen förstår är enkel: en 0xFE-byte öppnar en bildruta, en andra 0xFE stänger den, och varje nyttolastbyte mellan dem har sin översta bit satt och bär sex bitar av den komprimerade bilden – tre bildbytes blir fyra nyttolastbytes. Vanlig text använder aldrig de bytevärdena, så bildrutor och print()-utdata delar strömmen utan att kollidera: terminalen visar texten och visar bildrutorna.
Skriptet nedan fångar, konverterar varje bildruta till JPEG och skriver ut den i den formen. Bitpackningen körs genom ulab (som inte har några skiftoperatorer, så skiften skrivs som multiplikationer och divisioner), och är tillräckligt snabb för att hänga med kameran:
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())
Detta fungerar i en fristående terminal eftersom REPL-utskrift väntar: kameran blockerar tills terminalen har tagit emot datan, så varje byte av bildrutan kommer fram, och en JPEG flyttas snabbt över en USB-länk i full eller hög hastighet. Samma skript fungerar oförändrat över en TCP-terminal, vilket är vägen för nätverksfelsökning ovan. Det enda stället där det inte fungerar är IDE:ns huvudfelsökningsanslutning, vars utdatakanal återställer sig själv vid överflöd istället för att vänta – där visar bildbuffertvisaren redan kamerans bildrutor nativt, så ingenting missas.