Page 1 of 1
Forum

Welcome to the Tweaking4All community forums!
When participating, please keep the Forum Rules in mind!

Topics for particular software or systems: Start your topic link with the name of the application or system.
For example “MacOS X – Your question“, or “MS Word – Your Tip or Trick“.

Please note that switching to another language when reading a post will not bring you to the same post, in Dutch, as there is no translation for that post!



Trying to convert C...
 
Share:
Notifications
Clear all

[Solved] Trying to convert Cylon to multiple strips

6 Posts
2 Users
0 Likes
1,050 Views
 rai
(@rai)
Active Member
Joined: 8 years ago
Posts: 3
Topic starter  

Hello,

first i want to thank you for this really nice guide. 

Right now i am trying to convert your cylon effekt for multiple strips. It already runs, but i need to define the leds for each stripe because the lednumber is different in my setup. i already tried to make a second CylonBounce Objekt that points to NUM_LEDs_B but that didn't work.

Many thanks in advance. 

Best regards,

Boris

#include <Adafruit_NeoPixel.h>
#define NUM_LEDS 60
#define NUM_LEDS_B 10
#define PIN 10
#define PIN_B 6
// Parameter 1 = number of pixels in strip
// Parameter 2 = 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(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip_2 = Adafruit_NeoPixel(NUM_LEDS_B, PIN_B, NEO_GRB + NEO_KHZ800);
void setup() {
  strip.begin();
   strip_2.begin();
  strip.show(); 
  strip_2.show(); 
  // Initialize all pixels to 'off'
}
void loop() {
  CylonBounce(255, 255, 255, 10, 10, 50);
}
void CylonBounce(byte red, byte green, byte blue, int EyeSize, int SpeedDelay, int ReturnDelay){
  for(int i = 0; i < NUM_LEDS-EyeSize-2; i++){
    setAll(0,0,255);
    setPixel(i, red/10, green/10, blue/10);
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(i+j, red, green, blue); 
    }
    setPixel(i+EyeSize+1, red/10, green/10, blue/10);
    showStrip();
    delay(SpeedDelay);
  }
  delay(ReturnDelay);
  for(int i = NUM_LEDS-EyeSize-2; i > 0; i--) {
    setAll(0,0,255);
    setPixel(i, red/10, green/10, blue/10);
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(i+j, red, green, blue); 
    }
    setPixel(i+EyeSize+1, red/10, green/10, blue/10);
    showStrip();
    delay(SpeedDelay);
  }
  
  delay(ReturnDelay);
}
// REPLACE TO HERE
void showStrip() {
 #ifdef ADAFRUIT_NEOPIXEL_H 
   // NeoPixel
   strip.show();
    strip_2.show();
 #endif
 #ifndef ADAFRUIT_NEOPIXEL_H
   // FastLED
   FastLED.show();
 #endif
}
void setPixel(int Pixel, byte red, byte green, byte blue) {
 #ifdef ADAFRUIT_NEOPIXEL_H 
   // NeoPixel
   strip.setPixelColor(Pixel, strip.Color(red, green, blue));
   strip_2.setPixelColor(Pixel, strip_2.Color(red, green, blue));
 #endif
 #ifndef ADAFRUIT_NEOPIXEL_H 
   // FastLED
   leds[Pixel].r = red;
   leds[Pixel].g = green;
   leds[Pixel].b = blue;
 #endif
}
void setAll(byte red, byte green, byte blue) {
  for(int i = 0; i < NUM_LEDS; i++ ) {
    setPixel(i, red, green, blue); 
  }
  showStrip();
}

   
ReplyQuote
 Hans
(@hans)
Noble Member Admin
Joined: 11 years ago
Posts: 1065
 

Thanks Rai! 

What is happening with the code you have? Does it do anything at all?

I see a few potential issues to begin with.
The way your function works right now, it only bounces one strip and once completed it bounces the second one.
Is this what you want? Or do they need to run in parallel?

The first problem is that you use the "setAll" and "showStrip" without having it modified to work for both strips.

Right now you have:

void setAll(byte red, byte green, byte blue) {
  for(int i = 0; i < NUM_LEDS; i++ ) {
    setPixel(i, red, green, blue); 
  }
  showStrip();
}

I would probably modify it to something like the following.

I would rewrite "showStrip()" to (I removed the FastLED code as well):

void showStrip(byte stripnumber) {
   if (stripnumber==1) { 
     strip.show(); }
   else {
    strip_2.show(); }
}

Which implies that every call for "showStrip" has to be changed to "showStrip(1)" for strip 1 and "showStrip(2)" for strip 2.

Next I'd modify the "setAll()" function to something like this:

void setAll(byte red, byte green, byte blue, byte stripnumber) {
  int number_of_leds;
  if(stripnumber==1) {
    number_of_leds=NUM_LEDS; }
  else {
    number_of_leds=NUM_LEDS_B; }
  for(int i = 0; i < number_of_leds; i++ ) {
    setPixel(i, red, green, blue); 
  }
  showStrip(stripnumber);
}

Which means that all calls for "setAll()" need to be changed to "setAll(1)" for strip 1 or "setAll(2)" for strip 2.

Of course you can now clean up "setPixel()" as well, to the following since you use NeoPixel anyway:

void setPixel(int Pixel, byte red, byte green, byte blue) {
 strip.setPixelColor(Pixel, strip.Color(red, green, blue));
 strip_2.setPixelColor(Pixel, strip_2.Color(red, green, blue));
}

But ... I'd change it even to add the stripnumber as well, to something like this:

void setPixel(int Pixel, byte red, byte green, byte blue, byte stripnumber) {
  if(stripnumber==1) {
     strip.setPixelColor(Pixel, strip.Color(red, green, blue)); }
  else {
     strip_2.setPixelColor(Pixel, strip_2.Color(red, green, blue)); }
}

Again, you need to modify all calls for "setPixel" as well, so "setAll" for example would become:

void setAll(byte red, byte green, byte blue, byte stripnumber) {
  int number_of_leds;
  if(stripnumber==1) {
    number_of_leds=NUM_LEDS; }
  else {
    number_of_leds=NUM_LEDS_B; }
  for(int i = 0; i < number_of_leds; i++ ) {
    setPixel(i, red, green, blue, stripnumber); 
  }
  showStrip(stripnumber);
}

Based on these suggested changes, your code would look something like this:

#include <Adafruit_NeoPixel.h>
#define NUM_LEDS 60
#define NUM_LEDS_B 10
#define PIN 10
#define PIN_B 6
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip_2 = Adafruit_NeoPixel(NUM_LEDS_B, PIN_B, NEO_GRB + NEO_KHZ800);
void setup() {
  strip.begin();
  strip_2.begin();
  strip.show(); 
  strip_2.show(); 
  // Initialize all pixels to 'off'
}
void loop() {
  CylonBounce(255, 255, 255, 10, 10, 50);
}
void CylonBounce(byte red, byte green, byte blue, int EyeSize, int SpeedDelay, int ReturnDelay){
  for(int i = 0; i < NUM_LEDS-EyeSize-2; i++){
    setAll(0,0,255,1); // added strip number
    setPixel(i, red/10, green/10, blue/10,1); // added strip number
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(i+j, red, green, blue,1);  // added strip number
    }
    setPixel(i+EyeSize+1, red/10, green/10, blue/10,1); // added strip number
    showStrip(1); // added strip number
    delay(SpeedDelay);
  }
  delay(ReturnDelay);
  for(int i = NUM_LEDS-EyeSize-2; i > 0; i--) { // added stripnumbers here too
    setAll(0,0,255,2);
    setPixel(i, red/10, green/10, blue/10,2);
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(i+j, red, green, blue,2); 
    }
    setPixel(i+EyeSize+1, red/10, green/10, blue/10,2);
    showStrip(2);
    delay(SpeedDelay);
  }
  
  delay(ReturnDelay);
}
// REPLACE TO HERE
void showStrip(byte stripnumber) {
   if (stripnumber==1) { 
     strip.show(); }
   else {
     strip_2.show(); }
}
void setPixel(int Pixel, byte red, byte green, byte blue, byte stripnumber) {
  if(stripnumber==1) {
     strip.setPixelColor(Pixel, strip.Color(red, green, blue)); }
  else {
     strip_2.setPixelColor(Pixel, strip_2.Color(red, green, blue)); }
}
void setAll(byte red, byte green, byte blue, byte stripnumber) {
  int number_of_leds;
  if(stripnumber==1) {
    number_of_leds=NUM_LEDS; }
  else {
    number_of_leds=NUM_LEDS_B; }
  for(int i = 0; i < number_of_leds; i++ ) {
    setPixel(i, red, green, blue, stripnumber); 
  }
  showStrip(stripnumber);
}

Now mind you that I've only adapted the few functions to work with 2 strips instead of one.
Your loop to do the bounce, is probably in need of some change as well - depending on the effect you'd like.

Please review the code, I did type this without testing ... 


   
ReplyQuote
 rai
(@rai)
Active Member
Joined: 8 years ago
Posts: 3
Topic starter  

Wow thanks a lot, you are really fast. I want the same bounce on both strips but different led count. With my old code it did it like in your tutorial and your video. But for the second shorter strip... It thought there would be 60 leds too, so the white glow ran out of the strip.

with your code it just ran backwards on both strips. I tried to edit and now it does the same again like an my code. But still doesn't bounce back on second strip led 10... it still thinks there are 60 leds on strip2.

Thanks again,

Boris


#include <Adafruit_NeoPixel.h>
#define NUM_LEDS 60
#define NUM_LEDS_B 10
#define PIN 10
#define PIN_B 6
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel strip_2 = Adafruit_NeoPixel(NUM_LEDS_B, PIN_B, NEO_GRB + NEO_KHZ800);
void setup() {
  strip.begin();
  strip_2.begin();
  strip.show(); 
  strip_2.show(); 
  // Initialize all pixels to 'off'
}
void loop() {
  CylonBounce(255, 255, 255, 3, 10, 50);
}
void CylonBounce(byte red, byte green, byte blue, int EyeSize, int SpeedDelay, int ReturnDelay){
  for(int i = 0; i < NUM_LEDS-EyeSize-2; i++){
    setAll(0,0,255,1); // added strip number
    setAll(0,0,255,2);
    setPixel(i, red/10, green/10, blue/10,1); // added strip number
    setPixel(i, red/10, green/10, blue/10,2);
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(i+j, red, green, blue,1); // added strip number
      setPixel(i+j, red, green, blue,2);
    }
    setPixel(i+EyeSize+1, red/10, green/10, blue/10,1); // added strip number
    setPixel(i+EyeSize+1, red/10, green/10, blue/10,2); // added strip number
    showStrip(1);
    showStrip(2);
    delay(SpeedDelay);
  }
  delay(ReturnDelay);
  for(int i = NUM_LEDS-EyeSize-2; i > 0; i--) { // added stripnumbers here too
    setAll(0,0,255,1);
    setAll(0,0,255,2);
    setPixel(i, red/10, green/10, blue/10,1);
    setPixel(i, red/10, green/10, blue/10,2);
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(i+j, red, green, blue,1); 
      setPixel(i+j, red, green, blue,2); 
    }
    setPixel(i+EyeSize+1, red/10, green/10, blue/10,1);
    setPixel(i+EyeSize+1, red/10, green/10, blue/10,2);
    showStrip(1);
    showStrip(2);
    delay(SpeedDelay);
  }
  
  delay(ReturnDelay);
}
// REPLACE TO HERE
void showStrip(byte stripnumber) {
   if (stripnumber==1) { 
     strip.show(); }
   else {
     strip_2.show(); }
}
void setPixel(int Pixel, byte red, byte green, byte blue, byte stripnumber) {
  if(stripnumber==1) {
     strip.setPixelColor(Pixel, strip.Color(red, green, blue)); }
  else {
     strip_2.setPixelColor(Pixel, strip_2.Color(red, green, blue)); }
}
void setAll(byte red, byte green, byte blue, byte stripnumber) {
  int number_of_leds;
  if(stripnumber==1) {
    number_of_leds=NUM_LEDS; }
  else {
    number_of_leds=NUM_LEDS_B; }
  for(int i = 0; i < number_of_leds; i++ ) {
    setPixel(i, red, green, blue, stripnumber); 
  }
  showStrip(stripnumber);
}

   
ReplyQuote
 Hans
(@hans)
Noble Member Admin
Joined: 11 years ago
Posts: 1065
 

Hi Rai!

You're welcome ....

Well, there are a few problems with your code.

First problem is that you set the pixel for each LED of both strips in the same loop, and that loop counts to 60 ...

    for(int i = 0; i < NUM_LEDS-EyeSize-2; i++){
     ...
    }

See how you use NUM_LEDS  here, yet you call setPixel for both of the strips in that loop.

For both to bounce simultaneously, we would probably have to apply a trick. Probably something like this:

void CylonBounce(byte red, byte green, byte blue, int EyeSize, int SpeedDelay, int ReturnDelay){
  int i2; // counter for the 2nd strip
  for(int i = 0; i < NUM_LEDS-EyeSize-2; i++) {
    setAll(0,0,255,1); setAll(0,0,255,2); i2 = i / (NUM_LEDS/NUM_LEDS_B); // take a fraction, since the strip is not as long
    setPixel(i, red/10, green/10, blue/10,1); setPixel(i2, red/10, green/10, blue/10,2);
    for(int j = 1; j <= EyeSize; j++) {
      setPixel(i+j, red, green, blue,1);  setPixel(i2+j, red, green, blue,2);
    }
    setPixel(i+EyeSize+1, red/10, green/10, blue/10,1); setPixel(i2+EyeSize+1, red/10, green/10, blue/10,2);
    showStrip(1); showStrip(2);
    delay(SpeedDelay);
  }
  delay(ReturnDelay);
  // etc ...
}

Now the problem you might run into is that you're dividing and integer (int) which can can result in a non-integer (float, for example 1/6). I believe the Arduino will handle this right, and return an integer. But it will truncate the result, I think. So 1/6 will become 0, 1.8 will become 1, etc).
I have not been able to test this though.

A side effect might be that the short strip might not have a LED lighting up ... you'll have to test this.

If this does become a problem, then we need to look for a better trick, where we check if the division results in an integer or not. If it does: set the LED, if not, ignore it. We'd have to use an "if" statement for that.

For example:

  if( (i / (NUM_LEDS/NUM_LEDS_B)) * (NUM_LEDS/NUM_LEDS_B) ) == i) { ... }

So we divide i first and the multiply it again with what we used to divide. If this results in "i" then we didn't loose any numbers behind the decimal point and are we indeed dealing with a proper LED.

This would then need to be applied to each of the "setPixel(....,2)" lines, like this for example:

  if( (i / (NUM_LEDS/NUM_LEDS_B)) * (NUM_LEDS/NUM_LEDS_B) ) == i) {
    setPixel(i2+EyeSize+1, red/10, green/10, blue/10,2); }

Obviously this can be done smarter, by doing the calculation only once, by introducing a boolean at the beginning of the function;

   boolean isLED;

And where we calculate i2:

  isLED = (i / (NUM_LEDS/NUM_LEDS_B)) * (NUM_LEDS/NUM_LEDS_B) ) == i;

And where we write the "if" statement:

  if( isLED ) {  setPixel(i2+EyeSize+1, red/10, green/10, blue/10,2); }

Much shorter and faster ... but you'll have to do some experimenting, and I hope I didn't make any typo's ... 


   
ReplyQuote
 rai
(@rai)
Active Member
Joined: 8 years ago
Posts: 3
Topic starter  

Thanks a lot, i think the Arduino handles the integer correct. Both Effects work now! But i think we have a problem with delay now, because the second stripe takes the same time to bounce from one side to another as the long stripe. This results in a much slower effect for the short one. 

Or maybe this is because of not handling the integer correct? But in result of that there should be any effect at all or am i wrong?


   
ReplyQuote
 Hans
(@hans)
Noble Member Admin
Joined: 11 years ago
Posts: 1065
 

Awesome! 
We are making progress ....

The slower bounce for the short one is because we do it in parallel with the longer strip.
If you want to have the short one bounce independently, then things will become a lot more complicated.

The Arduino natively does not do multitasking, so we cannot have 2 bounces run at the same time, in a different pace.
One method could be by using global variables and determine the bounce direction by changing a global variable that tracks direct and LED position for each strip. That would take more time to write and would look very differently from what we have right now.

Another trick could be that in each for-loop, we turn direction for the short strip after 10 LEDs have been done. Again; this would result in a lot of code to write and test with. 
What I mean with that, is that in the for-loop, for the long strip we just do as before, but for the short strip;

1st 10: normal (0 to 9)
2nd 10: reverse (from 9 back to 0)
3rd 10: normal but correct counter so it starts at 0 and goes up to 9
4th 10: reverse (from 9 back to 0)
5th 10: normal but correct counter so it starts at 0 and goes up to 9
6th 10: reverse (from 9 back to 0)

Which just takes a if...then... to catch, and a small calculation to correct the counter.
This needs to be done for the 2nd for...loop as well.


   
ReplyQuote
Share: