Zápisník experimentátora
Hierarchy: WS2812
Tento článok popisuje algoritmus, ktorý simuluje horenie ohňa. Je to môj prvý pokus o jeho simuláciu. Simulácia sa skúša na NeoPixel Ringu s 24 LED diódami. Simulátor nie je určený na priame pozeranie. Predpokladá sa jeho umiestnenie pri bielej stene, na ktorej vytvára mihotanie podobné reálnemu ohňu v kozube.
Výsledky simulácie by som chcel využiť v LED pásiku, dlhom 5 metrov. Jedným z efektov by mal byť aj tento oheň.
![]()
Budeme potrebovať nasledovné súčiastky:
Ochranné súčiastky sú nutné preto, aby sa NeoPixel Ring nepoškodil. Podrobnosti ochrany sú uvedené v článku o napájaní týchto diód.
![]()
Na obrázku je Ring s 12 diódami. Ring s 24 diódami sa nijako mimoriadne od neho nelíši a je preto možné použiť aj menší ring po príslušnej úprave kódu.
Simulácia ohňa je jednoduchá. Potrebujeme poznať RGB hodnotu ohňa. Hodnoty 156,42,0 a 255,153,0 predstavujú odtiene oranžovej farby, z ktorých budeme vychádzať. LED WS2812 majú zelenú farbu trochu intenzívnejšiu, takže z nej budeme trochu uberať, aby sme výslednú farbu mali viac červenu než zelenú. Pretože tieto diódy svietia dosť silno, uberieme trochu aj z intenzity farby, aby sme dostali jas menšieho ohníka namiesto blčiaceho ohňa, ktorý taví kov.
![]()
Samotný algoritmus pozostáva z dvoch krokov:
Podstatné časti z programu sú uvedené na nasledovných riadkoch. Vychádzal som z môjho predchádzajúceho kódu na ovládanie NeoPixel Ring hodín. Do kódu som doplnil funkciu na odčítanie hodnôt, pomocou ktorej tlmím farbu na jednotlivých diódach.
![]()
Definícia triedy, ktorá simuluje horiaci oheň. Podstatná funkcia je Draw a Substract, ktoré vytvárajú tmavšie body v ohni.
// led count
#define CNT 24
uint32_t fire_color = strip.Color ( 80, 35, 00);
uint32_t off_color = strip.Color ( 0, 0, 0);
///
/// Set all colors
///
void NeoFire::Draw()
{
Clear();
for(int i=0;i<CNT;i++)
{
AddColor(i, fire_color);
int r = random(80);
uint32_t diff_color = strip.Color ( r, r/2, r/2);
SubstractColor(i, diff_color);
}
strip.show();
}
///
/// Set color of LED
///
void NeoFire::AddColor(uint8_t position, uint32_t color)
{
uint32_t blended_color = Blend(strip.getPixelColor(position), color);
strip.setPixelColor(position, blended_color);
}
///
/// Set color of LED
///
void NeoFire::SubstractColor(uint8_t position, uint32_t color)
{
uint32_t blended_color = Substract(strip.getPixelColor(position), color);
strip.setPixelColor(position, blended_color);
}
///
/// Color blending
///
uint32_t NeoFire::Blend(uint32_t color1, uint32_t color2)
{
uint8_t r1,g1,b1;
uint8_t r2,g2,b2;
uint8_t r3,g3,b3;
r1 = (uint8_t)(color1 >> 16),
g1 = (uint8_t)(color1 >> 8),
b1 = (uint8_t)(color1 >> 0);
r2 = (uint8_t)(color2 >> 16),
g2 = (uint8_t)(color2 >> 8),
b2 = (uint8_t)(color2 >> 0);
return strip.Color(constrain(r1+r2, 0, 255), constrain(g1+g2, 0, 255), constrain(b1+b2, 0, 255));
}
///
/// Color blending
///
uint32_t NeoFire::Substract(uint32_t color1, uint32_t color2)
{
uint8_t r1,g1,b1;
uint8_t r2,g2,b2;
uint8_t r3,g3,b3;
int16_t r,g,b;
r1 = (uint8_t)(color1 >> 16),
g1 = (uint8_t)(color1 >> 8),
b1 = (uint8_t)(color1 >> 0);
r2 = (uint8_t)(color2 >> 16),
g2 = (uint8_t)(color2 >> 8),
b2 = (uint8_t)(color2 >> 0);
r=(int16_t)r1-(int16_t)r2;
g=(int16_t)g1-(int16_t)g2;
b=(int16_t)b1-(int16_t)b2;
if(r<0) r=0;
if(g<0) g=0;
if(b<0) b=0;
return strip.Color(r, g, b);
}
Použitie objektu simulácie ohňa.
NeoFire fire(strip);
///
/// Setup
///
void setup()
{
strip.begin();
strip.show(); // Initialize all pixels to 'off'
}
///
/// Main loop
///
void loop()
{
fire.Draw();
delay(random(50,150));
}
Nik nemá takú dobrú predstavivosť, preto si môžete pozrieť výsledné video na Youtube.
23.09.2015