Flackerndes Windlicht - Programmversion 0.3
Der Nachteil der Programmversion 0.2 ist, dass die Flamme sich nur auf einer Kreisbahn bewegen kann. Das ist schon recht effektvoll, aber nur eine lausige Simulation der Bewegung einer echten Flamme im Windzug. Daher habe ich den Code in dieser Programmversion vollständig überarbeitet.
Ab dieser Programmversion kann sich die Flamme über die gesamte Kreisfläche bewegen, die der NeoPixel-Ring umschließt. Die Variable „deviance“ beschreibt die Ablenkung der Flamme aus der Mittelstellung, die Variable „angle“ den Winkel der Ablenkung und die Variable „flickerDepth“ die Stärke des Flackerns. Die Variable „FlickerDepth“ wirkt sich global auf die Helligkeit aller NeoPixel aus, da sie ein Multiplikator ist aber auf die helleren stärker als auf die dunkleren. Was mir sehr gut gefällt ist, dass der Algorithmus sehr kompakt ist.
// Flickering and fluttering candle
// This code emulates a candle using a ring of twelve NeoPixels
// Version 0.4.3
// by Frickelpiet
// Libraries
#include <Adafruit_NeoPixel.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_TSL2561_U.h>
// Define output pin
#define PIN 2
// Define the NeoPixel ring
int numPixels = 12; // Number of NeoPixels
Adafruit_NeoPixel ring = Adafruit_NeoPixel(numPixels, PIN, NEO_GRBW + NEO_KHZ800);
// Define the light seensor (TSL2561)
Adafruit_TSL2561_Unified tsl = Adafruit_TSL2561_Unified(TSL2561_ADDR_FLOAT, 12345);
// Variables
int mode = 0; // Mode of the flame's flickering and fluttering
double deviation = 0; // Value for the flame's deviation from the center of the candle (min: 0; max: 1)
double angle = 0; // Angle of the flame's deviation from the center (min: 0; max: 359)
double flickering; // Value for the flame's flickering (min: 0; max: 1000)
int brightness = 255; // Value for the flame's brightness (min: 0; max: 255)
double pi = 3.14159265358979; // Pi
double angleArray[12]; // Array für die Winkelpositionen der NeoPixel
double deviationArray[12]; // Array für die d-Werte für jedes einzelne NeoPixel
byte flameArray[12];
double flickerDepth; // (min: 0; max: 1000)
double deviationAlteration; // (min: 0; max: 1000)
double deviationTreshold; // (min: 0; max: 1)
double angleAlteration; // (min: 0; max: 1000)
float sensorValue;
unsigned long previousMillisProgram = 0; // Program
unsigned long previousMillisCandle = 0; // Emulation
unsigned long previousMillisBrightness = 0; // Brightness
unsigned long intervalProgram = 50; // Program
unsigned long intervalCandle = 20; // Emulation
unsigned long intervalBrightness = 200; // Brightness
void setup() {
Serial.begin(115200);
if(!tsl.begin())
{
/* There was a problem detecting the TSL2561 ... check your connections */
Serial.print("Ooops, no TSL2561 detected ... Check your wiring or I2C ADDR!");
while(1);
}
sensor_t sensor;
tsl.getSensor(&sensor);
Serial.println("------------------------------------");
Serial.print ("Sensor: "); Serial.println(sensor.name);
Serial.print ("Driver Ver: "); Serial.println(sensor.version);
Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id);
Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" lux");
Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" lux");
Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" lux");
Serial.println("------------------------------------");
Serial.println("");
delay(500);
/* You can also manually set the gain or enable auto-gain support */
tsl.setGain(TSL2561_GAIN_1X); /* No gain ... use in bright light to avoid sensor saturation */
// tsl.setGain(TSL2561_GAIN_16X); /* 16x gain ... use in low light to boost sensitivity */
// tsl.enableAutoRange(true); /* Auto-gain ... switches automatically between 1x and 16x */
/* Changing the integration time gives you better sensor resolution (402ms = 16-bit data) */
tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_13MS); /* fast but low resolution */
// tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_101MS); /* medium resolution and speed */
// tsl.setIntegrationTime(TSL2561_INTEGRATIONTIME_402MS); /* 16-bit data but slowest conversions */
/* Update these values depending on what you've set above! */
Serial.println("------------------------------------");
Serial.print ("Gain: "); Serial.println("Auto");
Serial.print ("Timing: "); Serial.println("13 ms");
Serial.println("------------------------------------");
randomSeed(analogRead(6));
// Calculate the angle for each NeoPixel
angleArray[0] = 0;
for (int i = 0; i < numPixels - 1; i++) {
angleArray[i + 1] = angleArray[i] + pi / (numPixels / 2);
}
for(int i = 0; i < numPixels; i++) {
Serial.println(angleArray[i]);
}
ring.begin();
ring.show(); // Initialize all pixels to 'off'
}
void loop() {
// Get current time in microseconds
unsigned long currentMillis = millis();
// Program modes
if ((unsigned long)(currentMillis - previousMillisProgram) >= intervalProgram) {
mode = random(0, 4);
//mode = 4;
// Calm burning
if (mode == 0) {
intervalCandle = random(80, 100);
flickerDepth = 940;
deviationAlteration = 50;
deviationTreshold = 0.5;
angleAlteration = 30;
intervalProgram = random(1000, 30000);
Serial.print("Calm burning: "); Serial.print(intervalCandle); Serial.print(", "); Serial.println(intervalProgram);
}
// Gentle flickering
if (mode == 1) {
intervalCandle = random(60, 80);
flickerDepth = 900;
deviationAlteration = 100;
deviationTreshold = 0.6;
angleAlteration = 60;
intervalProgram = random(1000, 20000);
Serial.print("Gentle flickering: "); Serial.print(intervalCandle); Serial.print(", "); Serial.println(intervalProgram);
}
// Moderate flickering
if (mode == 2) {
intervalCandle = random(50, 60);
flickerDepth = 850;
deviationAlteration = 150;
deviationTreshold = 0.7;
angleAlteration = 90;
intervalProgram = random(1000, 10000);
Serial.print("Moderatemoderat flickering: "); Serial.print(intervalCandle); Serial.print(", "); Serial.println(intervalProgram);
}
// Noticeabal flickering
if (mode == 3) {
intervalCandle = random(40, 50);
flickerDepth = 800;
deviationAlteration = 200;
deviationTreshold = 0.8;
angleAlteration = 120;
intervalProgram = random(1000, 8000);
Serial.print("Noticeable flickering: "); Serial.print(intervalCandle); Serial.print(", "); Serial.println(intervalProgram);
}
// Strong flickering
if (mode == 4) {
intervalCandle = random(30, 50);
flickerDepth = 750;
deviationAlteration = 250;
deviationTreshold = 1.0;
angleAlteration = 240;
intervalProgram = random(1000, 5000);
Serial.print("Strong flickering: "); Serial.print(intervalCandle); Serial.print(", "); Serial.println(intervalProgram);
}
previousMillisProgram = currentMillis;
}
// Emulation of the flame's flickering and fluttering
if ((unsigned long)(currentMillis - previousMillisCandle) >= intervalCandle) {
// Calculation of the flame's deviation from the center
deviation = deviation + double(random(-deviationAlteration, deviationAlteration)) / 1000;
if (deviation < 0) {
deviation = 0;
}
if (deviation > deviationTreshold) {
deviation = deviationTreshold;
}
// Calculation of the angle of the flame's deviation
angle = angle + double(random(-angleAlteration, angleAlteration)) / 1000 * pi;
if (angle < 0) {
angle = angle + 2 * pi;
}
if (angle > 2 * pi) {
angle = angle - 2 * pi;
}
// Calculation of the flame's flickering
flickering = double(random(flickerDepth, 1000)) / 1000;
Serial.print("m:"); Serial.print(mode);
Serial.print(" d:"); Serial.print(deviation);
Serial.print(" w:"); Serial.print(angle);
Serial.print(" f:"); Serial.print(flickering);
Serial.print(" s:"); Serial.print(sensorValue);
Serial.print(" b:"); Serial.print(brightness);
Serial.print(" ");
// Calculation of the d values for the twelve NeoPixel
for (int i = 0; i < numPixels; i++) {
deviationArray[i] = (((cos(angleArray[i] - angle) / (2 / deviation)) + 0.5));
}
// Calculation of the flickering and brithness fpr the twelve NeoPixel
for (int i = 0; i < numPixels; i++) {
flameArray[i] = byte(deviationArray[i] * flickering * brightness);
}
// Calculation of the colors for the twelve NeoPixel
for (int i = 0; i < numPixels; i++) {
ring.setPixelColor(i, flameArray[i], flameArray[i] / 3.2, flameArray[i] / 25, flameArray[i] / 15);
//ring.setPixelColor(i, flameArray[i], flameArray[i] / 3.2, flameArray[i] / 25, 0);
}
ring.show();
for(int i = 0; i < numPixels; i++) {
Serial.print(deviationArray[i]); Serial.print(" ");
}
for(int i = 0; i < numPixels; i++) {
Serial.print(byte(flameArray[i] * 255)); Serial.print(" ");
}
Serial.println();
previousMillisCandle = currentMillis;
}
// Brightness control
if ((unsigned long)(currentMillis - previousMillisBrightness) >= intervalBrightness) {
/* Get a new sensor event */
sensors_event_t event;
tsl.getEvent(&event);
sensorValue = event.light;
brightness = int(sqrt(sensorValue * 100) * 2);
if (brightness < 192) {
brightness = 128;
}
if (brightness > 255) {
brightness = 255;
}
previousMillisBrightness = currentMillis;
}
}
Tags: #Arduino #NeoPixel #Windlicht