Hľadanie vianočného algoritmu
Varovanie, text je určený pre technicky zdatných čitateľov.
Partnerka pred pár rokmi dostala od nemenovanej cukrovinkovej spoločnosti za nákup jej produktov vianočné gule, také čo plynule pomaly menia farby. Životnosť vzhľadom na vstavanú baterku nebola postačujúca, tak som baterky neskôr zamenil za napájací adaptér. Odvtedy keď sa blížia Vianoce, je mojou povinnosťou ich rozvešať a vytvoriť čaro Vianoc.
Tento rok prichádza opäť sviatok konzumu a s ním rovnaký problém, čím obdarujem partnerku ? Zistím algoritmus gule a použijem ho na ovládanie farebného dvojmetrového led pásu osvetľujúceho police !
Hľadanie algoritmu
Snažil som sa identifikovať algoritmus farieb, ale pri prelínaní farieb to nie je tak jednoduché. Skúsil som algoritmy na báze sínusu a posunu fáz, no s výsledkom som nebol spokojný.
Neúspech ma neodradil tak som vytvoril z svietiacej gule video. Video 60fps (fps - obrázkov za sekundu) som rozložil na sekvenčné snímky.
ffmpeg -i 20191206_103146.mp4 -vf fps=10 frame%04d.jpg -hide_banner
Z každého snímku som vyrezal 10x10 bodov.
for i in `ls -1` ; do convert $i -crop 10x10+540+960 crop/$i; done
Štvorce zoradil do pásu.
montage frame*.jpg -tile 10x40 -geometry +0+0 out.jpg
Presnejšie výsledkom je stĺpec, kde je jeden riadok zložený z 10 obrázkov ktoré predstavujú 1 sekundu:
Skúška konverzie štvorcov farieb na rgb kódy (red,green,blue základné farby z ktorých sa miešajú ostatné farby) ma síce naviedla k očakávaným výsledkom, ale vzhľadom na kvalitu farieb Samsungu S8 bola kvôli nepresným farbám nepoužiteľná. Radšej som si farby odhadol ručne. Tabuľka s rgb farbami:
255 | 0 | 0 | červená |
0 | 255 | 0 | zelená |
0 | 0 | 255 | modrá |
255 | 255 | 0 | žltá |
0 | 255 | 255 | tyrkysová |
255 | 0 | 255 | fialová |
255 | 255 | 255 | biela |
Časovanie je odhadom 3/5 svit farby, 2/5 prechod medzi farbami. Algoritmus je ako inak - triviálny.
Hardware
Ako hardware používam raspberry pi s doskou PCA9685 (i2c to 16x pwm). PWM je pulzná šírková modulácia, tz. regulácia je úmerná od zmeny šírky pulzu. Dosku je možné vynechať a elektroniku riadiť priamo cez GPIO piny na raspberry pi. Výkonový spínací tranzistor je použitý MosFet IRF3205 - ktorý je na vyžšie riadiace napätie, preto potrebuje budiaci tranzistor (ľubovolný NPN), zato má nízky vnútorný odpor, takže netreba chladič. Schéma:
Pre dosku pca9685 do /boot/config.txt pridať riadok
dtoverlay=i2c-pwm-pca9685a,addr=0x40
a reštartovať. V adresári /sys/class/pwm/pwmchip0 vzniknú riadiace súbory zariadenia PWM. Pokiaľ nemáš dosku môžeš na riadenie pomocou PWM použiť sw pi-blaster, ktorý cez DMA radič (používa sa na kopírovanie v RAM bez účasti CPU) vyemuluješ na GPIO výstupe PWM. V programe musíš zmeniť funkciu light(), keďže do súboru /dev/pi-blaster zapisuješ "číslo pinu = hodnota".
Finále
Algoritmus som mierne vylepšil je pomalší a vynechal som bielu farbu. Skúšobný kód:
#!/usr/bin/python3 # 0 = red, 1 = blue, 2 = green import time,os # negovane hodnoty #zoznam = ((0,255,255),(255,0,255),(255,255,0),(0,0,255),(255,0,0),(0,255,0),(0,0,0)); zoznam = ((0,255,255),(255,0,255),(255,255,0),(0,0,255),(255,0,0),(0,255,0)); rold=0; bold=0; gold=0; base = 1; def export(channel): ex = open('/sys/class/pwm/pwmchip0/export','w'); ex.write(str(channel)); ex.close(); pe = open('/sys/class/pwm/pwmchip0/pwm' + str(channel) + '/period','w'); pe.write(str(10000000)); pe.close(); en = open('/sys/class/pwm/pwmchip0/pwm' + str(channel) + '/enable','w'); en.write(str('1')); en.close(); return for exc in 0,1,2: if not os.path.isfile('/sys/class/pwm/pwmchip0/pwm' + str(exc) + '/duty_cycle'): export(exc); def light(color,value): if color == 'r': pwm = 0; if color == 'b': pwm = 1; if color == 'g': pwm = 2; x = open('/sys/class/pwm/pwmchip0/pwm' + str(pwm) + '/duty_cycle', 'w'); ns = value * 39200; #print ( color,value ); x.write(str(ns)); x.close(); return while True: for x,y,z in zoznam: while x != rold or y != gold or z != bold: if x > rold: rold = rold+base; light('r',rold); if x < rold: rold = rold-base; light('r',rold); if y > gold: gold = gold+base; light('g',gold); if y < gold: gold = gold-base; light('g',gold); if z > bold: bold = bold+base; light('b',bold); if z < bold: bold = bold-base; light('b',bold); time.sleep(0.1); time.sleep(5);
Už len integrovať do openhab2, ale o tom možno na budúce priatelia...