Leds moving along an led rgb strip

Here I have a small program with a single led moving along a strip, I want to add a 2nd led to move along the strip with 5 leds spaces between them. What do I need to add to the program to achieve this?

[code]
//Leds chase forwards along strip

#include <FastLED.h>
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB

#define NUM_LEDS 60
#define DATA_PIN 5
#define BRIGHTNESS         32

CRGB leds[NUM_LEDS];

unsigned long delayPeriod = 50;

void setup() {
  delay(2000);
  FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);  // GRB ordering is typical
  FastLED.setBrightness(BRIGHTNESS);
}

void loop()  {
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CRGB::Red;
    FastLED.show();
    leds[i] = CRGB::Black;;
    delay(delayPeriod);
    
  }

}

[/code]

This is an attempt to get 2 leds moving along the strip, not quite right lol I think the method is in the for loop I'm just not sure of the syntax.

[code]
//Leds chase forwards along strip

#include <FastLED.h>
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB

#define NUM_LEDS 60
#define DATA_PIN 5
#define BRIGHTNESS         96

CRGB leds[NUM_LEDS];

unsigned long delayPeriod = 50;

void setup() {
  delay(2000);
  FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);  // GRB ordering is typical
  FastLED.setBrightness(BRIGHTNESS);
}

void loop()  {
  for (int i = 0; i < NUM_LEDS; i++) {
    for (int j = 0; j < NUM_LEDS; j++) {
    leds[i] = CRGB::Red;
    leds[j] = CRGB::Green;
    //leds[j] = leds[i];
    FastLED.show();
    leds[i] = CRGB::Black;
    leds[j] = CRGB::Black;
    delay(delayPeriod);
    //leds[10] = leds[i];
  }

}
}

[/code]

In the first code try

leds[i] = CRGB::Red;
if (i >= 5)
{
  leds[i - 5] = CRGB::Red;
}

and something similar to turn off the second LED

What should happen when the first LED reaches the end of the strip ?

UKHeliBob:
In the first code try

leds[i] = CRGB::Red;

if (i >= 5)
{
  leds[i - 5] = CRGB::Red;
}



and something similar to turn off the second LED

What should happen when the first LED reaches the end of the strip ?

Thanks for that code and to answer your question (What should happen?) I hadn't thought that far ahead lol I can see from the code that once the red led reaches the end of the strip all the others stop.

[code]
//Leds chase forwards along strip

#include <FastLED.h>
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB

#define NUM_LEDS 60
#define DATA_PIN 5
#define BRIGHTNESS         96

CRGB leds[NUM_LEDS];

unsigned long delayPeriod = 50;

void setup() {
  delay(2000);
  FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);  // GRB ordering is typical
  FastLED.setBrightness(BRIGHTNESS);
}

void loop()  {
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i]  = CRGB::Red;
    if (i >= 5) {
      leds[i - 5] = CRGB::Yellow;
    }
    if (i >= 10) {
      leds[i - 10] = CRGB::Green;
    }
    if (i >= 15) {
      leds[i - 15] = CRGB::Cyan;
    }
    if (i >= 20) {
      leds[i - 20] = CRGB::Blue;
    }
    if (i >= 25) {
      leds[i - 25] = CRGB::Magenta;
    }
    FastLED.show();
    leds[i] = CRGB::Black;
    
    if (i >= 5) {
      leds[i - 5] = CRGB::Black;
    }
    if (i >= 10) {
      leds[i - 10] = CRGB::Black;
    }
    if (i >= 15) {
      leds[i - 15] = CRGB::Black;
    }
    if (i >= 20) {
      leds[i - 20] = CRGB::Black;
    }
    if (i >= 25) {
      leds[i - 25] = CRGB::Black;
    }
    delay(delayPeriod);
  }


}

[/code]

I suggest that you get the single colour LED and partner working before adding more colours

What I had in mind when asking about what happens at the end of the end of the strip is that it is all very well turning on LED i and LED i - 5 but do you want the second LED to move along its final 5 steps or is it OK just to turn it off when the first LED reaches the end ?

UKHeliBob:
do you want the second LED to move along its final 5 steps

Yes thats what I want to achieve

This is one way i have experimented with to achieve the 2nd led to finish the last 5 steps - adding the number of last steps to the NUM_LEDS

but I don't think this is the best way.

void loop()  {
  for (int i = 0; i < NUM_LEDS + 5; i++) {
    leds[i]  .setHue( 0);
    if (i >= 5) {
      leds[i - 5] .setHue( 17);
    }

but I don't think this is the best way.

It is probably OK but I don't know what the possible side effects would be

It would be better to keep the number of LEDs to the real number, let the for loop go beyond that number but not to turn the LEDs past the end of the strip on or off, much in the same way as the check for the low numbered LEDs

I would also strongly advise that you replace the hard coded number 5 with a variable as it will be so much easier to make changes later

Looking at this led strip got me thinking that if it were a ring you would want the leds to be continuous. for example as each led reaches the end it begins again.

is it possible to duplicate a for loop? I know this code below is not correct. what I'm wanting to do do is start the dot moving and then start another after 5 and keep them moving till the end of the strip.

void loop()  {
for (int a = 0; a < NUM_LEDS; a++) {
    leds[a]  .setHue( 0);
    FastLED.show();
    leds[a] = CRGB::Black;
    delay(delayPeriod);

    if (a>=5) }
}    
    (int b = 0; b < NUM_LEDS; b++) { 
    leds[a]  .setHue( 17);
    FastLED.show();
    delay(delayPeriod);
}
}

If you start a second for loop inside an existing one (nested loops) then the steps in the inner one will run as many times as there are steps in the outer one. That is not what you want

If you start a second for loop when the first one is finished then each will run independently. That is not what you want

Conclusion : using 2 for loops is not what you want to do

However, you have the well named loop() function to do the work for you

Try this

byte r = 0; //start positions
byte g = 4;
byte b = 9;

byte maxCount = 20;

void setup()
{
  Serial.begin(115200);
  while (!Serial);
  Serial.println("r\tg\tb");
}

void loop()
{
  Serial.print(r);
  Serial.print("\t");
  Serial.print(g);
  Serial.print("\t");
  Serial.println(b);
  r++;
  if (r > maxCount)
  {
    r = 0;
  }
  g++;
  if (g > maxCount)
  {
    g = 0;
  }
  b++;
  if (b > maxCount)
  {
    b = 0;
  }
  delay(1000);
}

If you want the colours to move at different rates then you will need to use a different technique

One way to get anything to wrap around is to use modular arithmetic, another good trick for smart pixel animations.

You can do it several ways.

A free running index can just be reset when it goes beyond:

indexB++; if (indexB >= NUM_LEDS) indexB = 0;

you can use the modulo operator

setPixel(indexB % NUM_LEDS, whateverColor);

if the NUM_LEDS happens to be a power of two, you can mask the index so it is always in range, if it was 32, for example (0x20), this will keep the index in range

setPixel(indexB & 0x1f, whateverColor);

or more likely to be scene

indexB++; indexB &= 0x1f;

All these go backwards just fine, too, I’ll call that an exercise for the reader, haha.

These can run in an infinite loop - the for loop is not needed as we are now handling our own indices and taking care to move them how we want, as we want and with care taken to never refer to a non existant pixel.

This, BTW, is one more step closer to where you are going to want to learn about millis() and, perhaps, state machines. This too is a good candidate.

I see @UKHeliBob is eating my breakfast already while I type this…

a7

UKHeliBob:
If you start a second for loop inside an existing one (nested loops) then the steps in the inner one will run as many times as there are steps in the outer one. That is not what you want

If you start a second for loop when the first one is finished then each will run independently. That is not what you want

Conclusion : using 2 for loops is not what you want to do

However, you have the well named loop() function to do the work for you

Try this

byte r = 0; //start positions

byte g = 4;
byte b = 9;

byte maxCount = 20;

void setup()
{
 Serial.begin(115200);
 while (!Serial);
 Serial.println("r\tg\tb");
}

void loop()
{
 Serial.print(r);
 Serial.print("\t");
 Serial.print(g);
 Serial.print("\t");
 Serial.println(b);
 r++;
 if (r > maxCount)
 {
   r = 0;
 }
 g++;
 if (g > maxCount)
 {
   g = 0;
 }
 b++;
 if (b > maxCount)
 {
   b = 0;
 }
 delay(1000);
}



If you want the colours to move at different rates then you will need to use a different technique

That works very well thankyou, its getting late here in Melbourne Aus, so i'll have to call it a night and pick this up again in the morning

byte r = 0; //start positions
byte g = 5;
byte b = 10;

byte maxCount = 59;

void setup() {
  delay(2000);
  FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);  // GRB ordering is typical
  FastLED.setBrightness(BRIGHTNESS);

  Serial.begin(115200);
  while (!Serial);
  Serial.println("r\tg\tb");
}

void loop()
{
  Serial.print(r);
  Serial.print("\t");
  Serial.print(g);
  Serial.print("\t");
  Serial.println(b);
  leds[r] = CRGB::Red;
  leds[g] = CRGB::Green;
  leds[b] = CRGB::Blue;

  FastLED.show();
  leds[r] = CRGB::Black;
  leds[g] = CRGB::Black;
  leds[b] = CRGB::Black;

  r++;
  if (r > maxCount)
  {
    r = 0;
  }
  g++;
  if (g > maxCount)
  {
    g = 0;
  }
  b++;
  if (b > maxCount)
  {
    b = 0;
  }
  delay(50);
}

Rotating a fixed pattern through an LED strip is a bit simpler than what you are doing. Set the initial pattern into the LED strip, then just rotate the position of all the LEDs, taking whatever LED gets shifted out the end and placing it back at the start of the strip.

byte r = 10; //start positions
byte g = 5;
byte b = 0;

void setup() {
  delay(2000);
  FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);  // GRB ordering is typical
  FastLED.setBrightness(BRIGHTNESS);
  //turn on the LEDs in the initial positions
  leds[r] = CRGB::Red;
  leds[g] = CRGB::Green;
  leds[b] = CRGB::Blue;
}

void loop()  {
  //save the LED from the end of the strip
  CRGB wrapAround = leds[NUM_LEDS - 1];
  //shift the entire LED strip one LED position towards the end of the strip
  for (int i = NUM_LEDS - 1; i > 0; i--) {
    leds[i] = leds[i - 1];
  }
  //the last LED in the strip gets shifted into the first LED position
  leds[0] = wrapAround;
  FastLED.show();
  delay(delayPeriod);
}

Of course it gets a bit more complex when you want to shift the LEDs once through the strip, and light additional LEDs at unknown intervals, but there is no need to keep track of the current position of the lit LEDs.

//Leds chase forwards along strip
#include <FastLED.h>
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB

#define NUM_LEDS 60
#define DATA_PIN 5
#define BRIGHTNESS         32

CRGB leds[NUM_LEDS];

unsigned long delayPeriod = 50;

byte r = 0; //start positions
byte g = 5;
byte b = 10;

int ledCount = 0;

void setup() {
  delay(2000);
  FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);  // GRB ordering is typical
  FastLED.setBrightness(BRIGHTNESS);
}

void loop()  {
  bool ledsAllOff = true;
  //shift the entire LED strip one LED position towards the end of the strip
  for (int i = NUM_LEDS - 1; i > 0; i--) {
    leds[i] = leds[i - 1];
    //check to see if the current LED is off (Black)
    if ((leds[i].red != 0) || (leds[i].green != 0) || (leds[i].blue != 0)) {
      ledsAllOff = false;  //this will be set false if any LED is not Black
    }
  }
  if (r == ledCount) {
    leds[0] = CRGB::Red;
    ledsAllOff = false;
  }
  else if (g == ledCount) {
    leds[0] = CRGB::Green;
    ledsAllOff = false;
  }
  else if (b == ledCount) {
    leds[0] = CRGB::Blue;
    ledsAllOff = false;
  }
  else {
    leds[0] = CRGB::Black;
  }
  FastLED.show();
  //restart the pattern when it has completely shifted through the LED strip
  if (ledsAllOff == true) {
    ledCount = 0;
  } else {
    ledCount++;
  }
  delay(delayPeriod);
}

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.