Zápisník experimentátora
Hierarchy: WS2812
This article describes an algorithm that simulates a burning fire. This is my first attempt to simulate fire. The simulation was run on NeoPixel Ring with 24 LEDs. The simulator is not designed for direct viewing. Place it next to the white wall on which it produces flickering like a real fire in the fireplace.
The simulation results, I would like to use with the LED strip 5 meters long. One effect should be this fire.
We will need the following components:
Protective components are necessary in order to not damage NeoPixel Ring. Details of protection are in article on powering these diodes.
The picture shows a ring with 12 diodes. Ring with 24 diodes is not very different from it and it is therefore possible to use a smaller ring after minor changes in the sketch.
Fire simulation is simple. We need to know the RGB value of the fire. 156,42,0 and 255,153,0 values represent shades of orange color, from which we will build our color. WS2812 LED green color is a little bit more intensive, so little of it we take, that we had more resulting color the red than green. Because these LEDs glow strong enough, we detract a little from the intensity and color brightness to get the smaller bonfire that burns instead of fire that melts the metal.
The algorithm consists of two steps:
The significant parts of the program are given in the following lines. I relied on my previous code to control NeoPixel Ring Clock. I added a function for substraction of values by which I am darkening color of each diode.
The definition of a class that simulates a burning fire. Important functions are Draw and Subtract, which creates a darker points in fire.
// 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);
}
Object of fire simulation.
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));
}
No one has such a good imagination, so you can see the resulting video on Youtube.
18.06.2019