Simulácia ohňa

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ň.

Súčiastky

Budeme potrebovať nasledovné súčiastky:

  • Arduino Uno alebo Mini {linkArduino}
  • Breadboard {linkBreadboard}
  • NeoPixel Ring s 24 diódami. Ja som môj kupoval od Banggood. Dá sa kúpiť aj na Ebay (pod názvom led ring 24bit) a priemerná cena v čase nákupu bola 5,6 USD za kus. {linkNeopixel}
  • Ochranný rezistor 470R. {linkR}
  • Ochranný kondenzátor 1000 uF. {linkC}

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.

Algoritmus

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:

  • Nastavenie všetkých bodov na maximálnu hodnotu farby ohňa.
  • Výber náhodného čísla pre každú diódu. Túto hodnotu odpočítame od maximálnej hodnoty ohňa. Náhodné číslo vyberáme tak, aby sme vytvorili širší rozsah tmavších odtieňov pôvodnej farby.
  • Po nastavení všetkých diód nasleduje krátky časový úsek s nepravidelnou dĺžkou, ktorý spomaľuje efekt na rýchlosť, akou by približne horel aj skutočný oheň.

Programovanie

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));
}

Video

Nik nemá takú dobrú predstavivosť, preto si môžete pozrieť výsledné video na Youtube.



Video




Download

23.09.2015


Menu