Has anyone modified the Kaleidoscope eyes code to go into "sleep" and only wake up say every 5 mins? I'm not sure how to do this and would appreciate any tips - would then save on battery life too.
Phil
Code mode for Kaleidoscope Eyes
Moderators: adafruit_support_bill, adafruit
Please be positive and constructive with your questions and comments.
- adafruit_support_mike
- Posts: 67454
- Joined: Thu Feb 11, 2010 2:51 pm
Re: Code mode for Kaleidoscope Eyes
The Gemma Space Invader Pendant project will probably give you some ideas: http://learn.adafruit.com/trinket-slash ... er-pendant
That uses a button to wake up the microcontroller, but the ATtiny85 has a built-in watchdog timer that can be used to wake the chip up after a specified amount of time. The details for that are on page 42 of the datasheet: http://www.atmel.com/Images/Atmel-2586- ... asheet.pdf
That uses a button to wake up the microcontroller, but the ATtiny85 has a built-in watchdog timer that can be used to wake the chip up after a specified amount of time. The details for that are on page 42 of the datasheet: http://www.atmel.com/Images/Atmel-2586- ... asheet.pdf
- philmonty
- Posts: 52
- Joined: Mon Jun 08, 2009 5:28 pm
Re: Code mode for Kaleidoscope Eyes
Thanks - not sure I need to close down the CPU, but that's definitely an option.
Any advice on how I just blank/turn off the neopixel rings ? I've tried looking through the examples and can't see an easy way. Given that it what sucks the power, couldn't I just turn off the rings and use a delay()?
My idea is that the neopixel rings just startup every five minutes, cycle for 30 seconds, and then sleep.
Phil
Any advice on how I just blank/turn off the neopixel rings ? I've tried looking through the examples and can't see an easy way. Given that it what sucks the power, couldn't I just turn off the rings and use a delay()?
My idea is that the neopixel rings just startup every five minutes, cycle for 30 seconds, and then sleep.
Phil
- adafruit_support_bill
- Posts: 88093
- Joined: Sat Feb 07, 2009 10:11 am
Re: Code mode for Kaleidoscope Eyes
If you just want to turn off the rings, you can call setBrightness(0);
- philmonty
- Posts: 52
- Joined: Mon Jun 08, 2009 5:28 pm
Re: Code mode for Kaleidoscope Eyes
Ok, so I have to admit I am a newbie Arduino programmer, but I am having a blast with the trinket.
I used the function that you suggested and it definitely turns off the rings perfectly. The problem I am having is that the delay(5000) doesn't seem to be doing anything:
I defined two new global uint8_t variables:
loopCount = 0,
maxLoops = 200;
pixels.show(); //existing code at end of main loop.
//code I stuck in
if (++loopCount > maxLoops) {
pixels.setBrightness(0); //turn rings off
delay(5000); //wait
pixels.setBrightness(brightness); //turn rings back on
loopCount =0; //reset loop counter
}
When this runs, the rings stay on without a delay. Hmmmmm. When I document out the "pixels.setBrightness(brightness);" the rings stay off after a few cycles, so I know it's getting into the loop. All I want to do is pause my goggles regularly...
Fun project!
I used the function that you suggested and it definitely turns off the rings perfectly. The problem I am having is that the delay(5000) doesn't seem to be doing anything:
I defined two new global uint8_t variables:
loopCount = 0,
maxLoops = 200;
pixels.show(); //existing code at end of main loop.
//code I stuck in
if (++loopCount > maxLoops) {
pixels.setBrightness(0); //turn rings off
delay(5000); //wait
pixels.setBrightness(brightness); //turn rings back on
loopCount =0; //reset loop counter
}
When this runs, the rings stay on without a delay. Hmmmmm. When I document out the "pixels.setBrightness(brightness);" the rings stay off after a few cycles, so I know it's getting into the loop. All I want to do is pause my goggles regularly...
Fun project!
- pburgess
- Posts: 4161
- Joined: Sun Oct 26, 2008 2:29 am
Re: Code mode for Kaleidoscope Eyes
Something like this might work:
It's not all super-efficient using sleep or anything, but should get the job done.
Code: Select all
unsigned long t;
void setup() {
// NORMAL SETUP STUFF HAPPENS HERE, then...
t = millis();
}
void loop() {
if((millis() - t) >= 30000L) { // 30 seconds elapsed?
for(int i=0; i<strip.numPixels(); i++) strip.setPixelColor(i, 0);
strip.show();
delay(270000L); // 4.5 minutes
t = millis();
}
// NORMAL ANIMATION CODE GOES HERE
}
- philmonty
- Posts: 52
- Joined: Mon Jun 08, 2009 5:28 pm
Re: Code mode for Kaleidoscope Eyes
Dude that's awesome. And the good thing I understand what you wrote so I have learnt something here.
Much appreciated senor
Much appreciated senor
- philmonty
- Posts: 52
- Joined: Mon Jun 08, 2009 5:28 pm
Re: Code mode for Kaleidoscope Eyes
Hate to keep asking questions, but I am trying to cycle the display between the Rainbow and ecto schemes, and the idea is to add more schemes over time. The trouble with the code I have written is that after the 5min break it just cycles back to Rainbow. I'd appreciate if someone can explain what I am missing - do I need to reinitialize the neopixel rings?
So... I moved EFFECT from a define to being a unit8_t with an initial definition:
unit8_t
EFFECT = RAINBOW; // Choose a visual effect from the names below
Then at the end of the code:
if((millis() - t) >= 30000L) { // 30 seconds elapsed?
for(int i=0; i<pixels.numPixels(); i++) pixels.setPixelColor(i, 0);
pixels.show();
delay(270000L); // 4.5 minutes
if (EFFECT == RAINBOW){ //cycle the effect
EFFECT = ECTO;
}
else {
EFFECT = RAINBOW;
}
t = millis();
}
So... I moved EFFECT from a define to being a unit8_t with an initial definition:
unit8_t
EFFECT = RAINBOW; // Choose a visual effect from the names below
Then at the end of the code:
if((millis() - t) >= 30000L) { // 30 seconds elapsed?
for(int i=0; i<pixels.numPixels(); i++) pixels.setPixelColor(i, 0);
pixels.show();
delay(270000L); // 4.5 minutes
if (EFFECT == RAINBOW){ //cycle the effect
EFFECT = ECTO;
}
else {
EFFECT = RAINBOW;
}
t = millis();
}
- philmonty
- Posts: 52
- Joined: Mon Jun 08, 2009 5:28 pm
Re: Code mode for Kaleidoscope Eyes
Ok, so I figured it out and now understand compiler instructions. I changed the #if to a normal if line, and it all works perfectly and just squeezes into the memory size (Binary sketch size: 5,248 bytes (of a 5,310 byte maximum) . For reference, here is the code:
Code: Select all
/*
NeoPixel Ring goggles sketch -- for steampunk, rave or Burning Man fashion!
Welding or costume goggles using 50mm round lenses can be outfitted with
a pair of Adafruit NeoPixel Rings: http://www.adafruit.com/product/1463
Please exercise common sense. These goggles emit a LOT of stray light and
should NOT BE WORN ON YOUR EYES. They're for fashion and costuming only,
for display on a hat or on your forehead.
Draws a spinning rainbow on both eyepieces. Not a Mac beachball, honest.
"Eyes" glance around and blink at random.
For 'reflected' colors (rainbows rotate in opposite directions, while eyes
look in same direction), connect the output of the first ring to the input
of the second. Or you can connect the inputs of both rings to the same
Arduino pin if that's easier -- the rainbows will both twirl in the same
direction in that case.
By default, pixel #0 (the first LED) on both rings should be at the TOP of
the goggles. Looking at the BACK of the board, pixel #0 is immediately
clockwise from the OUT connection. If a different pixel is at the top,
that's OK, the code can compensate (TOP_LED_FIRST and TOP_LED_SECOND below).
10/18/2013 - Mods by PhilM to run for 30 secs then sleep for 4.5mins, and
cycle through both ECTO and RAINBOW
*/
#include <Adafruit_NeoPixel.h>
#ifdef __AVR_ATtiny85__ // Trinket, Gemma, etc.
#include <avr/power.h>
#endif
#define PIN 4
#define TOP_LED_FIRST 0 // Change these if the first pixel is not
#define TOP_LED_SECOND 0 // at the top of the first and/or second ring.
#define RAINBOW 0
#define ECTO 1
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(32, PIN, NEO_GRB + NEO_KHZ800);
const int8_t PROGMEM
yCoord[] = { // Vertical coordinate of each pixel. First pixel is at top.
127,117,90,49,0,-49,-90,-117,-127,-117,-90,-49,0,49,90,117 },
sine[] = { // Brightness table for ecto effect
0, 28, 96, 164, 192, 164, 96, 28, 0, 28, 96, 164, 192, 164, 96, 28 };
// Eyelid vertical coordinates. Eyes shut slightly below center.
#define upperLidTop 130
#define upperLidBottom -45
#define lowerLidTop -40
#define lowerLidBottom -130
// Gamma correction improves appearance of midrange colors
const uint8_t PROGMEM gamma8[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3,
3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7,
7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12,
13, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20,
20, 21, 21, 22, 22, 23, 24, 24, 25, 25, 26, 27, 27, 28, 29, 29,
30, 31, 31, 32, 33, 34, 34, 35, 36, 37, 38, 38, 39, 40, 41, 42,
42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
58, 59, 60, 61, 62, 63, 64, 65, 66, 68, 69, 70, 71, 72, 73, 75,
76, 77, 78, 80, 81, 82, 84, 85, 86, 88, 89, 90, 92, 93, 94, 96,
97, 99,100,102,103,105,106,108,109,111,112,114,115,117,119,120,
122,124,125,127,129,130,132,134,136,137,139,141,143,145,146,148,
150,152,154,156,158,160,162,164,166,168,170,172,174,176,178,180,
182,184,186,188,191,193,195,197,199,202,204,206,209,211,213,215,
218,220,223,225,227,230,232,235,237,240,242,245,247,250,252,255
};
uint32_t
iColor[16][3]; // Background colors for eyes
int16_t
hue = 0; // Initial hue around perimeter (0-1535)
uint8_t
iBrightness[16], // Brightness map -- eye colors get scaled by these
brightness = 220, // Global brightness (0-255)
blinkFrames = 5, // Speed of current blink
blinkCounter = 30, // Countdown to end of next blink
eyePos = 192, // Current 'resting' eye (pupil) position
newEyePos = 192, // Next eye position when in motion
gazeCounter = 75, // Countdown to next eye movement
gazeFrames = 50, // Duration of eye movement (smaller = faster)
EFFECT = ECTO; // Choose a visual effect from the names below
int8_t
eyeMotion = 0; // Distance from prior to new position
unsigned long t;
void setup() {
#ifdef __AVR_ATtiny85__ // Trinket, Gemma, etc.
if(F_CPU == 16000000) clock_prescale_set(clock_div_1);
// Seed random number generator from an unused analog input:
randomSeed(analogRead(2));
#else
randomSeed(analogRead(A0));
#endif
t = millis();
pixels.begin();
}
void loop() {
uint8_t i, r, g, b, a, c, inner, outer, ep;
int y1, y2, y3, y4, h;
int8_t y;
// Draw eye background colors
if (EFFECT == RAINBOW) {
// This renders a glotating rainbow...a WAY overdone LED effect but
// does show the color gamut nicely.
for(h=hue, i=0; i<16; i++, h += 96) {
a = h;
switch((h >> 8) % 6) {
case 0: iColor[i][0] = 255; iColor[i][1] = a; iColor[i][2] = 0; break;
case 1: iColor[i][0] = ~a; iColor[i][1] = 255; iColor[i][2] = 0; break;
case 2: iColor[i][0] = 0; iColor[i][1] = 255; iColor[i][2] = a; break;
case 3: iColor[i][0] = 0; iColor[i][1] = ~a; iColor[i][2] = 255; break;
case 4: iColor[i][0] = a; iColor[i][1] = 0; iColor[i][2] = 255; break;
case 5: iColor[i][0] = 255; iColor[i][1] = 0; iColor[i][2] = ~a; break;
}
}
hue += 7;
if(hue >= 1536) hue -= 1536;
}
else if (EFFECT == ECTO)
{
// A steampunk aesthetic might fare better with this more subdued effect.
// Etherial green glow with just a little animation for visual spice.
a = (hue >> 4) & 15;
c = hue & 15;
for(i=0; i<16; i++) {
b = (a + 1) & 15;
iColor[i][1] = 255; // Predominantly green
iColor[i][0] = (pgm_read_byte(&sine[a]) * (16 - c) +
pgm_read_byte(&sine[b]) * c ) >> 4;
iColor[i][2] = iColor[i][0] >> 1;
a = b;
}
hue -= 3;
}
// Render current blink (if any) into brightness map
if(blinkCounter <= blinkFrames * 2) { // In mid-blink?
if(blinkCounter > blinkFrames) { // Eye closing
outer = blinkFrames * 2 - blinkCounter;
inner = outer + 1;
} else { // Eye opening
inner = blinkCounter;
outer = inner - 1;
}
y1 = upperLidTop - (upperLidTop - upperLidBottom) * outer / blinkFrames;
y2 = upperLidTop - (upperLidTop - upperLidBottom) * inner / blinkFrames;
y3 = lowerLidBottom + (lowerLidTop - lowerLidBottom) * inner / blinkFrames;
y4 = lowerLidBottom + (lowerLidTop - lowerLidBottom) * outer / blinkFrames;
for(i=0; i<16; i++) {
y = pgm_read_byte(&yCoord[i]);
if(y > y1) { // Above top lid
iBrightness[i] = 0;
} else if(y > y2) { // Blur edge of top lid in motion
iBrightness[i] = brightness * (y1 - y) / (y1 - y2);
} else if(y > y3) { // In eye
iBrightness[i] = brightness;
} else if(y > y4) { // Blur edge of bottom lid in motion
iBrightness[i] = brightness * (y - y4) / (y3 - y4);
} else { // Below bottom lid
iBrightness[i] = 0;
}
}
} else { // Not in blink -- set all 'on'
memset(iBrightness, brightness, sizeof(iBrightness));
}
if(--blinkCounter == 0) { // Init next blink?
blinkFrames = random(4, 8);
blinkCounter = blinkFrames * 2 + random(5, 180);
}
// Calculate current eye movement, possibly init next one
if(--gazeCounter <= gazeFrames) { // Is pupil in motion?
ep = newEyePos - eyeMotion * gazeCounter / gazeFrames; // Current pos.
if(gazeCounter == 0) { // Last frame?
eyePos = newEyePos; // Current position = new pos
newEyePos = random(16) * 16; // New pos. (always pixel center)
eyeMotion = newEyePos - eyePos; // Distance to move
gazeFrames = random(10, 20); // Duration of movement
gazeCounter = random(gazeFrames, 130); // Count to END of next movement
}
} else ep = eyePos; // Not moving -- fixed gaze
// Draw pupil -- 2 pixels wide, but sup-pixel positioning may span 3.
a = ep >> 4; // First candidate
b = (a + 1) & 0x0F; // 1 pixel CCW of a
c = (a + 2) & 0x0F; // 2 pixels CCW of a
i = ep & 0x0F; // Fraction of 'c' covered (0-15)
iBrightness[a] = (iBrightness[a] * i ) >> 4;
iBrightness[b] = 0;
iBrightness[c] = (iBrightness[c] * (16 - i)) >> 4;
// Merge iColor with iBrightness, issue to NeoPixels
for(i=0; i<16; i++) {
a = iBrightness[i] + 1;
// First eye
r = iColor[i][0]; // Initial background RGB color
g = iColor[i][1];
b = iColor[i][2];
if(a) {
r = (r * a) >> 8; // Scale by brightness map
g = (g * a) >> 8;
b = (b * a) >> 8;
}
pixels.setPixelColor(((i + TOP_LED_FIRST) & 15),
pgm_read_byte(&gamma8[r]), // Gamma correct and set pixel
pgm_read_byte(&gamma8[g]),
pgm_read_byte(&gamma8[b]));
// Second eye uses the same colors, but reflected horizontally.
// The same brightness map is used, but not reflected (same left/right)
r = iColor[15 - i][0];
g = iColor[15 - i][1];
b = iColor[15 - i][2];
if(a) {
r = (r * a) >> 8;
g = (g * a) >> 8;
b = (b * a) >> 8;
}
pixels.setPixelColor(16 + ((i + TOP_LED_SECOND) & 15),
pgm_read_byte(&gamma8[r]),
pgm_read_byte(&gamma8[g]),
pgm_read_byte(&gamma8[b]));
}
pixels.show();
delay(30);
if((millis() - t) >= 30000L) { // 30 seconds elapsed?
for(int i=0; i<pixels.numPixels(); i++) pixels.setPixelColor(i, 0);
pixels.show();
delay(270000L); // 4.5 minutes
if (EFFECT == RAINBOW){ //cycle the effect
EFFECT = ECTO;
}
else {
EFFECT = RAINBOW;
}
t = millis();
}
}
- TheExpertNoob
- Posts: 15
- Joined: Sun Feb 15, 2015 8:03 pm
Re: Code mode for Kaleidoscope Eyes
I know this is an old thread, but this is what I have been working on. Its currently too big to fit on the trinket as is, but you can flash the trinket with ArduinoISP as an ATtiny85 which I have found easier and less cumbersome.
Also, Discovered this by accident today, Its a neat effect. Replace the similar lines under the "ECTO" effect.
Also, Discovered this by accident today, Its a neat effect. Replace the similar lines under the "ECTO" effect.
Code: Select all
iColor[i][0] = (pgm_read_byte(&sine[a]) * ((16 - c) - 105) + pgm_read_byte(&sine[b]) * (c - 105)) >> 4; //red
iColor[i][1] = 255; //green
iColor[i][2] = (pgm_read_byte(&sine[a]) * ((16 - c) - 55) + pgm_read_byte(&sine[b]) * (c - 55)) >> 4; //blue
Code: Select all
#include <Adafruit_NeoPixel.h>
#ifdef __AVR_ATtiny85__ // Trinket, Gemma, etc.
#include <avr/power.h>
#endif
#define PIN 4
#define TOP_LED_FIRST 0 // Change these if the first pixel is not
#define TOP_LED_SECOND 0 // at the top of the first and/or second ring.
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(32, PIN, NEO_GRB + NEO_KHZ800);
const int8_t PROGMEM
yCoord[] = { // Vertical coordinate of each pixel. First pixel is at top.
127,117,90,49,0,-49,-90,-117,-127,-117,-90,-49,0,49,90,117 },
sine[] = { // Brightness table for ecto effect
0, 28, 96, 164, 192, 164, 96, 28, 0, 28, 96, 164, 192, 164, 96, 28 };
// Eyelid vertical coordinates. Eyes shut slightly below center.
#define upperLidTop 130
#define upperLidBottom -45
#define lowerLidTop -40
#define lowerLidBottom -130
// Gamma correction improves appearance of midrange colors
const uint8_t PROGMEM gamma8[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3,
3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7,
7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12,
13, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20,
20, 21, 21, 22, 22, 23, 24, 24, 25, 25, 26, 27, 27, 28, 29, 29,
30, 31, 31, 32, 33, 34, 34, 35, 36, 37, 38, 38, 39, 40, 41, 42,
42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
58, 59, 60, 61, 62, 63, 64, 65, 66, 68, 69, 70, 71, 72, 73, 75,
76, 77, 78, 80, 81, 82, 84, 85, 86, 88, 89, 90, 92, 93, 94, 96,
97, 99,100,102,103,105,106,108,109,111,112,114,115,117,119,120,
122,124,125,127,129,130,132,134,136,137,139,141,143,145,146,148,
150,152,154,156,158,160,162,164,166,168,170,172,174,176,178,180,
182,184,186,188,191,193,195,197,199,202,204,206,209,211,213,215,
218,220,223,225,227,230,232,235,237,240,242,245,247,250,252,255
};
uint32_t
iColor[16][3]; // Background colors for eyes
int16_t
hue = 0; // Initial hue around perimeter (0-1535)
uint8_t
iBrightness[16], // Brightness map -- eye colors get scaled by these
brightness = 170, // Global brightness (0-255)
blinkFrames = 5, // Speed of current blink
blinkCounter = 30, // Countdown to end of next blink
eyePos = 192, // Current 'resting' eye (pupil) position
newEyePos = 192, // Next eye position when in motion
gazeCounter = 75, // Countdown to next eye movement
gazeFrames = 50; // Duration of eye movement (smaller = faster)
int8_t
eyeMotion = 0; // Distance from prior to new position
const int buttonPin = 3; // the pin that the pushbutton is attached to
int buttonPushCounter = 0; // counter for the number of button presses
int buttonState = 0; // current state of the button
int lastButtonState = 0; // previous state of the button
void setup() {
#ifdef __AVR_ATtiny85__ // Trinket, Gemma, etc.
if(F_CPU == 16000000) clock_prescale_set(clock_div_1);
// Seed random number generator from an unused analog input:
randomSeed(analogRead(2));
#else
randomSeed(analogRead(A0));
#endif
pinMode(buttonPin, INPUT); // initialize the button pin as a input
pixels.begin();
}
void loop() {
uint8_t i, r, g, b, a, c, inner, outer, ep;
int y1, y2, y3, y4, h;
int8_t y;
buttonState = digitalRead(buttonPin); // read the pushbutton input pin:
if (buttonState != lastButtonState) { // compare the buttonState to its previous state
if (buttonState == LOW) { // if the state has changed, increment the counter
buttonPushCounter++;
}
}
lastButtonState = buttonState;
a = (hue >> 4) & 15;
c = hue & 15;
for(i=0; i<16; i++) {
b = (a + 1) & 15;
switch (buttonPushCounter) {
case 0: //rainbow
for(h=hue, i=0; i<16; i++, h += 96) {
a = h;
switch((h >> 8) % 6) {
case 0: iColor[i][0] = 255; iColor[i][1] = a; iColor[i][2] = 0; break;
case 1: iColor[i][0] = ~a; iColor[i][1] = 255; iColor[i][2] = 0; break;
case 2: iColor[i][0] = 0; iColor[i][1] = 255; iColor[i][2] = a; break;
case 3: iColor[i][0] = 0; iColor[i][1] = ~a; iColor[i][2] = 255; break;
case 4: iColor[i][0] = a; iColor[i][1] = 0; iColor[i][2] = 255; break;
case 5: iColor[i][0] = 255; iColor[i][1] = 0; iColor[i][2] = ~a; break;
}
}
hue += 7;
if(hue >= 1536) hue -= 1536;
break;
case 1: //red
iColor[i][0] = 255; //red
iColor[i][1] = (pgm_read_byte(&sine[a]) * (16 - c) + pgm_read_byte(&sine[b]) * c) >> 4; //green
iColor[i][2] = (pgm_read_byte(&sine[a]) * (16 - c) + pgm_read_byte(&sine[b]) * c) >> 4; //blue
break;
case 2: //green
iColor[i][0] = (pgm_read_byte(&sine[a]) * (16 - c) + pgm_read_byte(&sine[b]) * c) >> 4; //red
iColor[i][1] = 255; //green
iColor[i][2] = (pgm_read_byte(&sine[a]) * (16 - c) + pgm_read_byte(&sine[b]) * c) >> 4; //blue
break;
case 3: //blue
iColor[i][0] = (pgm_read_byte(&sine[a]) * (16 - c) + pgm_read_byte(&sine[b]) * c) >> 4; //red
iColor[i][1] = (pgm_read_byte(&sine[a]) * (16 - c) + pgm_read_byte(&sine[b]) * c) >> 4; //green
iColor[i][2] = 255; //blue
break;
case 4: //yellow
iColor[i][0] = 255; //red
iColor[i][1] = 255; //green
iColor[i][2] = (pgm_read_byte(&sine[a]) * (16 - c) + pgm_read_byte(&sine[b]) * c) >> 4; //blue
break;
case 5: //teal
iColor[i][0] = (pgm_read_byte(&sine[a]) * (16 - c) + pgm_read_byte(&sine[b]) * c) >> 4; //red
iColor[i][1] = 255; //green
iColor[i][2] = 255; //blue
break;
case 6: //pink
iColor[i][0] = 255; //red
iColor[i][1] = (pgm_read_byte(&sine[a]) * (16 - c) + pgm_read_byte(&sine[b]) * c) >> 4; //green
iColor[i][2] = 255; //blue
break;
case 7: //police
iColor[i][0] = (pgm_read_byte(&sine[a]) * (16 - c) + pgm_read_byte(&sine[b]) * c) >> 4; //red
iColor[i][1] = 0; //green
iColor[i][2] = ~(pgm_read_byte(&sine[a]) * (16 - c) + pgm_read_byte(&sine[b]) * c) >> 4; //blue
break;
case 8: //auburn
iColor[i][0] = (pgm_read_byte(&sine[a]) * (16 - c) + pgm_read_byte(&sine[b]) * c) >> 4; //red
iColor[i][1] = (pgm_read_byte(&sine[a]) * ((16 - c) - 128) + pgm_read_byte(&sine[b]) * (c - 128)) >> 4; //green
iColor[i][2] = ~(pgm_read_byte(&sine[a]) * (16 - c) + pgm_read_byte(&sine[b]) * c) >> 4; //blue
break;
default:
buttonPushCounter = 0;
iColor[i][0] = 0; //red
iColor[i][1] = 0; //green
iColor[i][2] = 0; //blue
}
a = b;
}
hue -= 3;
// Render current blink (if any) into brightness map
if(blinkCounter <= blinkFrames * 2) { // In mid-blink?
if(blinkCounter > blinkFrames) { // Eye closing
outer = blinkFrames * 2 - blinkCounter;
inner = outer + 1;
} else { // Eye opening
inner = blinkCounter;
outer = inner - 1;
}
y1 = upperLidTop - (upperLidTop - upperLidBottom) * outer / blinkFrames;
y2 = upperLidTop - (upperLidTop - upperLidBottom) * inner / blinkFrames;
y3 = lowerLidBottom + (lowerLidTop - lowerLidBottom) * inner / blinkFrames;
y4 = lowerLidBottom + (lowerLidTop - lowerLidBottom) * outer / blinkFrames;
for(i=0; i<16; i++) {
y = pgm_read_byte(&yCoord[i]);
if(y > y1) { // Above top lid
iBrightness[i] = 0;
} else if(y > y2) { // Blur edge of top lid in motion
iBrightness[i] = brightness * (y1 - y) / (y1 - y2);
} else if(y > y3) { // In eye
iBrightness[i] = brightness;
} else if(y > y4) { // Blur edge of bottom lid in motion
iBrightness[i] = brightness * (y - y4) / (y3 - y4);
} else { // Below bottom lid
iBrightness[i] = 0;
}
}
} else { // Not in blink -- set all 'on'
memset(iBrightness, brightness, sizeof(iBrightness));
}
if(--blinkCounter == 0) { // Init next blink?
blinkFrames = random(4, 8);
blinkCounter = blinkFrames * 2 + random(5, 180);
}
// Calculate current eye movement, possibly init next one
if(--gazeCounter <= gazeFrames) { // Is pupil in motion?
ep = newEyePos - eyeMotion * gazeCounter / gazeFrames; // Current pos.
if(gazeCounter == 0) { // Last frame?
eyePos = newEyePos; // Current position = new pos
newEyePos = random(16) * 16; // New pos. (always pixel center)
eyeMotion = newEyePos - eyePos; // Distance to move
gazeFrames = random(10, 20); // Duration of movement
gazeCounter = random(gazeFrames, 130); // Count to END of next movement
}
} else ep = eyePos; // Not moving -- fixed gaze
// Draw pupil -- 2 pixels wide, but sup-pixel positioning may span 3.
a = ep >> 4; // First candidate
b = (a + 1) & 0x0F; // 1 pixel CCW of a
c = (a + 2) & 0x0F; // 2 pixels CCW of a
i = ep & 0x0F; // Fraction of 'c' covered (0-15)
iBrightness[a] = (iBrightness[a] * i ) >> 4;
iBrightness[b] = 0;
iBrightness[c] = (iBrightness[c] * (16 - i)) >> 4;
// Merge iColor with iBrightness, issue to NeoPixels
for(i=0; i<16; i++) {
a = iBrightness[i] + 1;
// First eye
r = iColor[i][0]; // Initial background RGB color
g = iColor[i][1];
b = iColor[i][2];
if(a) {
r = (r * a) >> 8; // Scale by brightness map
g = (g * a) >> 8;
b = (b * a) >> 8;
}
pixels.setPixelColor(((i + TOP_LED_FIRST) & 15),
pgm_read_byte(&gamma8[r]), // Gamma correct and set pixel
pgm_read_byte(&gamma8[g]),
pgm_read_byte(&gamma8[b]));
// Second eye uses the same colors, but reflected horizontally.
// The same brightness map is used, but not reflected (same left/right)
r = iColor[15 - i][0];
g = iColor[15 - i][1];
b = iColor[15 - i][2];
if(a) {
r = (r * a) >> 8;
g = (g * a) >> 8;
b = (b * a) >> 8;
}
pixels.setPixelColor(16 + ((i + TOP_LED_SECOND) & 15),
pgm_read_byte(&gamma8[r]),
pgm_read_byte(&gamma8[g]),
pgm_read_byte(&gamma8[b]));
}
pixels.show();
delay(15);
}
Please be positive and constructive with your questions and comments.