V tomto projektu jsme si dali za cíl vyrobit nasvětlení pro divadelní/kino scénu. Z kartonů jsme vyrobili jeviště, z lego-technic strop a osvětlovací věže, dírky jsme pak využili pro LED diody, případně přichycení LED pásků. Vše jsme buď přímo, nebo pomocí tranzistorů připojili k několika microbitům, které je mohou rozsvěcet a zhasínat. Celé to řídí hlavní “serverový” microbit, který je instruovaný z počítače a posílá zprávy našim “klientským” microbitům.
Serverová část je nad limit kurzu, jedná se o GUI (grafické uživatelské rozhraní) vytvořené v jazyce Python:
a její funkcí je umožnit ovládání jednotlivých zařízení připojených k
několika microbitům. Tato část posílá na sériovou konzoli zprávy ve
formátu KANÁL NÁZEV HODNOTA
, kde:
vše oddělené pomocí mezer.
ZPRÁVA | POPIS |
---|---|
0 5 1023 | Rozsviť diodu 5 na microbitu na kanále 0 |
15 pasek 1023 0 1023 | Rozsviť pásek pasek připojený k microbitu na kanále 15 barvou #FF00FF |
7 servox 78 | Nastav servox připojené k microbitu na kanále 7 na pozici 78 |
Tyto zprávy putují po sériové konzoli do řídícího (server) microbitu. Ten čte zprávy na sériové konzoli, zjistí, na jaký kanál má zprávu přeposlat a odešle ji. Micropython základní kód:
from microbit import *
import radio
# Opakuj do nekonečně
while True:
# Přečti řádku ze sériové konzole
line = input().split(' ', 1)
# Kanál je prvním argumentem ve formátu číslo (integer - int)
kanal = int(line[0])
display.set_pixel(x, y, 0 if display.get_pixel(x, y) else 9)
# Nastav skupinu/kanál rádia
radio.config(group=kanal)
# Odešli zbytek řádky ke zpracování microbitům na tomto kanále
radio.send(line[1])
V praxi jsme pak používali lehce složitější verzi s vizualizací odesílaného kanálu a obsluze případné chyby:
from microbit import *
import radio
# Opakuj do nekonečně
while True:
try:
# Přečti řádku ze sériové konzole
line = input().split(' ', 1)
channel = int(line[0])
# Vizualizace odesílaného kanálu
x = channel // 5
y = channel % 5
display.set_pixel(x, y, 0 if display.get_pixel(x, y) else 9)
# Nastav skupinu/kanál rádia
radio.config(group=channel)
# Odešli zbytek řádky ke zpracování microbitům na tomto kanále
radio.send(line[1])
except Exception as details:
# V případě chybi ji vypiš na seriovou konzoli
print(details)
Klientské microbity mají na sobě připojené LED diody/pásky či motůrky. Pár ukázek Micropython kódů které slouží jako inspirace a zároveň kostra programu pro děti:
# Ovládání LED diod připojených na piny 0, 1, 2, 3, 4
from microbit import *
import radio
# Nastav skupinu rádia
radio.on()
radio.config(group=0)
while True:
try:
prijato = radio.receive()
# Zkontroluj, že přišla nějaká zpráva
if not prijato:
continue
# Zprávu rozděl po mezerníkách
data = prijato.split(' ')
# Získej diodu a hodnotu
dioda = data[0]
hodnota = int(data[1])
# Rozsviť požadovanou diodu
if dioda == "0":
pin0.write_analog(hodnota)
elif dioda == "1":
pin1.write_analog(hodnota)
elif dioda == "2":
pin2.write_analog(hodnota)
elif dioda == "3":
pin3.write_analog(hodnota)
elif dioda == "4":
pin4.write_analog(hodnota)
else:
print("ERROR: %s" % prijato)
except Exception as details:
# Vytiskni chybu na seriovou konzoli
print(str(details))
# Ovládání LED pásku připojeného na pinu 1 s 11 diodami
from microbit import *
import radio
import neopixel
# Nastav skupinu rádia
radio.on()
radio.config(group=0)
# Zapni led pásek
pasek = neopixel.NeoPixel(pin1, 11)
while True:
try:
prijato = radio.receive()
# Zkontroluj, že přišla nějaká zpráva
if not prijato:
continue
# Zprávu rozděl po mezerníkách
data = prijato.split(' ')
# Získej diodu a hodnotu
modul = data[0]
hodnota = int(data[1])
# Rozsviť všechny diody LED pásku
if modul == "pasek":
r = hodnota
g = int(data[2])
b = int(data[3])
pasek.fill((r // 4, g // 4, b // 4))
pasek.show()
else:
print("ERROR: %s" % prijato)
except Exception as details:
# Vytiskni chybu na seriovou konzoli
print(str(details))
Pro simulaci denního světla lze využít LED pásek s pohyblivým světlem:
from microbit import *
import radio
import neopixel
# Nastav skupinu rádia
radio.on()
radio.config(group=0)
# Zapni led pásek
DELKA = 27 # Počet diod
POZICE = 0 # Pozice kam svítit
SIRKA = 3 # Kolik LED rozsvítit okolo středu
BARVA = (255, 255, 255) # Jakou barvou svítit
PASEK = neopixel.NeoPixel(pin1, 11)
# Otestuj funkci po spuštění
PASEK.fill((0, 0, 255))
PASEK.show()
def zobraz_pasek():
# Překresli LED pásek
PASEK.clear()
PASEK[POZICE] = BARVA
for i in range(1, SIRKA):
PASEK[max(POZICE - i, 0)] = BARVA
PASEK[min(POZICE + i, DELKA-1)] = BARVA
PASEK.show()
while True:
try:
prijato = radio.receive()
# Zkontroluj, že přišla nějaká zpráva
if not prijato:
continue
# Zprávu rozděl po mezerníkách
data = prijato.split(' ')
# Získej diodu a hodnotu
modul = data[0]
hodnota = int(data[1])
if modul == "pozice":
# Změň pozici a překresli pásek
# hodnota je 0 - 1023, přepočítej na 0 - (DELKA-1)
POZICE = hodnota * DELKA // 1024
zobraz_pasek()
elif modul == "barva":
# Změň barvu a překresli pásek
# hodnota ke 0 - 1023, přepočítej na 0 - 255
BARVA = (hodnota // 4, int(data[2]) // 4, int(data[3]) // 4)
zobraz_pasek()
elif modul == "pasek":
# Rozsviť všechny diody LED pásku
r = hodnota
g = int(data[2])
b = int(data[3])
# hodnota ke 0 - 1023, přepočítej na 0 - 255
PASEK.fill((r // 4, g // 4, b // 4))
PASEK.show()
else:
print("ERROR: %s" % prijato)
except Exception as details:
# Vytiskni chybu na seriovou konzoli
print(str(details))
Můžeme zobrazit i několik pohyblivých světel na jednom led pásku_
from microbit import *
import radio
import neopixel
# Nastav skupinu rádia
radio.on()
radio.config(group=4)
class Svetlo:
def __init__(self, pozice=0, sirka=0, barva=(0, 0, 0)):
self.pozice = pozice
self.sirka = sirka
self.barva = barva
def __str__(self):
return " ".join(str(_) for _ in (self.pozice, self.sirka, self.barva))
# Zapni led pásek
DELKA = 300 # Počet diod
SVETLA = [Svetlo() for _ in range(5)]
PASEK = neopixel.NeoPixel(pin1, DELKA)
# Otestuj funkci po spuštění
PASEK.fill((0, 0, 255))
#PASEK[0] = (254, 0, 0)
PASEK.show()
def zobraz_pasek():
# Překresli LED pásek
PASEK.clear()
for svetlo in SVETLA:
PASEK[svetlo.pozice] = svetlo.barva
i=0
for i in range(1, svetlo.sirka):
PASEK[max(svetlo.pozice - i, 0)] = svetlo.barva
PASEK[min(svetlo.pozice + i, DELKA-1)] = svetlo.barva
PASEK.show()
while True:
try:
prijato = radio.receive()
# Zkontroluj, že přišla nějaká zpráva
if not prijato:
continue
# Zprávu rozděl po mezerníkách
data = prijato.split(' ')
# Získej diodu a hodnotu
modul = data[0]
index = int(data[1])
hodnota = int(data[2])
if modul == "pozice":
# Změň pozici a překresli pásek
# hodnota je 0 - 1023, přepočítej na 0 - (DELKA-1)
SVETLA[index].pozice = hodnota * DELKA // 1024
zobraz_pasek()
elif modul == "barva":
# Změň barvu a překresli pásek
# hodnota ke 0 - 1023, přepočítej na 0 - 255
SVETLA[index].barva = (hodnota // 4, int(data[3]) // 4, int(data[4]) // 4)
zobraz_pasek()
elif modul == "sirka":
# Změň šířku světla a překresli pásek
SVETLA[index].sirka = hodnota * DELKA // 512
zobraz_pasek()
elif modul == "pasek":
# Rozsviť všechny diody LED pásku
r = hodnota
g = int(data[3])
b = int(data[4])
# hodnota ke 0 - 1023, přepočítej na 0 - 255
PASEK.fill((r // 4, g // 4, b // 4))
#PASEK[0] = (r // 4, g // 4, b // 4)
PASEK.show()
else:
print("ERROR: %s" % prijato)
except Exception as details:
# Vytiskni chybu na seriovou konzoli
print(str(details))
Pro otestování komunikace jsme nejprve použili (trošku složitější) kód který rozsvěcí přímo diody na displeji microbitu:
from microbit import *
import radio
# Nastav skupinu rádia
radio.on()
radio.config(group=0)
while True:
try:
prijato = radio.receive()
# Zkontroluj, že přišla nějaká zpráva
if not prijato:
continue
# Zprávu rozděl po mezerníkách
data = prijato.split(' ')
# Získej diodu a novou hodnotu
dioda = int(data[0])
hodnota = int(data[1])
# Rozsviť diodu 0-25 pomocí souřadnic 0-5, 0-5
# hodnotu poděl 114 protože microbit očekává hodnotu 0-9
display.set_pixel(dioda // 5, dioda % 5, hodnota // 102)
except Exception as details:
# Vytiskni chybu na seriovou konzoli
print(str(details))
Stop-motion animace je technika, kdy fotíme scénu po jednotlivých snímcích s drobnými změnami (pohyb ruky, posunutí motorky, …) a následné spojení do jednoho videa. Existuje mnoho programů, které nám s tímto mohou pomoci, my jsme ale zvolili přímý postup bez využití specializovaných aplikací, abychom si ukázali, co vše je k tomuto potřeba.
Fotky jsme snímali pomocí telefonu s fyzickým zoomem 2x (ukázali jsme si i 0.5x a 1x, rozdíl byl hlavně při okrajích kdy širokoúhlá čočka “vidí” širší záběr a výrazně se liší pozorovací úhly, 2x zoom má tyto rozdíly výrazně menší a lépe se hodí pro natáčení našich scén). V aplikaci (FreeDcam) jsme museli nastavit na pevno hodnoty ISO (citlivost snímače - souvisí se šumem a světlostí; 100), rychlost uzávěrky (jak dlouho se bude “vyvolávat” fotografie - světlost; 0.8s), vyvážení bíle (automatika by nám vyrušila barevné efekty; 5000/3800) a zaostření.
Aby se nám mobilní telefon neposunoval, propojili jsme jej s počítačem a snímky pořizovali pomocí adb. Ten umožňuje simulovat doteky na obrazovce pomocí příkazu adb shell "input tap 10 20"
(dotkni se prstem na poloze x=10 y=20).
Po pořízení fotografie jsme fotky rovnou stahovali do počítače opět pomocí adb příkazem adb pull -Z "$ADRESAR_FOTEK_TELEFON/$FOTO" "$ADRESAR_FOTEK_PC/"
. Abychom mohli výsledek zkontrolovat, zobrazili jsme si vždy nejnovější fotografii v klasickém prohlížeči obrázků. Abychom nemuseli překlikávat vždy na poslední fotku, nechali jsme počítač vždy zkopírovat poslední staženou fotku a přejmenovat ji na .posledni.jpg
, čímž prohlížeč fotek vždy po přepsání sám aktualizoval zobrazovanou .posledni.jpg
fotografii.
Abychom lépe viděli rozdíl mezi předchozím a současným snímkem, nechali jsme počítač vytvořit ještě jeden obrázek složený z poslední fotky a přes ní polo-průhledným obrázkem předposlední fotky. K tomu jsme využili programový balík ImageMagic
.
Celý (BASH) skript vypadal následovně (spustitelné v operačním systému GNU/Linux, Windows používá obdobné BAT soubory):
#!/bin/bash
## Definice proměnných použitých dále v programu
ADRESAR_FOTEK_TELEFON="/storage/self/primary/DCIM/FreeDcam"
ADRESAR_FOTEK_PC="./foto"
POZICE_TLACITKA_VYFOT="2100 500"
## Funkce použité dále v programu
stahni_nove_fotky() {
# Detekuj nové fotky a stáhni je
for IMG in $(adb shell "cd $ADRESAR_FOTEK_TELEFON && ls -1"); do
[ -e "$ADRESAR_FOTEK_PC/$IMG" ] && continue
adb pull -Z "$ADRESAR_FOTEK_TELEFON/$IMG" "$ADRESAR_FOTEK_PC/"
done
}
vyfot_fotku() {
# Stiskni tlačítko vyfotit
adb shell "input tap $POZICE_TLACITKA_VYFOT"
# Odkomentuj následující řádek pro vyčkání na uložení fotky
sleep 1.5
}
aktualizuj_nahled() {
# Zkopíruj poslední obrázek do .posledni.jpg a vytvoř sloučený obrázek z posledních 2 obrázků
OBRAZKY=($(ls -t "$ADRESAR_FOTEK_PC" | head -n 2))
cp "$ADRESAR_FOTEK_PC/${OBRAZKY[0]}" "$ADRESAR_FOTEK_PC/.posledni.jpg"
convert "$ADRESAR_FOTEK_PC/${OBRAZKY[1]}" -quality 25 -alpha set -channel A -evaluate set 50% +channel "$ADRESAR_FOTEK_PC/.pruhledny.png"
composite "$ADRESAR_FOTEK_PC/.pruhledny.png" "$ADRESAR_FOTEK_PC/${OBRAZKY[0]}" -quality 25 -alpha on -compose over "$ADRESAR_FOTEK_PC/.nahled.png"
}
## Nyní již vlastní kód
# Vytvoř výstupní složku
mkdir -p "$ADRESAR_FOTEK_PC"
# Do nekonecna porizuj fotky a stahuj je
echo "Pozor, uložení fotky může chvíli trvat, takže poslední fotka nemusí být synchronizovaná!"
while true; do
echo "ENTER pro vyfocení scény, CTRL+C pro ukončení"
read
vyfot_fotku
stahni_nove_fotky
aktualizuj_nahled
done
Celý postup pak vypadal následovně:
A tak pořád dokola, dokud nebylo dost obrazového materiálu ke zpracování.