FastLED Help

Im looking to run two or sometimes three of these animations "simultaneously". I've read up on kriegsman's post about running two animations at once, and while that is ultimately helpful, it seems to rely on using the built-in animations in the FastLED Library. I can't seem to find a way to apply my animations to his coding example. Furthermore, I've read blinking without delay and I believe I understand the basis of it, though my animations rely on some sort of time delay to function properly. I've entertained the idea of re-writing my animations to encompass what is now separate animations, but I've run into roadblocks there as well.

In short, what I'm looking to do is run say, bSwirl and tDrain, at what appears to be the same time but I can't figure out a way to achieve that. I'm using an Arduino Uno board, a 5M strip of LPD8806 LEDs, and a button in this project.

The code I've written is sincerely a hodgepodge of code from all over the place. I'm not going to pretend I know precisely what I'm doing, but I'm willing to give my best efforts to it. I just need some guidance if thats at all possible. I've only got about two weeks of experience under my belt so far and what I know I've learned without assistance.

Also, I know I should be commenting more in my code, I've just gotten away from it. I intend to ament this code to include comments in future.

#include <Arduino.h>
#include <FastLED.h>
#define NUM_LEDS 160
#define DATA_PIN 6
#define CLOCK_PIN 13
#define FORWARD 0
#define BACKWARD 1
#define BRIGHTNESS 96
#define FRAMES_PER_SECOND 100
CRGB leds[NUM_LEDS];
const int buttonPin = 2;




//SETUP//
void setup() {
  delay(3000);
  pinMode(buttonPin, INPUT);  // sets button 2 to input
  Serial.begin(9600);         // sets baud rate for serial comm to 9600
  FastLED.addLeds<LPD8806, DATA_PIN, CLOCK_PIN, BRG>(leds, NUM_LEDS);
  FastLED.setBrightness(BRIGHTNESS);
  for (int iT = 0; iT < 59; iT++) {
    leds[iT] = CRGB::Black;
  }
  for (int iB = 60; iB < 119; iB++) {
    leds[iB] = CRGB::Black;
  }
  for (int iD = 120; iD < 159; iD++) {
    leds[iD] = CRGB::Black;
  }
  FastLED.show();

}




//loop//

void loop() {
  preRun();
  while (digitalRead(buttonPin) == HIGH) {}
  bSwirl(0, 255, 255);
  tDrain(CRGB::Black, 0);
  bDrain(CRGB::Black, 0);
  drain(128, 0, 0);
  dDrain(CRGB::Black, 0);
  bFill(CRGB::Aqua, 1);
  tFill(CRGB::Blue, 1);
}




//preRun//

void preRun() {
  for (int iT = 0; iT < 59; iT++) {
    leds[iT] = CRGB::Blue;
  }
  for (int iB = 60; iB < 119; iB++) {
    leds[iB] = CRGB::Aqua;
  }
  FastLED.show();
}




//bSwirl//

void bSwirl(uint32_t r, uint32_t g, uint32_t b) {
  for (int j = 0; j < 10; j++) { //do 10 cycles of chasing
    for (int q = 0; q < 3; q++) {
      for (int i = 60; i < 119; i = i + 3) {
        //turn every third pixel on
        leds[i + q].r = r;
        leds[i + q].g = g;
        leds[i + q].b = b;
      }
      FastLED.show();
      timeLoop(millis(), 100);
      for (int i = 60; i < 119; i = i + 3) {
        //turn every third pixel off
        leds[i + q].r = 0;
        leds[i + q].g = 0;
        leds[i + q].b = 0;

      }
    }
  }
  for (int j = 0; j < 1; j++) { //do 1 cycles of chasing
    for (int q = 0; q < 3; q++) {
      for (int i = 60; i < 119; i = i + 3) {
        //turn every third pixel on
        leds[i + q].r = r;
        leds[i + q].g = g;
        leds[i + q].b = b;
      }
      FastLED.show();
      timeLoop(millis(), 100);
      for (int i = 60; i < 119; i = i + 3) {
        //turn every third pixel off
        leds[i + q].r = r;
        leds[i + q].g = g;
        leds[i + q].b = b;
      }
    }
  }
}




//drain//

void drain(uint32_t r, uint32_t g, uint32_t b) {
  for (int j = 0; j < 10; j++) { //do 10 cycles of chasing
    for (int q = 0; q < 3; q++) {
      for (int i = 120; i < 159; i = i + 3) {
        //turn every third pixel on
        leds[i + q].r = r;
        leds[i + q].g = g;
        leds[i + q].b = b;
      }
      FastLED.show();
      timeLoop(millis(), 100);
      for (int i = 120; i < 159; i = i + 3) {
        //turn every third pixel off
        leds[i + q].r = 0;
        leds[i + q].g = 0;
        leds[i + q].b = 0;

      }
    }
  }
  for (int j = 0; j < 1; j++) { //do 1 cycles of chasing
    for (int q = 0; q < 3; q++) {
      for (int i = 120; i < 159; i = i + 3) {
        //turn every third pixel on
        leds[i + q].r = r;
        leds[i + q].g = g;
        leds[i + q].b = b;
      }
      FastLED.show();
      timeLoop(millis(), 100); //delay speed
      for (int i = 120; i < 159; i = i + 3) {
        //turn every third pixel off
        leds[i + q].r = r;
        leds[i + q].g = g;
        leds[i + q].b = b;
      }
    }
  }
}




//timeLoop//

void timeLoop (long int startMillis, long int interval) { // delay substitute function

  // this loops until "n" milliseconds has passed since the function began
  while (millis() - startMillis < interval) {}
}




//bDrain//

void bDrain(CRGB c, int direction) {
  for (int i = 60; i < 120; i++) {
    if (direction == FORWARD) {
      leds[i] = c;
    }
    else {
      leds[119 - 1 - i] = c;
    }
    FastLED.show();
    timeLoop(millis(), 50); // speed at which colors chase to black
  }
}




//tDrain//

void tDrain(CRGB c, int direction) {
  for (int i = 0; i < 60; i++) {
    if (direction == FORWARD) {
      leds[i] = c;
    }
    else {
      leds[60 - 1 - i] = c;
    }
    FastLED.show();
    timeLoop(millis(), 50);
  }
}




//dDrain//

void dDrain(CRGB c, int direction) {
  for (int i = 120; i < 159; i++) {
    if (direction == FORWARD) {
      leds[i] = c;
    }
    else {
      leds[120 - 1 - i] = c;
    }
    FastLED.show();
    timeLoop(millis(), 50);
  }
}




//bFill//

void bFill(CRGB c, int direction) {
  for (int i = 119; i > 60; i--) {
    if (direction == BACKWARD) {
      leds[i] = c;
    }
    else {
      leds[60 + 1 + i] = c;
    }
    FastLED.show();
    timeLoop(millis(), 50);
  }
}




//tFill//

void tFill(CRGB c, int direction) {
  for (int i = 59; i > 0; i--) {
    if (direction == BACKWARD) {
      leds[i] = c;
    }
    else {
      leds[0 + 1 + i] = c;
    }
    FastLED.show();
    timeLoop(millis(), 50);
  }
}

The big mistake you are making is in trying to do too much at once. Start of by making your code do simply a single flashing LED on each strip.
In the examples for the fast LED look at the folder called Multiple for examples of how to run two strips with separate buffers at the same time. Also look at the website where they discuss this Multiple Controller Examples · FastLED/FastLED Wiki · GitHub

Just a few comments on your code.
100 frames a second is a bit fast, you can't tell the difference between this and 40 or so frames a second.
Their is no need for a 3 second delay at the start.

Grumpy_Mike:
The big mistake you are making is in trying to do too much at once. Start of by making your code do simply a single flashing LED on each strip.
In the examples for the fast LED look at the folder called Multiple for examples of how to run two strips with separate buffers at the same time. Also look at the website where they discuss this Multiple Controller Examples · FastLED/FastLED Wiki · GitHub

I've run and re-run the examples in the FastLED library, I've done my best to wrap my head around them as well as I can. I don't have three separate strips, I have one strip divided into three arrays, 0-59, 60-119, 120-159. But I'll give that link a good read to be sure I'm not misunderstanding what you're saying.

Also, I have to note that I am definitely a fan of yours on the forum. In my search for answers its taken me here plenty of times and you're always right there on top with a witty and insightful bit of knowledge. Many many thanks for the direction, though if you can think of anything else that may help I'm open to just about anything.

As far as the 1000FPS goes, theres definitely plenty of trimming and optimization to my code I can do, I'm trying to hammer out the last of the details, or at least try to find a workable alternative before I clean up and make everything nice and tidy, though in the interest of being as compliant as possible when asking others for help... I'll get on that asap.

I have one strip divided into three arrays, 0-59, 60-119, 120-159.

OK their are two ways you can tackle this. Their are examples of using multiple buffers on the one strip in the examples but you might be better off just limiting the putting of the patterns into the various buffer areas. Which looks like that is what you are doing.

However you need to write the animation as a state machine if you want to make them look like they are happening at the same time. As well as removing the delays you must also replace 'for' loops to increment the loop indexes each time the animation function is called.

I have not got any examples of this using the FastLED libiary but I have got one using the AdaFruit libiary. It will give you the idea of how to make a state machine animation. It is the standard Strand test but as a state machine.

// StrandTest from AdaFruit implemented as a state machine
// pattern change by push button
// By Mike Cook Jan 2016

#define PINforControl   7 // pin connected to the small NeoPixels strip
#define NUMPIXELS1      6 // number of LEDs on second strip

#include <Adafruit_NeoPixel.h>
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMPIXELS1, PINforControl, NEO_GRB + NEO_KHZ800);

unsigned long patternInterval = 20 ; // time between steps in the pattern
unsigned long lastUpdate = 0 ; // for millis() when last update occoured
unsigned long intervals [] = { 20, 20, 50, 100 } ; // speed for each pattern
const byte button = 2; // pin to connect button switch to between pin and ground

void setup() {
  strip.begin(); // This initializes the NeoPixel library.
  wipe(); // wipes the LED buffers
  pinMode(button, INPUT_PULLUP); // change pattern button
}

void loop() {
  static int pattern = 0, lastReading;
  int reading = digitalRead(button);
  if(lastReading == HIGH && reading == LOW){
    pattern++ ; // change pattern number
    if(pattern > 3) pattern = 0; // wrap round if too big
    patternInterval = intervals[pattern]; // set speed for this pattern
    wipe(); // clear out the buffer 
    delay(50); // debounce delay
  }
  lastReading = reading; // save for next time

if(millis() - lastUpdate > patternInterval) updatePattern(pattern);
}

void  updatePattern(int pat){ // call the pattern currently being created
  switch(pat) {
    case 0:
        rainbow(); 
        break;
    case 1: 
        rainbowCycle();
        break;
    case 2:
        theaterChaseRainbow(); 
        break;
    case 3:
         colorWipe(strip.Color(255, 0, 0)); // red
         break;     
  }  
}

void rainbow() { // modified from Adafruit example to make it a state machine
  static uint16_t j=0;
    for(int i=0; i<strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i+j) & 255));
    }
    strip.show();
     j++;
  if(j >= 256) j=0;
  lastUpdate = millis(); // time for next change to the display
  
}
void rainbowCycle() { // modified from Adafruit example to make it a state machine
  static uint16_t j=0;
    for(int i=0; i< strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
    }
    strip.show();
  j++;
  if(j >= 256*5) j=0;
  lastUpdate = millis(); // time for next change to the display
}

void theaterChaseRainbow() { // modified from Adafruit example to make it a state machine
  static int j=0, q = 0;
  static boolean on = true;
  // for (int j=0; j < 256; j++) {     // cycle all 256 colors in the wheel
  //  for (int q=0; q < 3; q++) {
     if(on){
            for (int i=0; i < strip.numPixels(); i=i+3) {
                strip.setPixelColor(i+q, Wheel( (i+j) % 255));    //turn every third pixel on
             }
     }
      else {
           for (int i=0; i < strip.numPixels(); i=i+3) {
               strip.setPixelColor(i+q, 0);        //turn every third pixel off
                 }
      }
     on = !on; // toggel pixelse on or off for next time
      strip.show(); // display
      q++; // update the q variable
      if(q >=3 ){ // if it overflows reset it and update the J variable
        q=0;
        j++;
        if(j >= 256) j = 0;
      }
  lastUpdate = millis(); // time for next change to the display    
}

void colorWipe(uint32_t c) { // modified from Adafruit example to make it a state machine
  static int i =0;
    strip.setPixelColor(i, c);
    strip.show();
  i++;
  if(i >= strip.numPixels()){
    i = 0;
    wipe(); // blank out strip
  }
  lastUpdate = millis(); // time for next change to the display
}


void wipe(){ // clear all LEDs
     for(int i=0;i<strip.numPixels();i++){
       strip.setPixelColor(i, strip.Color(0,0,0)); 
       }
}

uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if(WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

Also thanks for, your comments and thanks for framing your question so well, wish we had more of that round here.

Grumpy_Mike:
However you need to write the animation as a state machine if you want to make them look like they are happening at the same time. As well as removing the delays you must also replace 'for' loops to increment the loop indexes each time the animation function is called.

Omitting the for loops will probably cause me some severe headaches, though I completely understand where you're coming from in that regard. I'll look into your code and see what I can do to retrain myself to think in a way that applies your methods to my needs.

Grumpy_Mike:
Also thanks for, your comments and thanks for framing your question so well, wish we had more of that round here.

I've seen what happens when one incurs the wrath of Grumpy_Mike and I'd like to stay on the good side of that fence. Thats a beast I dare not bother.

On another note, would you suggest moving from the FastLED library to the AdaFruit library? I'm sure they can work together peacefully, but I'd like to keep the amount of library information preloaded to a minimum as well as avoiding any unforeseen conflicts between the two.

in the meantime, I'll get to re-working this and I'll update when I've either hit my next roadblock or have made some notable headway.

Thank you again Mike for your valuable input.

On another note, would you suggest moving from the FastLED library to the AdaFruit library?

Not really, it is just that I find the AdFruit one much simpler because their is less in it but essentially they work in the same way. If I want the extensions that the FastLED offers I tend to write them myself.

They both work with a buffer that you manipulate and then send out to the strip. With the AdaFruit one this buffer is a bit hidden but it is still there. With the FastLED one you can make the buffer explicit or indeed use any source of memory like program memory to provide the data you send.

I've seen what happens when one incurs the wrath

As some one once said, "you wouldn't like me when i'm angry" :slight_smile:
If you are too young to know this then google the phase.

Just thought if this it might help.

When converting an anamation into a state machine, you need to eliminate all the for loops as well as a delay. The point where the routine should return is every time their is a LED.show method called.
So if you have a for loop that doesn't contain a show method then you can leave that in. Any loop that contains a show method needs to be broken up and replaced by a static variable that contains the former for loop's loop index, and do the incrementing and checking by hand ( with specific lines of code like if statements ).

Grumpy_Mike:
Any loop that contains a show method needs to be broken up and replaced by a static variable that contains the former for loop's loop index, and do the incrementing and checking by hand ( with specific lines of code like if statements ).

I'm focusing now on trimming down the animations and making them so that they are compliant with the methods you've outlined for setting up a state machine.

I have one animation that does have a FastLED.show(); in the middle of its function.

void drain(uint32_t r, uint32_t g, uint32_t b) {
  for (int j = 0; j < 10; j++) { //do 10 cycles of chasing
    for (int q = 0; q < 3; q++) {
      for (int i = 120; i < 159; i = i + 3) {
        //turn every third pixel on
        leds[i + q].r = r;
        leds[i + q].g = g;
        leds[i + q].b = b;
      }
      FastLED.show();
      timeLoop(millis(), 100);
      for (int i = 120; i < 159; i = i + 3) {
        //turn every third pixel off
        leds[i + q].r = 0;
        leds[i + q].g = 0;
        leds[i + q].b = 0;

      }
    }
  }
}

I know I can trim it back and get rid of a lot of the fluff, thats not too difficult to wrap my head around.

void drain(uint32_t r, uint32_t g, uint32_t b) {
    for (int q = 0; q < 3; q++) {
      for (int i = 120; i < 159; i = i + 3) {
        //turn every third pixel on
        leds[i + q].r = r;
        leds[i + q].g = g;
        leds[i + q].b = b;
      }
      FastLED.show();
      timeLoop(millis(), 100);
      for (int i = 120; i < 159; i = i + 3) {
        //turn every third pixel off
        leds[i + q].r = 0;
        leds[i + q].g = 0;
        leds[i + q].b = 0;

      }
    }
  }

My issue right now is that when I move to separate the two halves of this function, the turn on & turn off half I lose functionality, I'm not able to retain the original function of the animation.

It looks for the timeLoop and the show() before it writes the leds to black. So if I split the two halves and write them to individual functions I'm assuming that if I call each function in order with a show() & timeLoop between they should still operate as intended...I'm trying to preserve the operation of the nested for loop without it being a nested for loop... I know I'm wrong and I'm sure its obvious what I'm missing but my lack of experience is going to show.

void loop() {
  drainOn(0, 255, 255);
  FastLED.show();
  timeLoop();
  drainOff(0, 255, 255);
  FastLED.show();
}


void drainOn(uint32_t r, uint32_t g, uint32_t b) {
  for (int q = 0; q < 3; q++) {
    for (int i = 120; i < 159; i = i + 3) {
      //turn every third pixel on
      leds[i + q].r = r;
      leds[i + q].g = g;
      leds[i + q].b = b;
    }
  }
}
void drainOff(uint32_t r, uint32_t g, uint32_t b) {
  for (int q = 0; q < 3; q++) {
    for (int i = 120; i < 159; i = i + 3) {
      //turn every third pixel off
      leds[i + q].r = 0;
      leds[i + q].g = 0;
      leds[i + q].b = 0;

    }
  }
}

Don't laugh too hard, I'm doing my best.

I'm also reading this article you wrote detailing state machines.

Sorry but no.
First off why are you setting the r,g,b to be 32 bit words you only need bytes. Second you have not got the idea of calling the animation only when you want to update it.
Your animation seems to have two states, one when you turn on three LEDs and the other when you turn them off. I have had a go at writing it in the style you need breaking it on the show state.
I have not tested this and I am not sure I can understand the pattern but this is somewhat what you need to do. It will not run because you need some setting up for the FastLED libiary but that is about all.

unsigned long lastUpdate [] = { 0, 0 }; // for millis() when last update occurred
unsigned long patternInterval [] = { 500, 0 }; // how often each pattern updates

void setup() {
  // put your setup code here, to run once:

}

void loop() {
if(millis() - lastUpdate[0] > patternInterval[0]) drain(0,255,255);

}

void drain(byte r, byte g, byte b) {
  static byte j,q, state = 0;
  if (state == 0) { // start up state
    state = 1; // next state
    j = 0;
    q = 0;
    return; // next return immediatly
  }
  if(state == 1){
      for (int i = 120; i < 159; i = i + 3) {
        //turn every third pixel on
        leds[i + q].r = r;
        leds[i + q].g = g;
        leds[i + q].b = b;
        state = 2; // turn off next time
      }
  }
  else if(state == 2){
       for (int i = 120; i < 159; i = i + 3) {
        //turn every third pixel off
        leds[i + q].r = 0;
        leds[i + q].g = 0;
        leds[i + q].b = 0;
        state = 1; // turn on next time
      }
    }
  // update loop variables regardless of state
  q++;
  if(q>2){
    q=0;
    j++;
    if(j> 11){
      state = 0 // repeat pattern  
    }
  }
  FastLED.show(); // show the LEDs
  lastUpdate[0] = millis(); // to set the next update
}

Grumpy_Mike:
Sorry but no.
First off why are you setting the r,g,b to be 32 bit words you only need bytes. Second you have not got the idea of calling the animation only when you want to update it.

Hodgepodge code and ignorance. I realize I should have been using byte now that I've looked into the terms and what values they are capable of carrying.

You're absolutely right, I haven't got the idea... I am sorely mistaken. I'll definitely be doing some serious reading up on how you wrote this section of code. I believe I'm starting to see the structure and how it interacts with itself. Though it is still above my understanding right now.

It does work. I've just got to figure out how to limit it to run for either a period of time, or a number of cycles. I'll work to implement it to other animations in the code.

Secondly I've got to figure out a better way to trigger the entire pattern to run once on a button press, but I can't say that this would be the appropriate forum for that.

I've just got to figure out how to limit it to run for either a period of time,

Make the state variable a global one, and set it to 3 once J > 11. Then it will not repeat until some other code sets it back to zero.

Thanks, I'll give that a try tomorrow morning. unfortunately this is a 9-5 project and I can't necessarily take it home with me, though I can revise and play with the code in the meantime. I'll continue to review it to better my understanding of whats going on.