Created
November 24, 2012 01:29
-
-
Save zacharyvoase/4137977 to your computer and use it in GitHub Desktop.
Rolling, fading LEDs, inspired by http://floodmagazine.com/2010/10/14/apples-attention-to-detail/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define E 2.71828182846 | |
// The ordered list of output pins, and the length thereof. | |
int pins[] = {3, 5, 6, 9, 10}; | |
int pins_length = 5; | |
// This needs to be close to 30ms to be perceived as smooth (NTSC = 33.36ms) | |
int refresh_interval = 30; | |
// Intervals are useful for explicitly declaring the valid range for a value, | |
// and converting values between ranges (e.g. 0 - 1.0 => 0 - 255). | |
struct Interval { | |
float low; | |
float high; | |
}; | |
// Map a value from one Interval to another. | |
float map_interval(float value, struct Interval source, struct Interval target) { | |
// normed will be a number between 0.0 - 1.0 inclusive. | |
double normed = (value - source.low) / (source.high - source.low); | |
return (normed * (target.high - target.low)) + target.low; | |
} | |
// Get an integer, modulo an interval. | |
// e.g. modulo_interval_i(22, (0..8)) => 6. | |
int modulo_interval_i(int value, struct Interval interval) { | |
while (value > interval.high) { | |
value -= (interval.high - interval.low); | |
} | |
return value; | |
} | |
// Same as `modulo_interval_i()`, but for floats. | |
float modulo_interval_f(float value, struct Interval interval) { | |
while (value > interval.high) { | |
value -= (interval.high - interval.low); | |
} | |
return value; | |
} | |
// Our clock ticks from 0 to 133, at 30ms intervals, for a total cycle length of ~4s. | |
Interval clockInterval = {0, 133}; | |
// We'll map the clock onto the x interval (-2, 2) of the PDF of a normal distribution. | |
float stddev = 0.7; | |
Interval normXInterval = {-2, 2}; | |
// The output of the normal PDF is in the y interval (0, 0.5699). Use 0.6 to be safe. | |
Interval normYInterval = {0, 0.6}; | |
// The 'analog' value of the pin (therefore the brightness of the LED) will be an 8-bit integer. | |
// You can control the global brightness floor/ceiling by changing this. | |
Interval brightnessInterval = {0, 255}; | |
// -- You shouldn't need to change anything below this line to get it to work. -- | |
void setup() { | |
} | |
// PDF of a normal distribution. | |
float normdist(float avg, float stddev, float x) { | |
return (1 / (stddev * sqrt(2 * PI))) * ( | |
pow(E, -0.5 * pow(((x - avg) / stddev), 2))); | |
} | |
// Get the brightness for a pin at a given time. The pin is provided as an index into `pins`, | |
// not the pin number itself. | |
int fade_value(int pin_index, int clock) { | |
int pin_phase = pin_index * (clockInterval.high - clockInterval.low) / pins_length; | |
clock = modulo_interval_i(clock + pin_phase, clockInterval); | |
return map_interval(normdist(0, stddev, map_interval(clock, clockInterval, normXInterval)), | |
normYInterval, brightnessInterval); | |
} | |
void loop() { | |
for (int clock = clockInterval.low; clock <= clockInterval.high; clock += 1) { | |
for (int i = 0; i < pins_length; i += 1) { | |
analogWrite(pins[i], fade_value(i, clock)); | |
} | |
delay(refresh_interval); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment