Welcome to Synthiam!

Program robots using technologies created from industry experts. ARC is our free-to-use robot programming software that makes features like vision recognition, navigation and artificial intelligence easy.

Get Started
Asked — Edited

Neopixel Tutorial

Trying to work through the neopixel tutorial. Is this working for others? I can't get the Arduino sketch to compile with new and old versions of IDE.

Is this working for others or is the problem on my end.

Thanks

PRO
USA
#19  
I haven't had any success Bob. I can compile the sketch from the reference thread and upload it. Once I did the neopixel quit running a previous script and went dark. Do you recall what the state of the ring was when the program initializes? Is it off? I don't know if the problem is with the Arduino and sketch or trying to activate it serially
#20  
I don't think it matters what state the ring is in when you activate it. I have found that I need to connect the EZB first then turn on the ring. If the Arduino is powered up before my EZB is connected it prevents my EZB from connecting. Try doing it in that order and see what happens.
PRO
USA
#21  
No results with booting up in that order. When I mentioned initial state, I meant any lights or patterns on. Mine just stays dark. Trying to determine if the problem is Arduino to neo. I don't think so because I can run the adafruit examples through it.

Also, just to confirm, I am cutting and pasting the examples into the scripts I make with the script manager then running them. Is that the right way to activate it?
#22  
I just hooked up an old arduino that had the sketch on it and tested the neopixel ring. It works.

Now to go through the process of dumping the sketch from the tuto to it to see if I can get it to work. If not, I have this sketch backed up to my NAS and will get it for you.
#23  
First, let me document the wiring.

From EZ-B
Ground on D5 to com port ground on Arduino
Signal on D5 to RX on Arduino

Power regulator- This is for the Mini Pro. Yours may be different depending on the arduino. The Neopixel needs 5V though.
5v to Neopixel ring +5v_PWR pin
5v to Arduino 5v pin
ground to Neopixel ring GND pin
ground to Arduino GND pin on Power side of the board

Arduino
Pin D6 to Input Pin on Neopixel Ring
#24  
Software setup -
Installed Arduino 1.6.3 from https://www.arduino.cc/download_handler.php?f=/arduino-1.6.3-windows.exe

- [EDIT] This script has been tested with version 1.1.1 of the Adafruit NeoPixel Library and works. This is the latest version of this library at the time of this writing so, you don't need to do this part. If you don't have the library installed, you can get it through the Arduino software or download it from GitHub at https://github.com/adafruit/Adafruit_NeoPixel

I am using the Adafruit NeoPixel by Adafruit version 1.0.4 library.
Adafruit_NeoPixel.zip

You will need to unzip the contents of the zip into your Arduino\libraries folder.
[/EDIT]

The code verifies. I also verified it with Arduino Uno (I use mini pro's) and it compiled.

Code:


Global variables use 259 bytes (12%) of dynamic memory, leaving 1,789 bytes for local variables. Maximum is 2,048 bytes.


Here is my sketch that I use. NeoPixelRingSerial2.zip
The zip file contains the sketch just in case a copy and paste doesn't work.

Code:


/* real time Serial Controlled Neopixel Ring -- Code not tested yet
/
/ Serial Commands
/ Cr1,g1,b1 - Set whole Ring to same color specified by r1,g1,b1
/ Rt,d - Rainbow with interval t and direction d
/ Tr1,g1,b1,r2,g2,b2,t,d - Theater Chase between color r1,g1,b1 and color r2,g2,b2 with interval t and direction d
/ Wr1,g1,b1,t,d - Color Wipe in color r1,g1,b1 with interval t and direction d
/ Fr1,g1,b1,r2,g2,b2,s,t,d - Fade between color r1,g1,b1 and color r2,g2,b2 in s steps with interval t and direction d
/ Sr1,g1,b1,t - Scanner with color specified by r1,g1,b1 and interval t
/ Pp,r1,g1,b1 - Set individual pixel p to color specified by r1,g1,b1
/
/ p = pixel number
/ r1 = 1st color red values 0 to 255
/ g1 = 1st color greern values 0 to 255
/ b1 = 1st color blue values 0 to 255
/ r2 = 2nd color red values 0 to 255
/ g2 = 2nd color greern values 0 to 255
/ b2 = 2nd color blue values 0 to 255
/ s = number of steps
/ t = interval time values 0 to 255
/ d = direction 0 = Forward 1 = Backward
*/

#include <Adafruit_NeoPixel.h>

// Pattern types supported:
enum pattern { NONE, RAINBOW_CYCLE, THEATER_CHASE, COLOR_WIPE, SCANNER, FADE };
// Patern directions supported:
enum direction { FORWARD, REVERSE };

// NeoPattern Class - derived from the Adafruit_NeoPixel class
class NeoPatterns : public Adafruit_NeoPixel
{
public:

// Member Variables:
pattern ActivePattern; // which pattern is running
direction Direction; // direction to run the pattern

unsigned long Interval; // milliseconds between updates
unsigned long lastUpdate; // last update of position

uint32_t Color1, Color2; // What colors are in use
uint16_t TotalSteps; // total number of steps in the pattern
uint16_t Index; // current step within the pattern

void (*OnComplete)(); // Callback on completion of pattern

// Constructor - calls base-class constructor to initialize strip
NeoPatterns(uint16_t pixels, uint8_t pin, uint8_t type, void (*callback)())
:Adafruit_NeoPixel(pixels, pin, type)
{
OnComplete = callback;
}

// Update the pattern
void Update()
{
if((millis() - lastUpdate) > Interval) // time to update
{
lastUpdate = millis();
switch(ActivePattern)
{
case RAINBOW_CYCLE:
RainbowCycleUpdate();
break;
case THEATER_CHASE:
TheaterChaseUpdate();
break;
case COLOR_WIPE:
ColorWipeUpdate();
break;
case SCANNER:
ScannerUpdate();
break;
case FADE:
FadeUpdate();
break;
default:
break;
}
}
}

// Increment the Index and reset at the end
void Increment()
{
if (Direction == FORWARD)
{
Index++;
if (Index >= TotalSteps)
{
Index = 0;
if (OnComplete != NULL)
{
OnComplete(); // call the comlpetion callback
}
}
}
else // Direction == REVERSE
{
--Index;
if (Index <= 0)
{
Index = TotalSteps-1;
if (OnComplete != NULL)
{
OnComplete(); // call the comlpetion callback
}
}
}
}

// Reverse pattern direction
void Reverse()
{
if (Direction == FORWARD)
{
Direction = REVERSE;
Index = TotalSteps-1;
}
else
{
Direction = FORWARD;
Index = 0;
}
}

// Initialize for a RainbowCycle
void RainbowCycle(uint8_t interval, direction dir = FORWARD)
{
ActivePattern = RAINBOW_CYCLE;
Interval = interval;
TotalSteps = 255;
Index = 0;
Direction = dir;
}

// Update the Rainbow Cycle Pattern
void RainbowCycleUpdate()
{
for(int i=0; i< numPixels(); i++)
{
setPixelColor(i, Wheel(((i * 256 / numPixels()) + Index) & 255));
}
show();
Increment();
}

// Initialize for a Theater Chase
void TheaterChase(uint32_t color1, uint32_t color2, uint8_t interval, direction dir = FORWARD)
{
ActivePattern = THEATER_CHASE;
Interval = interval;
TotalSteps = numPixels();
Color1 = color1;
Color2 = color2;
Index = 0;
Direction = dir;
}

// Update the Theater Chase Pattern
void TheaterChaseUpdate()
{
for(int i=0; i< numPixels(); i++)
{
if ((i + Index) % 3 == 0)
{
setPixelColor(i, Color1);
}
else
{
setPixelColor(i, Color2);
}
}
show();
Increment();
}

// Initialize for a ColorWipe
void ColorWipe(uint32_t color, uint8_t interval, direction dir = FORWARD)
{
ActivePattern = COLOR_WIPE;
Interval = interval;
TotalSteps = numPixels();
Color1 = color;
Index = 0;
Direction = dir;
}

// Update the Color Wipe Pattern
void ColorWipeUpdate()
{
setPixelColor(Index, Color1);
show();
Increment();
}

// Initialize for a SCANNNER
void Scanner(uint32_t color1, uint8_t interval)
{
ActivePattern = SCANNER;
Interval = interval;
TotalSteps = (numPixels() - 1) * 2;
Color1 = color1;
Index = 0;
}

// Update the Scanner Pattern
void ScannerUpdate()
{
for (int i = 0; i < numPixels(); i++)
{
if (i == Index) // Scan Pixel to the right
{
setPixelColor(i, Color1);
}
else if (i == TotalSteps - Index) // Scan Pixel to the left
{
setPixelColor(i, Color1);
}
else // Fading tail
{
setPixelColor(i, DimColor(getPixelColor(i)));
}
}
show();
Increment();
}

// Initialize for a Fade
void Fade(uint32_t color1, uint32_t color2, uint16_t steps, uint8_t interval, direction dir = FORWARD)
{
ActivePattern = FADE;
Interval = interval;
TotalSteps = steps;
Color1 = color1;
Color2 = color2;
Index = 0;
Direction = dir;
}

// Update the Fade Pattern
void FadeUpdate()
{
// Calculate linear interpolation between Color1 and Color2
// Optimise order of operations to minimize truncation error
uint8_t red = ((Red(Color1) * (TotalSteps - Index)) + (Red(Color2) * Index)) / TotalSteps;
uint8_t green = ((Green(Color1) * (TotalSteps - Index)) + (Green(Color2) * Index)) / TotalSteps;
uint8_t blue = ((Blue(Color1) * (TotalSteps - Index)) + (Blue(Color2) * Index)) / TotalSteps;

ColorSet(Color(red, green, blue));
show();
Increment();
}

// Calculate 50% dimmed version of a color (used by ScannerUpdate)
uint32_t DimColor(uint32_t color)
{
// Shift R, G and B components one bit to the right
uint32_t dimColor = Color(Red(color) >> 1, Green(color) >> 1, Blue(color) >> 1);
return dimColor;
}

// Set all pixels to a color (synchronously)
void ColorSet(uint32_t color)
{
for (int i = 0; i < numPixels(); i++)
{
setPixelColor(i, color);
}
show();
}

// Returns the Red component of a 32-bit color
uint8_t Red(uint32_t color)
{
return (color >> 16) & 0xFF;
}

// Returns the Green component of a 32-bit color
uint8_t Green(uint32_t color)
{
return (color >> 8) & 0xFF;
}

// Returns the Blue component of a 32-bit color
uint8_t Blue(uint32_t color)
{
return color & 0xFF;
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos)
{
WheelPos = 255 - WheelPos;
if(WheelPos < 85)
{
return Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
else if(WheelPos < 170)
{
WheelPos -= 85;
return Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
else
{
WheelPos -= 170;
return Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
}
};

// Define some NeoPatterns for the two rings and the stick
// as well as some completion routines
NeoPatterns Ring1(16, 6, NEO_GRB + NEO_KHZ800, &Ring1Complete);

int red1 = 0; // red value
int green1 = 34; // green value
int blue1 = 12; // blue value
int red2 = 0; // red value
int green2 = 34; // green value
int blue2 = 12; // blue value
int my_pixel = 0; // pixel number
int s = 5; // step value
int t = 10; // interval time value
int d = 0; // direction indicator 0= Forward 1 = Backward

// Initialize everything and prepare to start
void setup()
{
Serial.begin(9600);
Serial.setTimeout(10); // set serial timeout

// Initialize all the pixelStrips
Ring1.begin();
Ring1.ColorSet(Ring1.Color(0, 0, 0));
}

// Main loop
void loop()
{
int inchar;

if (Serial.available() > 0) {
inchar = Serial.read();
if ( inchar == 'C') { // string should start with C
red1 = Serial.parseInt(); // then an ASCII number for red
green1 = Serial.parseInt(); // then an ASCII number for green
blue1 = Serial.parseInt(); // then an ASCII number for blue
Ring1.ActivePattern = NONE;
Ring1.ColorSet(Ring1.Color(red1, green1, blue1));
}
if ( inchar == 'R') { // string should start with R
t = Serial.parseInt(); // then an ASCII number for interval
d = Serial.parseInt(); // then an ASCII number for direction
if (d ==0) {
Ring1.RainbowCycle(t, FORWARD);
} else {
Ring1.RainbowCycle(t, REVERSE);
}
}
if ( inchar == 'F') { // string should start with F
red1 = Serial.parseInt(); // then an ASCII number for red
green1 = Serial.parseInt(); // then an ASCII number for green
blue1 = Serial.parseInt(); // then an ASCII number for blue
red2 = Serial.parseInt(); // then an ASCII number for red
green2 = Serial.parseInt(); // then an ASCII number for green
blue2 = Serial.parseInt(); // then an ASCII number for blue
s = Serial.parseInt(); // then an ASCII number for steps
t = Serial.parseInt(); // then an ASCII number for interval
d = Serial.parseInt(); // then an ASCII number for direction
if (d ==0) {
Ring1.Fade(Ring1.Color(red1, green1, blue1), Ring1.Color(red2, green2, blue2), s, t, FORWARD);
} else {
Ring1.Fade(Ring1.Color(red1, green1, blue1), Ring1.Color(red2, green2, blue2), s, t, REVERSE);
}
}
if ( inchar == 'T') { // string should start with T
red1 = Serial.parseInt(); // then an ASCII number for red
green1 = Serial.parseInt(); // then an ASCII number for green
blue1 = Serial.parseInt(); // then an ASCII number for blue
red2 = Serial.parseInt(); // then an ASCII number for red
green2 = Serial.parseInt(); // then an ASCII number for green
blue2 = Serial.parseInt(); // then an ASCII number for blue
t = Serial.parseInt(); // then an ASCII number for interval
d = Serial.parseInt(); // then an ASCII number for direction
if (d ==0) {
Ring1.TheaterChase(Ring1.Color(red1, green1, blue1), Ring1.Color(red2, green2, blue2), t, FORWARD);
} else {
Ring1.TheaterChase(Ring1.Color(red1, green1, blue1), Ring1.Color(red2, green2, blue2), t, REVERSE);
}
}
if ( inchar == 'W') { // string should start with W
red1 = Serial.parseInt(); // then an ASCII number for red
green1 = Serial.parseInt(); // then an ASCII number for green
blue1 = Serial.parseInt(); // then an ASCII number for blue
t = Serial.parseInt(); // then an ASCII number for interval
d = Serial.parseInt(); // then an ASCII number for direction
if (d ==0) {
Ring1.ColorWipe(Ring1.Color(red1, green1, blue1), t, FORWARD);
} else {
Ring1.ColorWipe(Ring1.Color(red1, green1, blue1), t, REVERSE);
}
}
if ( inchar == 'S') { // string should start with S
red1 = Serial.parseInt(); // then an ASCII number for red
green1 = Serial.parseInt(); // then an ASCII number for green
blue1 = Serial.parseInt(); // then an ASCII number for blue
t = Serial.parseInt(); // then an ASCII number for interval
Ring1.Scanner(Ring1.Color(red1, green1, blue1), t);
}
if ( inchar == 'P') { // string should start with P
my_pixel = Serial.parseInt(); // then an ASCII number for pixwel
red1 = Serial.parseInt(); // then an ASCII number for red
green1 = Serial.parseInt(); // then an ASCII number for green
blue1 = Serial.parseInt(); // then an ASCII number for blue
Ring1.ActivePattern = NONE;
Ring1.setPixelColor(my_pixel, Ring1.Color(red1, green1, blue1));
Ring1.show();
}
}

// Update the ring.
Ring1.Update();
}

//------------------------------------------------------------
//Completion Routines - get called on completion of a pattern
//------------------------------------------------------------

// Ring1 Completion Callback
void Ring1Complete()
{
if ((Ring1.ActivePattern == RAINBOW_CYCLE) || (Ring1.ActivePattern == FADE) ||
(Ring1.ActivePattern == THEATER_CHASE) || (Ring1.ActivePattern == SCANNER)){
Ring1.Reverse();
}
}
#25  
To use the neopixel, there are commands at the top of the sketch. These would be sent from the EZ-B to the arduino.

Code:


/ Cr1,g1,b1 - Set whole Ring to same color specified by r1,g1,b1
/ Rt,d - Rainbow with interval t and direction d
/ Tr1,g1,b1,r2,g2,b2,t,d - Theater Chase between color r1,g1,b1 and color r2,g2,b2 with interval t and direction d
/ Wr1,g1,b1,t,d - Color Wipe in color r1,g1,b1 with interval t and direction d
/ Fr1,g1,b1,r2,g2,b2,s,t,d - Fade between color r1,g1,b1 and color r2,g2,b2 in s steps with interval t and direction d
/ Sr1,g1,b1,t - Scanner with color specified by r1,g1,b1 and interval t
/ Pp,r1,g1,b1 - Set individual pixel p to color specified by r1,g1,b1


If you change the pin on the Arduino that is connecting to the NeoPixel, you need to adjust line 317 I think. I would have to dig through to make sure.

The baud rate for the arduino is set to 9600.

To test you can use this script if configured like I have described.

Code:


SendSerial( D5, 9600, "C100,100,100" )



I have to step away for a bit. I will continue when I can
#26  
One more thing to mention...
Line 317 also contains the number of pixels in the NeoPixel. If you have 8, the first number should be 8. If you have 16, the first number should be 16. Same with 24 and so on.

I did load this onto a new arduino mini pro using the information provided above, and then tested it in the Serial Monitor in Arduino. It worked by sending the commands at the top of the sketch. I then connected to a digital port on the EZ-B (in my case D0 to try something other than D5) and it worked by sending the commands via a script as shown above but replacing D5 with D0.

I think that there is a newer version of the script that uses newer Arduino stuff and newer NeoPixel libraries, but I haven't spent any time with them.

If you try the above steps and have any issues, let me know and I will help where I can.

Thanks
David
#27  
One more test that I did just now...

I updated the NeoPixel library through the Sketch, Include Library, Manage Library menu option.

The new library (1.1.1) also still works with the NeoPixel and the sketch provided above, so it isn't necessary to stay at the older 1.0.4 version of the NeoPixel library for this to work.
#28  
I made a plugin a while back for the NeoPixel. It will give you the language of the script command that belongs in the quotes.

You can leave the arduino hooked up to the usb port and test some things out using it if you want to see how the NeoPixel reacts to the commands. You can also leave it disconnected and just use this to get the format of the commands.

To see the commands being sent to the NeoPixel, set the com port and then the number of pixels in the neopixel through the config page of the plugin.

From there, select the mode, and fill out the other fields that are enabled after selecting the mode. Click the Check mark at the bottom of the form if you want the command to be sent to the com port you specified to see the results of the settings you chose. Again, you don't have to have the connection established though to see the command that would go into the script for that action to be sent to the NeoPixel. It is just nice to also be able to see what that command looks like.

The bottom text box will display the command that you would enter into your script for this action.

https://synthiam.com/redirect/legacy?table=plugin&id=76 is the link to the plugin.
PRO
USA
#29  
Thanks David. I know you are busy so it is nice that you could spend a little time on this. I will be back at it tonight after work trying to make this work. I feel I am close.
#30  
I have had a bit more time to play around with this.

I loaded Arduino 1.8.3 and then loaded the project that RobertL184 provided to allow this to work with new versions of Arduino. https://www.ez-robot.com/Community/Forum/Thread?threadId=6767&page=7 post #67

Code:


/* real time Serial Controlled Neopixel Ring -- Code not tested yet
/
/ Serial Commands
/ Cr1,g1,b1 - Set whole Ring to same color specified by r1,g1,b1
/ Rt,d - Rainbow with interval t and direction d
/ Tr1,g1,b1,r2,g2,b2,t,d - Theater Chase between color r1,g1,b1 and color r2,g2,b2 with interval t and direction d
/ Wr1,g1,b1,t,d - Color Wipe in color r1,g1,b1 with interval t and direction d
/ Fr1,g1,b1,r2,g2,b2,s,t,d - Fade between color r1,g1,b1 and color r2,g2,b2 in s steps with interval t and direction d
/ Sr1,g1,b1,t - Scanner with color specified by r1,g1,b1 and interval t
/ Pp,r1,g1,b1 - Set individual pixel p to color specified by r1,g1,b1
/
/ p = pixel number
/ r1 = 1st color red values 0 to 255
/ g1 = 1st color greern values 0 to 255
/ b1 = 1st color blue values 0 to 255
/ r2 = 2nd color red values 0 to 255
/ g2 = 2nd color greern values 0 to 255
/ b2 = 2nd color blue values 0 to 255
/ s = number of steps
/ t = interval time values 0 to 255
/ d = direction 0 = Forward 1 = Backward
*/

#include <Adafruit_NeoPixel.h>

// Pattern types supported:
enum pattern { NONE, RAINBOW_CYCLE, THEATER_CHASE, COLOR_WIPE, SCANNER, FADE };
// Patern directions supported:
enum direction { FORWARD, REVERSE };

// NeoPattern Class - derived from the Adafruit_NeoPixel class
class NeoPatterns : public Adafruit_NeoPixel
{
public:

// Member Variables:
pattern ActivePattern; // which pattern is running
direction Direction; // direction to run the pattern

unsigned long Interval; // milliseconds between updates
unsigned long lastUpdate; // last update of position

uint32_t Color1, Color2; // What colors are in use
uint16_t TotalSteps; // total number of steps in the pattern
uint16_t Index; // current step within the pattern

void (*OnComplete)(); // Callback on completion of pattern

// Constructor - calls base-class constructor to initialize strip
NeoPatterns(uint16_t pixels, uint8_t pin, uint8_t type, void (*callback)())
:Adafruit_NeoPixel(pixels, pin, type)
{
OnComplete = callback;
}

// Update the pattern
void Update()
{
if((millis() - lastUpdate) > Interval) // time to update
{
lastUpdate = millis();
switch(ActivePattern)
{
case RAINBOW_CYCLE:
RainbowCycleUpdate();
break;
case THEATER_CHASE:
TheaterChaseUpdate();
break;
case COLOR_WIPE:
ColorWipeUpdate();
break;
case SCANNER:
ScannerUpdate();
break;
case FADE:
FadeUpdate();
break;
default:
break;
}
}
}

// Increment the Index and reset at the end
void Increment()
{
if (Direction == FORWARD)
{
Index++;
if (Index >= TotalSteps)
{
Index = 0;
if (OnComplete != NULL)
{
OnComplete(); // call the comlpetion callback
}
}
}
else // Direction == REVERSE
{
--Index;
if (Index <= 0)
{
Index = TotalSteps-1;
if (OnComplete != NULL)
{
OnComplete(); // call the comlpetion callback
}
}
}
}

// Reverse pattern direction
void Reverse()
{
if (Direction == FORWARD)
{
Direction = REVERSE;
Index = TotalSteps-1;
}
else
{
Direction = FORWARD;
Index = 0;
}
}
//------------------------------------------------------------
//Completion Routines - get called on completion of a pattern
//------------------------------------------------------------

// Initialize for a RainbowCycle
void RainbowCycle(uint8_t interval, direction dir = FORWARD)
{
ActivePattern = RAINBOW_CYCLE;
Interval = interval;
TotalSteps = 255;
Index = 0;
Direction = dir;
}

// Update the Rainbow Cycle Pattern
void RainbowCycleUpdate()
{
for(int i=0; i< numPixels(); i++)
{
setPixelColor(i, Wheel(((i * 256 / numPixels()) + Index) & 255));
}
show();
Increment();
}

// Initialize for a Theater Chase
void TheaterChase(uint32_t color1, uint32_t color2, uint8_t interval, direction dir = FORWARD)
{
ActivePattern = THEATER_CHASE;
Interval = interval;
TotalSteps = numPixels();
Color1 = color1;
Color2 = color2;
Index = 0;
Direction = dir;
}

// Update the Theater Chase Pattern
void TheaterChaseUpdate()
{
for(int i=0; i< numPixels(); i++)
{
if ((i + Index) % 3 == 0)
{
setPixelColor(i, Color1);
}
else
{
setPixelColor(i, Color2);
}
}
show();
Increment();
}

// Initialize for a ColorWipe
void ColorWipe(uint32_t color, uint8_t interval, direction dir = FORWARD)
{
ActivePattern = COLOR_WIPE;
Interval = interval;
TotalSteps = numPixels();
Color1 = color;
Index = 0;
Direction = dir;
}

// Update the Color Wipe Pattern
void ColorWipeUpdate()
{
setPixelColor(Index, Color1);
show();
Increment();
}

// Initialize for a SCANNNER
void Scanner(uint32_t color1, uint8_t interval)
{
ActivePattern = SCANNER;
Interval = interval;
TotalSteps = (numPixels() - 1) * 2;
Color1 = color1;
Index = 0;
}

// Update the Scanner Pattern
void ScannerUpdate()
{
for (int i = 0; i < numPixels(); i++)
{
if (i == Index) // Scan Pixel to the right
{
setPixelColor(i, Color1);
}
else if (i == TotalSteps - Index) // Scan Pixel to the left
{
setPixelColor(i, Color1);
}
else // Fading tail
{
setPixelColor(i, DimColor(getPixelColor(i)));
}
}
show();
Increment();
}

// Initialize for a Fade
void Fade(uint32_t color1, uint32_t color2, uint16_t steps, uint8_t interval, direction dir = FORWARD)
{
ActivePattern = FADE;
Interval = interval;
TotalSteps = steps;
Color1 = color1;
Color2 = color2;
Index = 0;
Direction = dir;
}

// Update the Fade Pattern
void FadeUpdate()
{
// Calculate linear interpolation between Color1 and Color2
// Optimise order of operations to minimize truncation error
uint8_t red = ((Red(Color1) * (TotalSteps - Index)) + (Red(Color2) * Index)) / TotalSteps;
uint8_t green = ((Green(Color1) * (TotalSteps - Index)) + (Green(Color2) * Index)) / TotalSteps;
uint8_t blue = ((Blue(Color1) * (TotalSteps - Index)) + (Blue(Color2) * Index)) / TotalSteps;

ColorSet(Color(red, green, blue));
show();
Increment();
}

// Calculate 50% dimmed version of a color (used by ScannerUpdate)
uint32_t DimColor(uint32_t color)
{
// Shift R, G and B components one bit to the right
uint32_t dimColor = Color(Red(color) >> 1, Green(color) >> 1, Blue(color) >> 1);
return dimColor;
}

// Set all pixels to a color (synchronously)
void ColorSet(uint32_t color)
{
for (int i = 0; i < numPixels(); i++)
{
setPixelColor(i, color);
}
show();
}

// Returns the Red component of a 32-bit color
uint8_t Red(uint32_t color)
{
return (color >> 16) & 0xFF;
}

// Returns the Green component of a 32-bit color
uint8_t Green(uint32_t color)
{
return (color >> 8) & 0xFF;
}

// Returns the Blue component of a 32-bit color
uint8_t Blue(uint32_t color)
{
return color & 0xFF;
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos)
{
WheelPos = 255 - WheelPos;
if(WheelPos < 85)
{
return Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
else if(WheelPos < 170)
{
WheelPos -= 85;
return Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
else
{
WheelPos -= 170;
return Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
}
};
void Ring1Complete();

// Define some NeoPatterns for the two rings and the stick
// as well as some completion routines
NeoPatterns Ring1(16, 6, NEO_GRB + NEO_KHZ800, &Ring1Complete);

int red1 = 0; // red value
int green1 = 34; // green value
int blue1 = 12; // blue value
int red2 = 0; // red value
int green2 = 34; // green value
int blue2 = 12; // blue value
int my_pixel = 0; // pixel number
int s = 5; // step value
int t = 10; // interval time value
int d = 0; // direction indicator 0= Forward 1 = Backward

// Initialize everything and prepare to start
void setup()
{
Serial.begin(9600);
Serial.setTimeout(10); // set serial timeout

// Initialize all the pixelStrips
Ring1.begin();
Ring1.ColorSet(Ring1.Color(0, 0, 0));
}

// Main loop
void loop()
{
int inchar;

if (Serial.available() > 0) {
inchar = Serial.read();
if ( inchar == 'C') { // string should start with C
red1 = Serial.parseInt(); // then an ASCII number for red
green1 = Serial.parseInt(); // then an ASCII number for green
blue1 = Serial.parseInt(); // then an ASCII number for blue
Ring1.ActivePattern = NONE;
Ring1.ColorSet(Ring1.Color(red1, green1, blue1));
}
if ( inchar == 'R') { // string should start with R
t = Serial.parseInt(); // then an ASCII number for interval
d = Serial.parseInt(); // then an ASCII number for direction
if (d ==0) {
Ring1.RainbowCycle(t, FORWARD);
} else {
Ring1.RainbowCycle(t, REVERSE);
}
}
if ( inchar == 'F') { // string should start with F
red1 = Serial.parseInt(); // then an ASCII number for red
green1 = Serial.parseInt(); // then an ASCII number for green
blue1 = Serial.parseInt(); // then an ASCII number for blue
red2 = Serial.parseInt(); // then an ASCII number for red
green2 = Serial.parseInt(); // then an ASCII number for green
blue2 = Serial.parseInt(); // then an ASCII number for blue
s = Serial.parseInt(); // then an ASCII number for steps
t = Serial.parseInt(); // then an ASCII number for interval
d = Serial.parseInt(); // then an ASCII number for direction
if (d ==0) {
Ring1.Fade(Ring1.Color(red1, green1, blue1), Ring1.Color(red2, green2, blue2), s, t, FORWARD);
} else {
Ring1.Fade(Ring1.Color(red1, green1, blue1), Ring1.Color(red2, green2, blue2), s, t, REVERSE);
}
}
if ( inchar == 'T') { // string should start with T
red1 = Serial.parseInt(); // then an ASCII number for red
green1 = Serial.parseInt(); // then an ASCII number for green
blue1 = Serial.parseInt(); // then an ASCII number for blue
red2 = Serial.parseInt(); // then an ASCII number for red
green2 = Serial.parseInt(); // then an ASCII number for green
blue2 = Serial.parseInt(); // then an ASCII number for blue
t = Serial.parseInt(); // then an ASCII number for interval
d = Serial.parseInt(); // then an ASCII number for direction
if (d ==0) {
Ring1.TheaterChase(Ring1.Color(red1, green1, blue1), Ring1.Color(red2, green2, blue2), t, FORWARD);
} else {
Ring1.TheaterChase(Ring1.Color(red1, green1, blue1), Ring1.Color(red2, green2, blue2), t, REVERSE);
}
}
if ( inchar == 'W') { // string should start with W
red1 = Serial.parseInt(); // then an ASCII number for red
green1 = Serial.parseInt(); // then an ASCII number for green
blue1 = Serial.parseInt(); // then an ASCII number for blue
t = Serial.parseInt(); // then an ASCII number for interval
d = Serial.parseInt(); // then an ASCII number for direction
if (d ==0) {
Ring1.ColorWipe(Ring1.Color(red1, green1, blue1), t, FORWARD);
} else {
Ring1.ColorWipe(Ring1.Color(red1, green1, blue1), t, REVERSE);
}
}
if ( inchar == 'S') { // string should start with S
red1 = Serial.parseInt(); // then an ASCII number for red
green1 = Serial.parseInt(); // then an ASCII number for green
blue1 = Serial.parseInt(); // then an ASCII number for blue
t = Serial.parseInt(); // then an ASCII number for interval
Ring1.ColorWipe(Ring1.Color(red1, green1, blue1), 50, 0);
Ring1.ColorSet(Ring1.Color(0,0, 0));
Ring1.Scanner(Ring1.Color(red1, green1, blue1), t);
}
if ( inchar == 'P') { // string should start with P
my_pixel = Serial.parseInt(); // then an ASCII number for pixwel
red1 = Serial.parseInt(); // then an ASCII number for red
green1 = Serial.parseInt(); // then an ASCII number for green
blue1 = Serial.parseInt(); // then an ASCII number for blue
Ring1.ActivePattern = NONE;
Ring1.setPixelColor(my_pixel, Ring1.Color(red1, green1, blue1));
Ring1.show();
}
}

// Update the ring.
Ring1.Update();
}
// Ring1 Completion Callback
void Ring1Complete()
{
if ((Ring1.ActivePattern == RAINBOW_CYCLE) || (Ring1.ActivePattern == FADE) ||
(Ring1.ActivePattern == THEATER_CHASE) || (Ring1.ActivePattern == SCANNER)){
Ring1.Reverse();
}
}


When compiling, I get an error with the ColorWipe portion. Everything does compile and load to the Arduino Mini Pro. I was able to test all of the commands via the Arduino Serial Monitor and everything worked except for the Wipe portion. I will see if I can figure it out. If not, maybe Robert can chime in and let us know a fix.
#31  
This should fix the wipe section. It was a simple fix. Line 416 Changed from

Code:


Ring1.ColorWipe(Ring1.Color(red1, green1, blue1), 50, 0);

to

Code:


Ring1.ColorWipe(Ring1.Color(red1, green1, blue1), 50, FORWARD);


Here is the working code. I have tested it out.


Code:


/* real time Serial Controlled Neopixel Ring -- Code not tested yet
/
/ Serial Commands
/ Cr1,g1,b1 - Set whole Ring to same color specified by r1,g1,b1
/ Rt,d - Rainbow with interval t and direction d
/ Tr1,g1,b1,r2,g2,b2,t,d - Theater Chase between color r1,g1,b1 and color r2,g2,b2 with interval t and direction d
/ Wr1,g1,b1,t,d - Color Wipe in color r1,g1,b1 with interval t and direction d
/ Fr1,g1,b1,r2,g2,b2,s,t,d - Fade between color r1,g1,b1 and color r2,g2,b2 in s steps with interval t and direction d
/ Sr1,g1,b1,t - Scanner with color specified by r1,g1,b1 and interval t
/ Pp,r1,g1,b1 - Set individual pixel p to color specified by r1,g1,b1
/
/ p = pixel number
/ r1 = 1st color red values 0 to 255
/ g1 = 1st color greern values 0 to 255
/ b1 = 1st color blue values 0 to 255
/ r2 = 2nd color red values 0 to 255
/ g2 = 2nd color greern values 0 to 255
/ b2 = 2nd color blue values 0 to 255
/ s = number of steps
/ t = interval time values 0 to 255
/ d = direction 0 = Forward 1 = Backward
*/

#include <Adafruit_NeoPixel.h>

// Pattern types supported:
enum pattern { NONE, RAINBOW_CYCLE, THEATER_CHASE, COLOR_WIPE, SCANNER, FADE };
// Patern directions supported:
enum direction { FORWARD, REVERSE };

// NeoPattern Class - derived from the Adafruit_NeoPixel class
class NeoPatterns : public Adafruit_NeoPixel
{
public:

// Member Variables:
pattern ActivePattern; // which pattern is running
direction Direction; // direction to run the pattern

unsigned long Interval; // milliseconds between updates
unsigned long lastUpdate; // last update of position

uint32_t Color1, Color2; // What colors are in use
uint16_t TotalSteps; // total number of steps in the pattern
uint16_t Index; // current step within the pattern

void (*OnComplete)(); // Callback on completion of pattern

// Constructor - calls base-class constructor to initialize strip
NeoPatterns(uint16_t pixels, uint8_t pin, uint8_t type, void (*callback)())
:Adafruit_NeoPixel(pixels, pin, type)
{
OnComplete = callback;
}

// Update the pattern
void Update()
{
if((millis() - lastUpdate) > Interval) // time to update
{
lastUpdate = millis();
switch(ActivePattern)
{
case RAINBOW_CYCLE:
RainbowCycleUpdate();
break;
case THEATER_CHASE:
TheaterChaseUpdate();
break;
case COLOR_WIPE:
ColorWipeUpdate();
break;
case SCANNER:
ScannerUpdate();
break;
case FADE:
FadeUpdate();
break;
default:
break;
}
}
}

// Increment the Index and reset at the end
void Increment()
{
if (Direction == FORWARD)
{
Index++;
if (Index >= TotalSteps)
{
Index = 0;
if (OnComplete != NULL)
{
OnComplete(); // call the comlpetion callback
}
}
}
else // Direction == REVERSE
{
--Index;
if (Index <= 0)
{
Index = TotalSteps-1;
if (OnComplete != NULL)
{
OnComplete(); // call the comlpetion callback
}
}
}
}

// Reverse pattern direction
void Reverse()
{
if (Direction == FORWARD)
{
Direction = REVERSE;
Index = TotalSteps-1;
}
else
{
Direction = FORWARD;
Index = 0;
}
}
//------------------------------------------------------------
//Completion Routines - get called on completion of a pattern
//------------------------------------------------------------

// Initialize for a RainbowCycle
void RainbowCycle(uint8_t interval, direction dir = FORWARD)
{
ActivePattern = RAINBOW_CYCLE;
Interval = interval;
TotalSteps = 255;
Index = 0;
Direction = dir;
}

// Update the Rainbow Cycle Pattern
void RainbowCycleUpdate()
{
for(int i=0; i< numPixels(); i++)
{
setPixelColor(i, Wheel(((i * 256 / numPixels()) + Index) & 255));
}
show();
Increment();
}

// Initialize for a Theater Chase
void TheaterChase(uint32_t color1, uint32_t color2, uint8_t interval, direction dir = FORWARD)
{
ActivePattern = THEATER_CHASE;
Interval = interval;
TotalSteps = numPixels();
Color1 = color1;
Color2 = color2;
Index = 0;
Direction = dir;
}

// Update the Theater Chase Pattern
void TheaterChaseUpdate()
{
for(int i=0; i< numPixels(); i++)
{
if ((i + Index) % 3 == 0)
{
setPixelColor(i, Color1);
}
else
{
setPixelColor(i, Color2);
}
}
show();
Increment();
}

// Initialize for a ColorWipe
void ColorWipe(uint32_t color, uint8_t interval, direction dir = FORWARD)
{
ActivePattern = COLOR_WIPE;
Interval = interval;
TotalSteps = numPixels();
Color1 = color;
Index = 0;
Direction = dir;
}

// Update the Color Wipe Pattern
void ColorWipeUpdate()
{
setPixelColor(Index, Color1);
show();
Increment();
}

// Initialize for a SCANNNER
void Scanner(uint32_t color1, uint8_t interval)
{
ActivePattern = SCANNER;
Interval = interval;
TotalSteps = (numPixels() - 1) * 2;
Color1 = color1;
Index = 0;
}

// Update the Scanner Pattern
void ScannerUpdate()
{
for (int i = 0; i < numPixels(); i++)
{
if (i == Index) // Scan Pixel to the right
{
setPixelColor(i, Color1);
}
else if (i == TotalSteps - Index) // Scan Pixel to the left
{
setPixelColor(i, Color1);
}
else // Fading tail
{
setPixelColor(i, DimColor(getPixelColor(i)));
}
}
show();
Increment();
}

// Initialize for a Fade
void Fade(uint32_t color1, uint32_t color2, uint16_t steps, uint8_t interval, direction dir = FORWARD)
{
ActivePattern = FADE;
Interval = interval;
TotalSteps = steps;
Color1 = color1;
Color2 = color2;
Index = 0;
Direction = dir;
}

// Update the Fade Pattern
void FadeUpdate()
{
// Calculate linear interpolation between Color1 and Color2
// Optimise order of operations to minimize truncation error
uint8_t red = ((Red(Color1) * (TotalSteps - Index)) + (Red(Color2) * Index)) / TotalSteps;
uint8_t green = ((Green(Color1) * (TotalSteps - Index)) + (Green(Color2) * Index)) / TotalSteps;
uint8_t blue = ((Blue(Color1) * (TotalSteps - Index)) + (Blue(Color2) * Index)) / TotalSteps;

ColorSet(Color(red, green, blue));
show();
Increment();
}

// Calculate 50% dimmed version of a color (used by ScannerUpdate)
uint32_t DimColor(uint32_t color)
{
// Shift R, G and B components one bit to the right
uint32_t dimColor = Color(Red(color) >> 1, Green(color) >> 1, Blue(color) >> 1);
return dimColor;
}

// Set all pixels to a color (synchronously)
void ColorSet(uint32_t color)
{
for (int i = 0; i < numPixels(); i++)
{
setPixelColor(i, color);
}
show();
}

// Returns the Red component of a 32-bit color
uint8_t Red(uint32_t color)
{
return (color >> 16) & 0xFF;
}

// Returns the Green component of a 32-bit color
uint8_t Green(uint32_t color)
{
return (color >> 8) & 0xFF;
}

// Returns the Blue component of a 32-bit color
uint8_t Blue(uint32_t color)
{
return color & 0xFF;
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos)
{
WheelPos = 255 - WheelPos;
if(WheelPos < 85)
{
return Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
else if(WheelPos < 170)
{
WheelPos -= 85;
return Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
else
{
WheelPos -= 170;
return Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
}
};
void Ring1Complete();

// Define some NeoPatterns for the two rings and the stick
// as well as some completion routines
NeoPatterns Ring1(24, 6, NEO_GRB + NEO_KHZ800, &Ring1Complete);

int red1 = 0; // red value
int green1 = 34; // green value
int blue1 = 12; // blue value
int red2 = 0; // red value
int green2 = 34; // green value
int blue2 = 12; // blue value
int my_pixel = 0; // pixel number
int s = 5; // step value
int t = 10; // interval time value
int d = 0; // direction indicator 0= Forward 1 = Backward

// Initialize everything and prepare to start
void setup()
{
Serial.begin(9600);
Serial.setTimeout(10); // set serial timeout

// Initialize all the pixelStrips
Ring1.begin();
Ring1.ColorSet(Ring1.Color(0, 0, 0));
}

// Main loop
void loop()
{
int inchar;

if (Serial.available() > 0) {
inchar = Serial.read();
if ( inchar == 'C') { // string should start with C
red1 = Serial.parseInt(); // then an ASCII number for red
green1 = Serial.parseInt(); // then an ASCII number for green
blue1 = Serial.parseInt(); // then an ASCII number for blue
Ring1.ActivePattern = NONE;
Ring1.ColorSet(Ring1.Color(red1, green1, blue1));
}
if ( inchar == 'R') { // string should start with R
t = Serial.parseInt(); // then an ASCII number for interval
d = Serial.parseInt(); // then an ASCII number for direction
if (d ==0) {
Ring1.RainbowCycle(t, FORWARD);
} else {
Ring1.RainbowCycle(t, REVERSE);
}
}
if ( inchar == 'F') { // string should start with F
red1 = Serial.parseInt(); // then an ASCII number for red
green1 = Serial.parseInt(); // then an ASCII number for green
blue1 = Serial.parseInt(); // then an ASCII number for blue
red2 = Serial.parseInt(); // then an ASCII number for red
green2 = Serial.parseInt(); // then an ASCII number for green
blue2 = Serial.parseInt(); // then an ASCII number for blue
s = Serial.parseInt(); // then an ASCII number for steps
t = Serial.parseInt(); // then an ASCII number for interval
d = Serial.parseInt(); // then an ASCII number for direction
if (d ==0) {
Ring1.Fade(Ring1.Color(red1, green1, blue1), Ring1.Color(red2, green2, blue2), s, t, FORWARD);
} else {
Ring1.Fade(Ring1.Color(red1, green1, blue1), Ring1.Color(red2, green2, blue2), s, t, REVERSE);
}
}
if ( inchar == 'T') { // string should start with T
red1 = Serial.parseInt(); // then an ASCII number for red
green1 = Serial.parseInt(); // then an ASCII number for green
blue1 = Serial.parseInt(); // then an ASCII number for blue
red2 = Serial.parseInt(); // then an ASCII number for red
green2 = Serial.parseInt(); // then an ASCII number for green
blue2 = Serial.parseInt(); // then an ASCII number for blue
t = Serial.parseInt(); // then an ASCII number for interval
d = Serial.parseInt(); // then an ASCII number for direction
if (d ==0) {
Ring1.TheaterChase(Ring1.Color(red1, green1, blue1), Ring1.Color(red2, green2, blue2), t, FORWARD);
} else {
Ring1.TheaterChase(Ring1.Color(red1, green1, blue1), Ring1.Color(red2, green2, blue2), t, REVERSE);
}
}
if ( inchar == 'W') { // string should start with W
red1 = Serial.parseInt(); // then an ASCII number for red
green1 = Serial.parseInt(); // then an ASCII number for green
blue1 = Serial.parseInt(); // then an ASCII number for blue
t = Serial.parseInt(); // then an ASCII number for interval
d = Serial.parseInt(); // then an ASCII number for direction
if (d ==0) {
Ring1.ColorWipe(Ring1.Color(red1, green1, blue1), t, FORWARD);
} else {
Ring1.ColorWipe(Ring1.Color(red1, green1, blue1), t, REVERSE);
}
}
if ( inchar == 'S') { // string should start with S
red1 = Serial.parseInt(); // then an ASCII number for red
green1 = Serial.parseInt(); // then an ASCII number for green
blue1 = Serial.parseInt(); // then an ASCII number for blue
t = Serial.parseInt(); // then an ASCII number for interval
Ring1.ColorWipe(Ring1.Color(red1, green1, blue1), 50, FORWARD);
Ring1.ColorSet(Ring1.Color(0,0, 0));
Ring1.Scanner(Ring1.Color(red1, green1, blue1), t);
}
if ( inchar == 'P') { // string should start with P
my_pixel = Serial.parseInt(); // then an ASCII number for pixwel
red1 = Serial.parseInt(); // then an ASCII number for red
green1 = Serial.parseInt(); // then an ASCII number for green
blue1 = Serial.parseInt(); // then an ASCII number for blue
Ring1.ActivePattern = NONE;
Ring1.setPixelColor(my_pixel, Ring1.Color(red1, green1, blue1));
Ring1.show();
}
}

// Update the ring.
Ring1.Update();
}
// Ring1 Completion Callback
void Ring1Complete()
{
if ((Ring1.ActivePattern == RAINBOW_CYCLE) || (Ring1.ActivePattern == FADE) ||
(Ring1.ActivePattern == THEATER_CHASE) || (Ring1.ActivePattern == SCANNER)){
Ring1.Reverse();
}
}
PRO
USA
#32  
Loaded up the code and I am still having problems so I need to narrow it down. I know my neopixel works because I can load the Adafruit example code on and that works.
I can compile the new code and load. I have the Wiring holed up correctly to the EZB. I an not get a response. So I am down to Something in the serial connection.

I am using an Arduino micro. I assume this should work but some of the literature suggests it has TX peculiarities. So maybe that is it.

How should I be executing the sample codes? I am putting it into a script in the script manager and running it. Should I be doing this through a serial terminal or something?
PRO
USA
#33  
UPDATE!
Total success now. Thanks so much to everybody that helped. Great community over here.

So there was a problem with the tutorial script and a problem with me. Thanks for fixing the script David and +1 for making it such that I could dump that old Arduino version.

The problem with me was that I had the EZB connected to the TX of the Arduino and not the RX. I figured the Arduino was transmitting something to the ring. The wiring diagram in the tutorial is right. I just processed it wrong in my brain.

Thanks everyone for helping me get this far. This is a helpful forum and people stick around to see problems through

5 cheeseburgers for everyone involved.
#34  
That good news, Perry, glad to hear you got it working.
Dave, it would be great if you could make a new tutorial on this topic.
Can't wait for the new Neo Pixel hardware from EZ-Robot!
PRO
USA
#35  
Happy this is working. Happier now others will have a solid tutorial that works.

I have 2 neopixels in my robot. I am experimenting with emotions and color patters. This is a great win for me. Maybe David will get around to making his plugin a fully functional control with tons of configuration options. He's busy so maybe between 1 and 3 AM next Tuesday.

4 Beers into the celebration of hitting my MRL functionality test. Now my guy does every function I had with the other software. Major milestone for me, The thing is, I don't really see the trajectory changing. I think it will just get better from here.

Happy Friday to all!
#36  
Glad that it is working for you and even more glad that you have a robot instead of a statue:)

I don't know when I will get back to plugin development. When I do, I will basically be taking all of the pieces of EZ-AI that I had worked on for a couple of years, and make them plugins. Some of it I won't have to write again due to some amazing advances in plugin development. I am sure that I will revisit the NeoPixel plugin during this time, among others.

A new Tuto has been published. Hopefully it will help out some. The issue with a Tuto like this is that so many people can make a small change that breaks things. Arduino is the most likely to do this, so maintaining it becomes difficult unless you have someone tell you that it doesn't work. Yours is working great because at the time you wrote it, it worked. This is what Bob faced and I know it is frustrating. You are trying to offer something to the community and then it becomes a chore or job to keep it up to date. The last thing you want is people to run into issues following something that you wrote to help people out. The problem is that you have moved on because yours is working so you don't have a need to revisit it over and over, until you do.

Bob, I want to thank you for putting up your Tutorial. It did help a lot of people and the NeoPixel questions did drop for a while. Hopefully my Tutorial can help as many people as yours did.
#37  
Dave, thanks for the kind words. The new tutorial looks good, except this line didn't copy;
#include <Adafruit_NeoPixel.h>
That's the same problem I had, there is another way to upload the sketch so it shows but I don't know how to do it.