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 červená 
0 255  zelená 
0 0 255 modrá 
255 255  žltá 
0 255  255  tyrkysová 
255 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...