Asked — Edited
Resolved Resolved by RobertL184!

Help Connecting A Neopixel Ring

Hello all,

Has anyone used a NeoPixel Ring before. I can't figure out how to wire it or connect it to EZB. Here is a link to the NeoPixel Ring site it has a data sheet. http://www.adafruit.com/product/1586

I have look at the I2C but not sure what address or how it is wired.

Thank you.


ARC Pro

Upgrade to ARC Pro

Stay at the forefront of robot programming innovation with ARC Pro, ensuring your robot is always equipped with the latest advancements.

United Kingdom
#1  

It's not I2C which is why you can't find the I2C address.

From a quick (very quick) look it's based on timing. The "datasheet" isn't the simplest to follow but I'll have a proper read when I get home. In the mean time it may pay to see if anyone has it working with Arduino or other PICs and see how they managed it, check the libraries (if available) and see if you can port it over to EZ-Script.

From my quick look you will need to write a complex EZ-Script however it depends what you want to do with it.

#2  

NeoPixels are timing sensitive. At first glance I don't think the EZ-B can drive them due to the timing they use. The best way to talk to them is with an arduino. There is arduino library for them. I've made a guggenhat and an ironman ARC reactor (with the help of a 3 D printer) using them.

The guggenhat might be a good example to look at since it uses TTL serial to control the neopixels. The guggenhat is a complex example as the neopixels are in an array to provide a digital sign effect and a bluetooth le reciever, but the arduino code has a lot of the elements you may be interested in. Most arduino chips can support I2C so it should be possible to substitute the I2C for the TTL serial interface and control your neopixel ring using I2C if you wish. I have yet to try using an I2C interface on an arduino so perhaps someone else can help more there. A member on this forum Luis Vazquez has done some write ups that might be of interest to you. Check out his Forum Discussions.

I am not an expert in arduino code. I hack examples together to make them do what I want at this point. Fortunately there are a lot of arduino examples out there on the internet.

#3  

Here's a short video I made a while ago. I made the glasses out of a couple of Neo Pixel Rings. They are hooked up to Arduino Uno and I load the the sample sketch from Adafuits site. I have not explored running it with ARC but I'm sure someone like Luis could figure it out.

#4  

@ Rich, Thank you for checking. I'm really trying to figure out how the pinouts compare / connect to the arduino and then try to figure out how to ingrate with EZB. Figuring out the script later. I am not understanding how the wiring connects even if it where connected to an arduino first.

@ RobertL184, I am going to read more on the two web sites you mention. at just a 30 second looks like it will help. My biggest problem is know nothing about Arduino or how to use it. Heck, I have a hard enough time with EZB even though it's a lot easier to learn. I also really do not understand I2C, like what does SDA and SCL do or mean.

@ bhouston, that is a great video! Love the glasses. It makes your robot look smarter. :-) do you have pinouts how you connected it to the Uno? Also do you download the script to the Arduino or does it run from the PC like how most use Inmoov?

I will post in EZ-Script to see if Luis has any suggestions.

Thank you all for the responses, direction and help.

One more question . Who should I say resolved these questions?

Thank you, MErne

#5  

Hi Luis. do you have any input to my question. thanks

United Kingdom
#6  

With regards to who resolved the question, nobody yet. As far as I can see it's still unresolved. Only once you have your neopixel ring working in ARC should it be marked as resolved.

#7  

Just found the info I remembered on Neopixels Timing. They will require a separate controller like an arduino.

The single-wire control protocol used by NeoPixels requires a very steady data stream at 800 kilobits per second. There’s a tiny margin for error, but not very much. Bits must be issued at a precisely controlled ratethe Adafruit_NeoPixel library handles all this behind the scenes, carefully counting the time of each machine code instruction. For every pixel, there’s 24 of these:

components_neopixel-timing

What kind of things were you interested in doing with them?

Setting the whole ring to a specific color?

Being able to set individual pixels in the ring to a specific color?

Do you need the arduino to handle color fades or blinking neopixels or chasing patterns?

With individual pixel control you can write code in the EZ-B to do any of these, but you have the power of the arduino there so why not offload a little work.

The library needed to control the neopixels with an arduino is on the adafruit site. I personally would set it up to use TTL Serial to control the Arduino with the EZ-B, since you most likely don't need to request data back from the arduino. This would let you use any digital pin on the EZ-B to control the arduino.

The SendSerial( digitalPort, baudRate, data, ... ) command in EZ-Script works really well. The types of things you want to do with the Neopixel will determine the types of commands you need to send over the TTL Serial link.

#8  

I wish EZ-Robot and Adafuit could hook up somehow to where Adafruit would port their libraries out for the EZB. They usually have libraries for a few controllers. I do think they make a few of them conrolers themselves but, Adafruit has lots of cool stuff and it would be great for them to be "Plug and play" with the EZB. Alot of their stuff like neo-pixes almost seem like they would have been made for the EZ-Robot system in the first place.

EZ-Robot has sold quite a few units so I would think it woud be of interest for Adafruit to want to be able to sell periperals to this market. And having Adafruit stuff supported by the EZB would be a nice bullet point in the press releases.

What would it take to make something like that happen?

#9  

Thanks robertl284, i just wanted to have the ring change colors on cooand or when talking. curtently i have npt be missing with my robot latly. i will do more reading as time premits. i have no time right now. i am going to give the credit to you as you are the closest to gave a good answer.

thanks.

#10  

@Merne, I am now to this point and have ordered the parts needed to make this work. I will load the sketch onto an android mini and send it to you when I know I have it working. I will also let you know how I have it all wired up and all the other bits of info. It may be a bit of time, but i'll get it to you.

#11  

I have not connected it to an ez-b but I have used a pololu astar arduino board to control neopixels with TTL serial commands using a modification of this arduino sketch.

http://www.tigoe.com/pcomp/code/arduinowiring/1172/

The mod I made was to use serial1 instead of serial. The astar uses a 32u4 processor which has a second serial port on pins 0 and 1. Just had pin 0 of the astar hooked up to a TTL serial source ( the equivalent of a ez-b digital signal pin). What I was sending it was the equivalent to using the ARC sendserial command. (e.g. SendSerial(d0, 9600, "C0,255,0,0" ) ).The ez-b command causes ez-b port d0 to send a string that writes neopixel 0 to bright red. You don't need a full UART to control the arduino since it never sends anything back to the ez-b so any digital port like d0 would work.

The other change I made to the arduino sketch was to change define PIN 13 to define PIN 6 . This lets you connect the neopixel DIN pin to pin 6 of the pololu astar.

#13  

If you are using the ez-b with the lipo battery pack a pololu astar 32u4 mini LV might be the arduino to use as it runs off of 2.7 to 11 volts and has an on-board switching regulator that has up to 1 amp of extra 5V power capacity to run the neopixels with. That extra power should be enough for a couple of the smaller neopixel rings.

My ez-b is embedded in a robot so I can't test it with an ez-b myself.

#14  

Thanks Robert. I will look into it. All of mine are on a shelf right now so when the mini comes in I will play with it and see if I can't release some smoke :)

#15  

Here is the code I was playing with. When I did it I apparently just added the Serial1 feature in and left the original code there as a backup.

/* Simple BlinkyStrip control

This sketch allows serial control over a BlinkyStrip. To set any pixel in the strip, send the following serial string:

Cr,g,b

r, g, and b are ASCII numbers for the red, green, and blue brightness levels, from 0 to 255.

This will probably work for any string of NeoPixels from Adafruit as well.

Uses Adafruit's NeoPixel library: https://github.com/adafruit/Adafruit_NeoPixel

created 4 Dec 2014 by Tom Igoe

*/ #include <Adafruit_NeoPixel.h>

#define PIN 6

Adafruit_NeoPixel strip = Adafruit_NeoPixel(60, PIN, NEO_GRB + NEO_KHZ800);

int pixel = 0; // pixel number that you're changing int red = 0; // red value int green = 34; // green value int blue = 12; // blue value

void setup() { Serial.begin(9600); // initialize serial communication Serial.setTimeout(10); // set serial timeout Serial1.begin(9600); // initialize serial communication Serial1.setTimeout(10); // set serial timeout strip.begin(); // initialize pixel strip strip.show(); // Initialize all pixels to 'off' }

void loop() { // listen for serial: if (Serial.available() > 0) { if (Serial.read() == 'C' ) { // string should start with C pixel = Serial.parseInt(); // then an ASCII number for pixel number red = Serial.parseInt(); // then an ASCII number for red green = Serial.parseInt(); // then an ASCII number for green blue = Serial.parseInt(); // then an ASCII number for blue } } if (Serial1.available() > 0) { if (Serial1.read() == 'C' ) { // string should start with C pixel = Serial1.parseInt(); // then an ASCII number for pixel number red = Serial1.parseInt(); // then an ASCII number for red green = Serial1.parseInt(); // then an ASCII number for green blue = Serial1.parseInt(); // then an ASCII number for blue } } strip.setPixelColor(pixel, red, green, blue);// set the color for this pixel strip.show(); // refresh the strip }

#16  

Thanks for the example. I think I am going to start with something like this.


/*
Simple BlinkyStrip control

This sketch allows serial control over a BlinkyStrip.
To set any pixel in the strip, send the following serial string:

Cr,g,b

r, g, and b are ASCII numbers for the red, green, and blue brightness
levels, from 0 to 255.

This will probably work for any string of NeoPixels from Adafruit as well.

Uses Adafruit's NeoPixel library: https://github.com/adafruit/Adafruit_NeoPixel

created 4 Dec 2014
by Tom Igoe

*/
#include &lt;Adafruit_NeoPixel.h&gt;

#define PIN 6

Adafruit_NeoPixel strip = Adafruit_NeoPixel(16, PIN, NEO_GRB + NEO_KHZ800);

int pixel = 0; // pixel number that you're changing
int red = 0; // red value 
int green = 34; // green value
int blue = 12; // blue value

void setup() 
{
  Serial.begin(9600); // initialize serial communication
  Serial.setTimeout(10); // set serial timeout
  strip.begin(); // initialize pixel strip
  strip.show(); // Initialize all pixels to 'off'
}

void loop() 
{
  // listen for serial:
  if (Serial.available() &gt; 0) 
    {
    if (Serial.read() == 'C' ) 
      { // string should start with C
        pixel = Serial.parseInt(); // then an ASCII number for pixel number
        red = Serial.parseInt(); // then an ASCII number for red
        green = Serial.parseInt(); // then an ASCII number for green
        blue = Serial.parseInt(); // then an ASCII number for blue
      }
    }

  
   for (int i=0; i&lt;260; i+10)
   {
    delay(50);
    strip.setBrightness(i);
    for (int j=0; j &lt; 16; j++)
    {
      strip.setPixelColor(j, red, green, blue);// set the color for this pixela
    }
    strip.show(); // refresh the strip
   }
   for (int i=250; i &gt; 0; i-10)
   {
    delay(50);
    strip.setBrightness(i);
    for (int j=0; j &lt; 16; j++)
    {
      strip.setPixelColor(j, red, green, blue);// set the color for this pixela
    }
    strip.show(); // refresh the strip
   }
}

#17  

You might be happier with this slight mod of your code. It allows individual pixels to be set using the original Cp,r,g,b command and adds an Sr,g,b command which will change the color of the entire neopixel ring. It looks like you want the ring to gradually go bright to dim to bright again. With the code you have it will be doing that every 2.5 seconds or so. That might be a bit fast. delay(50) is a 50millisecond delay you get 25 of these in each brightness change loop. so it will go from bright to dim in about 1.25 seconds and dim to bright in 1.25 seconds. That seems fast to me. You might want to only change the brightness by 1 instead of 10. Not sure how response it will be to serial commands with the longer delays though.


/*
Simple BlinkyStrip control

This sketch allows serial control over a BlinkyStrip.
To set any pixel in the strip, send the following serial string:

Cp,r,g,b

To set the whole strip to a single color, send the following serial string:

Sr,g,b

p is the pixel number to set
r, g, and b are ASCII numbers for the red, green, and blue brightness
levels, from 0 to 255.




This will probably work for any string of NeoPixels from Adafruit as well.

Uses Adafruit's NeoPixel library: https://github.com/adafruit/Adafruit_NeoPixel

original sketch created 4 Dec 2014
by Tom Igoe
modified for neopixel ring 

*/
#include &lt;Adafruit_NeoPixel.h&gt;

#define PIN 6

Adafruit_NeoPixel strip = Adafruit_NeoPixel(16, PIN, NEO_GRB + NEO_KHZ800);
int incomingByte = 0;   // for incoming serial data
int input_pixel = 0; // pixel number that you're changing
int red = 0; // new serial red value 
int green = 0; // new serial green value
int blue = 0; // new serialblue value

void setup() 
{
Serial.begin(9600); // initialize serial communication
Serial.setTimeout(10); // set serial timeout
strip.begin(); // initialize pixel strip
strip.show(); // Initialize all pixels to 'off'
}

void loop() 
{
// listen for serial:
if (Serial.available() &gt; 0) 
{
  incomingByte = Serial.read();
  if (incomingByte == 'C' ) 
    { // string should start with C
    input_pixel = Serial.parseInt(); // then an ASCII number for pixel number
    red = Serial.parseInt(); // then an ASCII number for red
    green = Serial.parseInt(); // then an ASCII number for green
    blue = Serial.parseInt(); // then an ASCII number for blue
    strip.setPixelColor(input_pixel, red, green, blue);// set the color for this pixela
    strip.show(); // refresh the strip
   }
  if (incomingByte == 'S' ) 
    { // string should start with S
    red = Serial.parseInt(); // then an ASCII number for red
    green = Serial.parseInt(); // then an ASCII number for green
    blue = Serial.parseInt(); // then an ASCII number for blue
    for (int j=0; j &lt; 16; j++)
      {
      strip.setPixelColor(j, red, green, blue);// set the color for this pixela
      strip.show(); // refresh the strip
      }
    }
  }
for (int i=0; i&lt;250; i= i+10)
  {
  strip.setBrightness(i);
  strip.show(); // refresh the strip
  delay(50);
  }
for (int i=250; i &gt; 0; i=i-10)
  {
  strip.setBrightness(i);
  strip.show(); // refresh the strip
  delay(50);
  }
}


#18  

I figured I would play with the delay when I have something in my hands to use. I'm thinking of it more as a heart beat than anything right now. I'll check out your code.

#19  

I also want the user to be able to set the color and then forget it unless they want to change the color. I figured the loop would allow them to change the color and then perform the heart beat type of series. I am guessing what the results will be until I get my anxious hands on these components.

#20  

I've been playing with a Neo Ring the last couple of days and have a script working thru the EZBv4. I have tried running the scripts above and get this error message for all 3 - what am I missing?

Arduino: 1.6.3 (Windows 8.1), Board: "Arduino Uno"

Neo_ring_from_forum.ino:1:1: error: 'Code' does not name a type

Neo_ring_from_forum.ino:36:1: error: 'Adafruit_NeoPixel' does not name a type

Neo_ring_from_forum.ino: In function 'void setup()':

Neo_ring_from_forum.ino:47:1: error: 'strip' was not declared in this scope

Neo_ring_from_forum.ino: In function 'void loop()':

Neo_ring_from_forum.ino:63:1: error: 'strip' was not declared in this scope

Neo_ring_from_forum.ino:73:1: error: 'strip' was not declared in this scope

Neo_ring_from_forum.ino:80:1: error: 'strip' was not declared in this scope

Neo_ring_from_forum.ino:86:1: error: 'strip' was not declared in this scope

Error compiling.

Thanks

#21  

Remove the word Code: from the top of your arduino file and try to compile it again.

#22  

If it still doesn't work, make sure that you have the Adafruit_NeoPixel library loaded into your user libraries.

#23  

Ok, that worked, got it loaded, however when I enter C in the serial monitor nothing happens. Are there some color values that have to be added/changed?

#24  

I don't have my arduino or neopixel yet. I think ARC would use something like this

SendSerial(d0, 9600, "C0,255,0,0" ) 

with the wire from the signal of D0 to the serial pin or rx pin on the arduino. I'm new at this part for sure as I don't even have one yet.

#25  

The ring I think would be to pin 6 on the arduino for signal and provide power to the ring. I read something about the power should be from the same source as the arduino. This could come off of the arduino if you would like.

#26  

Dave, has the code you posted been tested? I was sending the command thru the Arduino serial monitor, should work there. I will try and send it thru the EZB.

#27  

Not at all. I dont even have an arduino yet. It should be here soon. The neopixel may be a week out or so. This was more of a conversation to get ideas in a topic that already existed. Read post #12.

#28  

Robert, what do you think about this. The V4 could set an arduino pin to high which would then be caught in the loop and kick the arduino code to a function that is looking for a serial connection to get the new values. The trigger port would be set to low again by the V4 and the arduino would see this and start the loop again using those color settings.

#29  

OK. Here's where I am at running a Neo Pixel Ring off of the EZBv4. I have to say right up front that what I am going to post is the work of our friend Luis Vazquez who has guided me thru get the ring up and running.

Connection between the EZB and the Arduino

Digital Port 18 (TX) to RX on the Arduino Digital Port 19 (RX) to TX on theArduino These are used as UART2 Connect a ground wire between the EZB and the Arduino:

Note; You can't upload a script to the Arduino with EZB powered up.

Arduino script:


 #include &lt;Adafruit_NeoPixel.h&gt;


#define PIN 6

// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
//   NEO_KHZ800  800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
//   NEO_KHZ400  400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
//   NEO_GRB     Pixels are wired for GRB bitstream (most NeoPixel products)
//   NEO_RGB     Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(60, PIN, NEO_GRB + NEO_KHZ800);

// IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across
// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input
// and minimize distance between Arduino and first pixel.  Avoid connecting
// on a live circuit...if you must, connect GND first.

void setup() {
  Serial.begin(9600);

  strip.begin();
  strip.show(); // Initialize all pixels to 'off'
}

void loop() {


  if (Serial.available())
  {


    int ib = 0;
    ib = Serial.read();


    // Stop All display
    if (ib == 33) {
      strip.show(); // Initialize all pixels to 'off'
    }



    // ColorWipes
    // Blue = &quot;B&quot; or 66
    if (ib == 66) {
      colorWipe(strip.Color(0, 0, 255), 5); // Blue
      
    }
    //Blue White = &quot;P&quot; or 80
    if (ib == 80){
      colorWipe(strip.Color(0, 0, 255), 20);
      colorWipe(strip.Color(0, 0, 0), 30);
    }
    // Red = &quot;R&quot; or 82
    if (ib == 82) {
      colorWipe(strip.Color(255, 0, 0), 10); // Red

    }
    // Green = &quot;G&quot; or 71
    if (ib == 71) {
      colorWipe(strip.Color(0, 255, 0), 50); // Green
    }
    if (ib == 87){
      colorWipe(strip.Color(0, 0, 0), 10);
    }

    // ChaseSetting
    // White = &quot;w&quot; or 119
    if (ib == 119) {
        theaterChase(strip.Color(127, 127, 127), 50); // White
    }
    // Red = &quot;r&quot; or 114
    if (ib == 114) {
      theaterChase(strip.Color(127,   0,   0), 50); // Red

    }
    
    if (ib == 98)
    {
     theaterChase(strip.Color(  0,   0, 127), 50); // Blue
    }
    
    if (ib == 88)
    {
    rainbow(20);
    }
  if (ib == 89)
  {
  rainbowCycle(20);
  }
  
  if (ib == 90)
  {
  theaterChaseRainbow(50);
  } 
    
    
  }



  


}

// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
  for (uint16_t i = 0; i &lt; strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    strip.show();
    delay(wait);
  }
}

void rainbow(uint8_t wait) {
  uint16_t i, j;

  for (j = 0; j &lt; 256; j++) {
    for (i = 0; i &lt; strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i + j) &amp; 255));
    }
    strip.show();
    delay(wait);
  }
}

// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(uint8_t wait) {
  uint16_t i, j;

  for (j = 0; j &lt; 256 * 5; j++) { // 5 cycles of all colors on wheel
    for (i = 0; i &lt; strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) &amp; 255));
    }
    strip.show();
    delay(wait);
  }
}

//Theatre-style crawling lights.
void theaterChase(uint32_t c, uint8_t wait) {
  for (int j = 0; j &lt; 10; j++) { //do 10 cycles of chasing
    for (int q = 0; q &lt; 3; q++) {
      for (int i = 0; i &lt; strip.numPixels(); i = i + 3) {
        strip.setPixelColor(i + q, c);  //turn every third pixel on
      }
      strip.show();

      delay(wait);

      for (int i = 0; i &lt; strip.numPixels(); i = i + 3) {
        strip.setPixelColor(i + q, 0);      //turn every third pixel off
      }
    }
  }
}

//Theatre-style crawling lights with rainbow effect
void theaterChaseRainbow(uint8_t wait) {
  for (int j = 0; j &lt; 256; j++) {   // cycle all 256 colors in the wheel
    for (int q = 0; q &lt; 3; q++) {
      for (int i = 0; i &lt; strip.numPixels(); i = i + 3) {
        strip.setPixelColor(i + q, Wheel( (i + j) % 255)); //turn every third pixel on
      }
      strip.show();

      delay(wait);

      for (int i = 0; i &lt; strip.numPixels(); i = i + 3) {
        strip.setPixelColor(i + q, 0);      //turn every third pixel off
      }
    }
  }
}

// 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) {
  if (WheelPos &lt; 85) {
    return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  } else if (WheelPos &lt; 170) {
    WheelPos -= 85;
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else {
    WheelPos -= 170;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
}

Makes sure you have the library for it.

You should be able to send it commands thru the Arduino Serial Monitor by entering the (ASCII Character). For example in the code above enter "B" or 66 and the Blue colorwipe should run.

To send the commands via the EZB.

Create an initialization script and have it run when you connect to the EZB


UARTInit( 0,2,9600 )

Create a script to send the commands to the Arduino, for example, this will run the Blue colorswipe, once.


UARTWrite(0,2,&quot;B&quot;)

To run it multiple times you can put it in a loop.

I have found the script hard to control, for example, running in a loop if you push stop it will still run for awhile.

What I am trying to achieve is a pulsing effect that can be changed to different colors, when needed. Kind of like a mood indicator. If anyone can help out there help with a script for that, it would be great. Once again thanks Luis for all your help.

#30  

The problem is that the loops that change pixel colors have delays in them and the arduino is busy in those loops and not checking the serial port for new commands. I have seen a few notes on the subject on the Internet. It is what I meant when I said I was not sure how responsive the arduino would be to serial commands. There is a way to write it that will work. There are some articles on adafruit about multitasking an arduino which help explain the way to do it. When I get time I will see if I can whip up something close to what you need as an example.

Luis is a probably better at this stuff than I am, but we all have different things we have worked with. I have been playing with neopixels for some projects lately. I made a guggenhat a while back that mixes neopixels with serial input that has the fixes in it you need.

#31  

Couldn't you check for the pin state in the inner loops which would make it check every 50 ms? If the pin is high, jump out. Basically at that point you could set another pin high but in the opposite direction. The v4 could be set to watch for that pin to go high and start the serial write. When it is done, the v4 could set the first pin back to low. You get the idea. The unique thing here is that there are many different ports to handle flags passed back and forth between the two devices.

if you want to work on it, thate great. I will be working on it as soon as I can. I like learning new stuff.

#32  

If you want to look into using digital signals to interrupt the loops the arduino does actually support interrupts. The same adafruit multitasking an arduino tutorials actually talk about using signals pins to interrupt loops. They are a good read.

https://learn.adafruit.com/multi-tasking-the-arduino-part-1

https://learn.adafruit.com/multi-tasking-the-arduino-part-2

https://learn.adafruit.com/multi-tasking-the-arduino-part-3

I think part 3 has a lot of the fix you need but it has been a bit since I read thru them. In part 3 they get rid of the delays in the loops. The code in part 3 uses push buttons to change operations, but a serial input could be used instead. If you really want to use up digital pins on the ez-b you could use the button code as is.

#33  

Thanks Robert. I will check it out and see where it leads.

#34  

@RobertL184, can you post an example of the fix you have for this?

#35  

I should have my parts tomorrow (unless something happens in shipping). I will work on this some time soon and post my script and how I have things wired up. I plan on using some of the things posted by Robert in his last post and using a digital pin from the V4 to a digital pin on the arduino as an interrupt when serial communication starts and stops which will allow the arduino to know to interrupt its loop and catch the serial communication from the V4 which will set which color you want to have pulse again.

#36  

Okay here is a total untested shot at the code for a single neopixel with animations which should be fairly responsive to serial commands. I haven't had time to test any of it. All I can say is that it does compile. The code is mainly from adafruit lesson number 3. It will probably need a bit more work to make everything function properly. The Ring1Complete function is the one I am least sure of.


/* 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 &lt;Adafruit_NeoPixel.h&gt;
 
// 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) &gt; 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 &gt;= TotalSteps)
            {
                Index = 0;
                if (OnComplete != NULL)
                {
                    OnComplete(); // call the comlpetion callback
                }
            }
        }
        else // Direction == REVERSE
        {
            --Index;
            if (Index &lt;= 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&lt; numPixels(); i++)
        {
            setPixelColor(i, Wheel(((i * 256 / numPixels()) + Index) &amp; 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&lt; 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 &lt; 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) &gt;&gt; 1, Green(color) &gt;&gt; 1, Blue(color) &gt;&gt; 1);
        return dimColor;
    }
 
    // Set all pixels to a color (synchronously)
    void ColorSet(uint32_t color)
    {
        for (int i = 0; i &lt; numPixels(); i++)
        {
            setPixelColor(i, color);
        }
        show();
    }
 
    // Returns the Red component of a 32-bit color
    uint8_t Red(uint32_t color)
    {
        return (color &gt;&gt; 16) &amp; 0xFF;
    }
 
    // Returns the Green component of a 32-bit color
    uint8_t Green(uint32_t color)
    {
        return (color &gt;&gt; 8) &amp; 0xFF;
    }
 
    // Returns the Blue component of a 32-bit color
    uint8_t Blue(uint32_t color)
    {
        return color &amp; 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 &lt; 85)
        {
            return Color(255 - WheelPos * 3, 0, WheelPos * 3);
        }
        else if(WheelPos &lt; 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, &amp;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() &gt; 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();
    }
}
 

#37  

Thank you Robert. I will give it a shot tonight and post any modifications that I make to it.

#38  

Thanks Robert, I just uploaded and ran your code. First thought I had to define the pin #. 'F' and 'R' work the others don't, the pixels are dark. I'll play with it.

#39  

I just tested and it is working great. Thank you Robert. This is very nice. I used 1 for right I believe. This will make a lot of EZ-Robot InMoov owners very happy.

Just to be clear of how I have everything wired up...

V4 D0 is connected to RX1 on the arduino mini pro

Ground from the Arduino mini pro is wired to the neopixel ground.

Pin 6 from the Arduino mini pro is wired to the neopixel data in.

  • Power to the neopixel and the Arduino is running from a voltage regulator that reduces from 12 V to 5 V.
  • power to the Arduino is connected to the voltage regulator.

In ARC I have tested these different modes. They are cool. You wouldn't just want to run this script as it would probably flash the neopixel and then go black. These are some examples of how to use it.


#White light
SendSerial(d0, 9600, &quot;C100,100,100&quot;)

#Ring rotating to the right
SendSerial(d0, 9600, &quot;R10,1&quot;)

#fade from black to red
SendSerial(d0, 9600, &quot;F255,0,0,0,0,0,50,2000,1&quot;)

#Turn off neopixel
SendSerial(d0, 9600, &quot;C0,0,0&quot;)


#40  

@ d.cochrane, did all of it work?

#42  

Thanks Dave, got it working - very cool. I am trying to change the color in the "Fade", Could you explain to me what numbers in this string represent( not the port and baud rate)

SendSerial( D18,9600,"F255,0,0,0,0,0,50,20,1")

Thanks

#43  

/ 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

Speeding it up or slowing it down would be the 50 and 20. the 50 is the number of steps it uses to fade, and 20 is how quickly it does it.

SendSerial(d0, 9600, "F255,0,0,0,0,0,50,25,R") looks pretty good to me personally. The only one I couldnt get to work right was the Wipe.

/ 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

@Robert, thanks again, you did an awesome job on this.

#44  

Thanks Dave, How do I change to color in the Fade from red (thats what it's set to) to Blue? Yes, Robert this is good!

#45  

RED


SendSerial(d0, 9600, &quot;F255,0,0,0,0,0,50,25,R&quot;)

GREEN


SendSerial(d0, 9600, &quot;F0,255,0,0,0,0,50,25,R&quot;)

BLUE


SendSerial(d0, 9600, &quot;F0,0,255,0,0,0,50,25,R&quot;)

#46  

@Merne, I have a second arduino mini pro tested with the code loaded and ready to ship if you would like me to send it to you. Let me know.

#47  

Thanks Dave, I get it now!

#48  

Not sure why you have an R in the last field of Fade command. It should either be a zero or a one.

For forward:



SendSerial(d0, 9600, &quot;F0,0,255,0,0,0,50,25,0&quot;) 

For reverse:




SendSerial(d0, 9600, &quot;F0,0,255,0,0,0,50,25,1&quot;)

Glad it is working for you. I didn't know if I should post it without testing, but I wanted you to have a decent jump off point. It should be fairly responsive to serial commands. I trust you will post any fixes. I have no clue at the moment why color wipe might not work. Only the serial decoding and setup of commands is really mine. The rest comes from the adafruit lesson 3.

Post a video of it working sometime if you can.

#49  

will do when I get off of work. Thanks!

Okay, the neopixel ring, not camera controlled by an Arduino mini pro...

#51  

Thanks for the video. It was neat to see it working with the ez-b that is the part I had no way to test at the moment.

You should have no problem with it driving a second ring. You can see in the adafruit tutorial 3 example how they drove two neopixel rings and a neopixel strip. Just need to add some more serial commands to control the rings separately or together and declare the second ring on a different arduino I/O pin.

Getting a video of neopixels is never easy.

#52  

The code I posted does not use the brightness setting that is sometimes in Neopixel code. This is because the Brightness setting affects the number of colors that are available from the Neopixel LEDs. The three arguments for the pixel color are red, green and blue LED brightness levels, where 0 is dimmest (off) and 255 is maximum brightness. So color (red, green, and blue) has 256 levels as long as the Brightness is not set lower than max. You have 16,777,216 colors available to you. Neopixels are really bright try numbers lower than 255.

Here are some notes from adafruit about hardware connection:

Quote:

Before connecting NeoPixels to any power source, add a large capacitor (1000 µF, 6.3V or higher) across the + and terminals

Quote:

Place a 300 to 500 Ohm resistor between the Arduino data output pin and the input to the first NeoPixel. This resistor must be at the NeoPixel end of the wire to be effective! Some products already incorporate this resistorif you’re not sure, add onethere’s no harm in doubling up!

Quote:

Try to minimize the distance between the Arduino and first pixel.

The longer the wiring between the arduino and the neopixels the more important the 300 to 500 ohm resistor becomes.

The same goes for the Capacitor. The longer the wiring between the Neopixel Strip and the power source the more important the Capacitor becomes. If you can't fit them right at the neopixel end get as close as you can.

For really short distances the resistor and capacitor are often not needed.

#53  

Here's a short video of a Neo Pixel Ring running off a EZBv4 thru an Arduino Uno. It is hard to video the ring because it is so bright. Thanks Luis V, RobertL and d. cochrane for all your help getting this up and running.

#54  

Hi @ all

i tryed the Code/script from Robert!

An i like it really much!

Everything works, but only the "Scanner"/"Knight rider" functions has some problems.

SendSerial( D18,9600,"S,255,0,0,20" )

If i change to some scripts and then back to the Scanner Script, often this Script not start, so the Neopixel Ring will be still black!

Boris

#55  

send a ("C0,0,0") to turn off the ring before sending another command. It might be ("C,0,0,0"), i cant remember off the top of my head.

#56  

Hello David,

i check your tipp with sending a "turn light off" command, but the same situation with the scanner fx. All other Commands like Wipe, Rainbow, Color, Fade works 100% perfekt without sending a "light off" command, only the Scanner Command not works everytime.

Now i sending this code:


SendSerial(1. d0, 9600, &quot;C0,0,0&quot;)
sleep(100)
SendSerial(1. d0, 9600, &quot;S,255,0,0,40


and now its works like that:

one red pixel is turning on for one second and then tunring off. Thats it. I can repeat this 10 times, all time the same.

To correct this problem i must send some other commands like a "fade" or "wipe" and then again sending the "scanner" command and then he works.

If you don´t know, nevermind, all other commands works to 100%, i only wondering why only the scanner command no works. I think in the Arduino Code must be the mistake/error

Boris

#57  

@rentaprinta I originally put the arduino code together from examples on the adafruit site. (There are references in the posts.) I didn't have a neopixel ring to test it and still don't. It is quite possible that there is a mistake/error in the code. It seemed to solve the problem the original poster of this string of messages needed a fix for. So the poster was happy and I was glad I could help.

#58  

@RobertL184

Sorry for the question: So the best solution is , not to use the "scanner" fx or do you know a method or somebody what/who can fix the error?

Boris

#59  

@renta, I'm not sure what the Scanner FX looks like. Can you describe it? Maybe I have it in my Arduino sketch.

#60  

Hi Bob!

The Scanner FX is a red dot/pixel what starts on the left site and turn to the right and back to the left and so on.

Image the "Knight Rider" Light but not as a stripe - now in a circle.

Sometime the red light starts and make the moving, but sometime the red light goes on for one second and then goes off and thats it.

Like i said. all other oves like the Wipe;Fade;Rainbow,Color works fine! Only the Scanner makes problems!

Boris

#61  

@Renta, I hope this is the "Scanner FX you're looking for. I think we are using the same Arduino sketch, if not then it probably won't work - I could send you mine.

Try this, this will run indefinitely or until another command is sent,


SendSerial(1.D18, 9600, &quot;W250,0,0,250,0,0&quot;)
SendSerial(1.D18, 9600, &quot;C0,0,0&quot;)
SendSerial(1.D18, 9600, &quot;S250,0,0,250,0,0&quot;)

If you want it run for a set period of time, Try this example, this will run for 60 seconds, then stop.


SendSerial(1.D18, 9600, &quot;W250,0,0,250,0,0&quot;)
SendSerial(1.D18, 9600, &quot;C0,0,0&quot;)
SendSerial(1.D18, 9600, &quot;S250,0,0,250,0,0&quot;)
sleep(60000)
SendSerial(1.D18, 9600, &quot;C0,0,0&quot;)

Change the port to your setting

#62  

@RobertL184 Hi Robert, I tried your code for multitasking with a neopixel ring and no matter what input I use (C, R, F or T....) the pixels stay dark! I know the HW setup and connections are all correct. Am I missing something or there is something missing from the code? In order to successfully compile the code I added

void Ring1Complete();

right above the neoPatterns Also, added

Ring1.setBrightness(50);

to set overal brightness

And my final question is: I have added a potentiometer to Arduino multi-tasking code part-3 which is working fine. The pot is for controlling the brightness, however I would like to learn how to remove serial input from your code and make it go through all the animations steps within the loop. I now I can use the strandtest to achieve my goal, but then due to delay() I have to wait for the entire loop to complete before seeing the new brightness setting (through potentiometer).

Thanks, Ron

#63  

If you don't want the serial interface you should check out the code in this adafruit learning guide.

https://learn.adafruit.com/multi-tasking-the-arduino-part-3/overview

You can modify the update routine to read your potentiometer and modify the brightness at that point. It may not modify the brightness immediately but it should modify the within a reasonable amount of time.

#64  

@RobertL184 Thank you for your quick reply. I'm sorry if I was not clear with question. I have the pot working with the Adafruit multi-tasking part-3 and it's responsive. I would like to get your code working for my project and the issue I am running into is that all LEDs are dark and I have combed through the code and I was not able to find the culprit.

BTW - I added my potentiometer code to your code and monitored it via serial UI and it's working. I would like to know if there is anything missing from the code causing the ring to stay dark. If not, then I am doing something wrong.

Thanks

#65  

If nothing with my code seems to make the neopixels work it may be that the neopixel data pin is different than what you have wire up.

The mulitasking code has a strand on pins 5,6, and 7

NeoPatterns Ring1(24, 5, NEO_GRB + NEO_KHZ800, &Ring1Complete); NeoPatterns Ring2(16, 6, NEO_GRB + NEO_KHZ800, &Ring2Complete); NeoPatterns Stick(16, 7, NEO_GRB + NEO_KHZ800, &StickComplete);

My code has the strand on pin 6

NeoPatterns Ring1(16, 6, NEO_GRB + NEO_KHZ800, &Ring1Complete);

So the first thing to check is that the NeoPattern Ring1 is being called with the correct pin number to match your wiring.

The second thing to note is that my code was hacked together to allow the EZ-B to control the neopixel strip. To get the arduino to light up the string you want to have the EZ-B send the arduino a command.

Like "F0,0,255,0,0,0,50,25,0" to have it do a fade.

The command for the EZ-B to do this is SendSerial(d0, 9600, "F0,0,255,0,0,0,50,25,0") assuming of course that the arduino is wired up to get serial data from the "d0" pin.

To try is you can use the serial monitor in the arduino IDE to send the serial string to the arduino.

If you don't want any serial control at all. The multitasking code should work for you.

#66  

Here is a version of my code with the larson scanner fixed.


/* 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 &lt;Adafruit_NeoPixel.h&gt;
 
// 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) &gt; 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 &gt;= TotalSteps)
            {
                Index = 0;
                if (OnComplete != NULL)
                {
                    OnComplete(); // call the comlpetion callback
                }
            }
        }
        else // Direction == REVERSE
        {
            --Index;
            if (Index &lt;= 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&lt; numPixels(); i++)
        {
            setPixelColor(i, Wheel(((i * 256 / numPixels()) + Index) &amp; 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&lt; 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 &lt; 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) &gt;&gt; 1, Green(color) &gt;&gt; 1, Blue(color) &gt;&gt; 1);
        return dimColor;
    }
 
    // Set all pixels to a color (synchronously)
    void ColorSet(uint32_t color)
    {
        for (int i = 0; i &lt; numPixels(); i++)
        {
            setPixelColor(i, color);
        }
        show();
    }
 
    // Returns the Red component of a 32-bit color
    uint8_t Red(uint32_t color)
    {
        return (color &gt;&gt; 16) &amp; 0xFF;
    }
 
    // Returns the Green component of a 32-bit color
    uint8_t Green(uint32_t color)
    {
        return (color &gt;&gt; 8) &amp; 0xFF;
    }
 
    // Returns the Blue component of a 32-bit color
    uint8_t Blue(uint32_t color)
    {
        return color &amp; 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 &lt; 85)
        {
            return Color(255 - WheelPos * 3, 0, WheelPos * 3);
        }
        else if(WheelPos &lt; 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, &amp;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() &gt; 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();
    }
}


I haven't tried the updated code with CochranRobotics EZ-B Plugin.

#67  

If you really want to use my code and don't want any serial input you need to replace the main loop with something like this:


void loop()
{
      red1 = 255;     // for red
      green1 = 0;   //  for green
      blue1 = 0;    //  for blue
      red2 = 0;     //  for second red
      green2 = 255;   // for second green
      blue2 = 0;    // for second blue
      t=100;
      Ring1.ActivePattern = NONE;
      Ring1.ColorSet(Ring1.Color(red1, green1, blue1));     
      Ring1.RainbowCycle(t, FORWARD); 
      Ring1.RainbowCycle(t, REVERSE);
      Ring1.Fade(Ring1.Color(red1, green1, blue1), Ring1.Color(red2, green2, blue2), s, t, FORWARD); 
     Ring1.Fade(Ring1.Color(red1, green1, blue1), Ring1.Color(red2, green2, blue2), s, t, REVERSE); 
    Ring1.TheaterChase(Ring1.Color(red1, green1, blue1), Ring1.Color(red2, green2, blue2), t, FORWARD);
    Ring1.TheaterChase(Ring1.Color(red1, green1, blue1), Ring1.Color(red2, green2, blue2), t, REVERSE);
      Ring1.ActivePattern = NONE;
      Ring1.ColorSet(Ring1.Color(red1, green1, blue1));     
    Ring1.ColorWipe(Ring1.Color(red1, green1, blue1), t, FORWARD);
      Ring1.ActivePattern = NONE;
      Ring1.ColorSet(Ring1.Color(red1, green1, blue1));     
      Ring1.ColorWipe(Ring1.Color(red1, green1, blue1), t, REVERSE);
      Ring1.ColorWipe(Ring1.Color(red1, green1, blue1), 50, 0);
      Ring1.ColorSet(Ring1.Color(0,0, 0));
      Ring1.Scanner(Ring1.Color(red1, green1, blue1), t);
}

Modify the variables:

red1, green1, blue1, red2, blue2, green2, and t for the colors and delay time you want.

I haven't complied the code above so don't know as it will work without some debugging.

You didn't mention where you put the code to read you potentiometer and set the Brightness in the multitasking code, but you could most likely put it in the same place in my code. It is based on the multitasking code.

Remember setting the strand brightness reduces the number of colors available for the entire strand. The same effect can be had for most of the routines my simply changing the red1, green1, blue1, red2, blue2, green2 variable to smaller values. The exception to this is the rainbow routine which uses all of the colors. For that one routine the Brightness setting would work best.

#68  

@RobertL184

Robert, Thank you for all your feedback and I will re-check the Arduino pin connection, but I am certain that is not the cause. When I change the

Ring1.ColorSet(Ring1.Color(0, 0, 0)); to Ring1.ColorSet(Ring1.Color(20, 0, 0));

the ring lights up. Also, I put few println in the code for sanity check and I see the output is the SUI.

Below is the code I added to yours and Arduino multi-tasking part-3 for the potentiometer and I know it works with the latter. The ints are placed under the NeoPatterns line and the rest is placed within the loop. I have Ring1,Ring2 and Stick for the Arduino multi-tasking and only Ring1 for your code.

void Ring1Complete();

int potPin                = A0; // Potentiometer input
int potVal                 =  0; // Potentiometer value
int ringBrightness  =  0; // Brightness of LEDs
int lastpot                =  0; // last potentiometer reading to compair with

// Main loop
void loop()
{
  potVal = analogRead(potPin);
  if ( potVal != lastpot ) {
    lastpot = potVal;
    ringBrightness = map(potVal, 0, 1023, 0, 250);
    Ring1.setBrightness(ringBrightness);
  }

I will let you once I get everything working.

#69  

I've been trying to load the code from post # 37 and I get a bunch of error messages. It worked when it was first posted but I can get it to load now. Could someone try loading it and see if it works. Maybe it's my system, I don't know.

Thanks

#70  

To download this version of the Arduino IDE ==> (previous versions link)

I think it was 1.6.4 that I used back then but it has been a while since I have looked.

I think what is happening is that you have to use a previous version of the Arduino IDE in order to compile the code from that long ago. I think the link above will take you to the version that you would have to use. The later post should work with a more current version of the IDE.

#71  

From my plugin that uses this code...

"The code below works with Arduino IDE 1.6.3 with the 1.0.3 version of the Adafruit NeoPixel library,"

#72  

Thanks Dave. I installed Arduino IDE 1.6.3 and the sketch loaded OK and works good.

#73  

This sketch fixes a minor bug that existed in the last code published by RobertL184. It works with Arduino 1.8.3 and the NeoPixel library v1.1.1

If you want to change the pin that the arduino is connecting to the NeoPixel on, change the 2nd parameter in line 321. If you want to change the number of NeoPixles in the ring or device, change the first parameter in line 321.

Example


NeoPatterns Ring1(24, 6, NEO_GRB + NEO_KHZ800, &amp;Ring1Complete);

is for a 24 pixel NeoPixel that has its input pin connected to pin 6 on the Arduino.


/* 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 &lt;Adafruit_NeoPixel.h&gt;
 
// 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) &gt; 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 &gt;= TotalSteps)
            {
                Index = 0;
                if (OnComplete != NULL)
                {
                    OnComplete(); // call the comlpetion callback
                }
            }
        }
        else // Direction == REVERSE
        {
            --Index;
            if (Index &lt;= 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&lt; numPixels(); i++)
        {
            setPixelColor(i, Wheel(((i * 256 / numPixels()) + Index) &amp; 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&lt; 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 &lt; 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) &gt;&gt; 1, Green(color) &gt;&gt; 1, Blue(color) &gt;&gt; 1);
        return dimColor;
    }
 
    // Set all pixels to a color (synchronously)
    void ColorSet(uint32_t color)
    {
        for (int i = 0; i &lt; numPixels(); i++)
        {
            setPixelColor(i, color);
        }
        show();
    }
 
    // Returns the Red component of a 32-bit color
    uint8_t Red(uint32_t color)
    {
        return (color &gt;&gt; 16) &amp; 0xFF;
    }
 
    // Returns the Green component of a 32-bit color
    uint8_t Green(uint32_t color)
    {
        return (color &gt;&gt; 8) &amp; 0xFF;
    }
 
    // Returns the Blue component of a 32-bit color
    uint8_t Blue(uint32_t color)
    {
        return color &amp; 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 &lt; 85)
        {
            return Color(255 - WheelPos * 3, 0, WheelPos * 3);
        }
        else if(WheelPos &lt; 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, &amp;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() &gt; 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();
      }
}

This will work with the plugin still. The commands don't change so there is no modification to the plugin.