Sending LED-Sequences simultaneously via switch

Hi, :slight_smile:
we are Olli and Devani and we are currently working on a mod for a Pinball machine.
What we want to happen is that the ball will trigger a switch that will then play a specific LED sequence that looks a bit like a wave. The speed of the wave can be set via a potentiometer.

We use the NeoPixel library and as a starting point we use this example, called "meteor rain":

So what is the actual problem?

We have a switch connected and it will trigger the sequence just fine. The problem is that in the game there is multiball mode that will give you 3 balls and you are supposed to hit the ramp (therefore the switch) three times in a relatively short time.

What we hope to do is that whenever the switch will be activated, it will also send another sequence on top of the running one. We managed to make it send a second "wave" by now which will interrupt the first one after it finished.

We tried a lot but we didn't manage to get a third wave. It will just not trigger, even though we do it exactly the same way we managed to make the second wave go. It's not the cleanest solution ever, but we managed to do so by checking for the switch state inside the meteorRain function, and calling for a second function (which is basically a copy from the first function). Yet, it won't work with a third function, and we don't get why.

We hope for some input from you guys. What we hope for is:

  1. We can activate 3 waves via button press
  2. Each wave will finish instead of being interrupted by the next one

Attached is a link to a video that shows you where we are at for now. I pressed the button again at the end of the first sequence to trigger the second one. For another round, we have to wait for the fading to go totally dark.
Video Example
Best regards from Germany,

Devani + Olli

#include <Adafruit_NeoPixel.h>
#define PIN 2
#define NUM_LEDS 95
#define Switch 4 //define input pin for switch
int val ;
int val2;
int potPin = A0;
int val3 = 0;
// 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);

void setup() {
  strip.begin();
 // strip.show(); // Initialize all pixels to 'off'
  pinMode(Switch,INPUT_PULLUP);
  val = 0;
  val2 = 0;
}

void loop() {
  val3 = analogRead(potPin) / 8;
  while (digitalRead(Switch)==LOW){
    delay(50);
      val = 1;
      }
  if (val == 1 and val2 ==0){
  meteorRain(0, 0, 255, 3, 280, true, 0);  
  val2 = 1;
      }
    setup(); 
    
}

void meteorRain(byte red, byte green, byte blue, byte meteorSize, byte meteorTrailDecay, boolean meteorRandomDecay, int SpeedDelay) {
  //setAll(0, 0, 0);

  for (int i = 0; i < NUM_LEDS + NUM_LEDS; i++) {

    
    // fade brightness all LEDs one step
    for (int j = 0; j < NUM_LEDS; j++) {
      if ( (!meteorRandomDecay) || (random(10) > 5) ) {
        fadeToBlack(j, meteorTrailDecay );
      }
      if (digitalRead(Switch)==LOW){
      delay(50);
      meteorRain_2(0, 0, 255, 4, 280, true, 0);
      setAll(0, 0, 0);
      
      setup();
    }
    }
    
    // draw meteor
    for (int j = 0; j < meteorSize; j++) {
      if ( ( i - j < NUM_LEDS) && (i - j >= 0) ) {
        setPixel(i - j, red, green, blue);
         strip.setPixelColor(i+1, strip.Color(30, 30, 255));
           strip.setPixelColor(i+2, strip.Color(80, 80, 180));
           strip.setPixelColor(i-3, strip.Color(60, 60, 200));
      }
    }
    
    showStrip();
    delay(val3);
    
  }
  setAll(0, 0, 0);
  setup();
}


void meteorRain_2(byte red, byte green, byte blue, byte meteorSize, byte meteorTrailDecay, boolean meteorRandomDecay, int SpeedDelay) {
  //setAll(0, 0, 0);

  for (int i = 0; i < NUM_LEDS + NUM_LEDS; i++) {


    // fade brightness all LEDs one step
    for (int j = 0; j < NUM_LEDS; j++) {
      if ( (!meteorRandomDecay) || (random(10) > 5) ) {
        fadeToBlack(j, meteorTrailDecay );
      }
    }
    
    // draw meteor
    for (int j = 0; j < meteorSize; j++) {
      if ( ( i - j < NUM_LEDS) && (i - j >= 0) ) {
        setPixel(i - j, red, green, blue);
         strip.setPixelColor(i+1, strip.Color(30, 30, 255));
           strip.setPixelColor(i+2, strip.Color(80, 80, 180));
           strip.setPixelColor(i-3, strip.Color(60, 60, 200));
      }
    }

    showStrip();
    delay(val3);
    
  }
  setup();
}

void meteorRain_3(byte red, byte green, byte blue, byte meteorSize, byte meteorTrailDecay, boolean meteorRandomDecay, int SpeedDelay) {
  //setAll(0, 0, 0);

  for (int i = 0; i < NUM_LEDS + NUM_LEDS; i++) {


    // fade brightness all LEDs one step
    for (int j = 0; j < NUM_LEDS; j++) {
      if ( (!meteorRandomDecay) || (random(10) > 5) ) {
        fadeToBlack(j, meteorTrailDecay );
      }
    }
    
    // draw meteor
    for (int j = 0; j < meteorSize; j++) {
      if ( ( i - j < NUM_LEDS) && (i - j >= 0) ) {
        setPixel(i - j, red, green, blue);
         strip.setPixelColor(i+1, strip.Color(30, 30, 255));
           strip.setPixelColor(i+2, strip.Color(80, 80, 180));
           strip.setPixelColor(i-3, strip.Color(60, 60, 200));
      }
    }

    showStrip();
    delay(val3);
    
  }
  setup();
}


void fadeToBlack(int ledNo, byte fadeValue) {
#ifdef ADAFRUIT_NEOPIXEL_H
  // NeoPixel
  uint32_t oldColor;
  uint8_t r, g, b;
  int value;

  oldColor = strip.getPixelColor(ledNo);
  r = (oldColor & 0x00ff0000UL) >> 16;
  g = (oldColor & 0x0000ff00UL) >> 8;
  b = (oldColor & 0x000000ffUL);

  r = (r <= 10) ? 0 : (int) r - (r * fadeValue / 256);
  g = (g <= 10) ? 0 : (int) g - (g * fadeValue / 256);
  b = (b <= 10) ? 0 : (int) b - (b * fadeValue / 256);

  strip.setPixelColor(ledNo, r, g, b);
#endif
#ifndef ADAFRUIT_NEOPIXEL_H
  // FastLED
  leds[ledNo].fadeToBlackBy( fadeValue );
#endif
}

void showStrip() {
#ifdef ADAFRUIT_NEOPIXEL_H
  // NeoPixel
  strip.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));
#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();
}

Do not call the setup() function from the loop. Just let the functions end, if you need to revisit the code in the setup function write another function with that code in it and call it from the setup function and form where ever you want it. The loop function will automatically be re-entered wen it finishes.

Do not control things on the level of the digital input but on the edge. Look at the state change example in the IDE for how to do this.

Do not use a delay or a for loop if you want to avoid having to wait until one animation ends before the other begins. Look to use a state machine, see my
http://www.thebox.myzen.co.uk/Tutorial/State_Machine.html
Or Robin2's several things at once
http://forum.arduino.cc/index.php?topic=223286.0

Hello Mike,
Thank you for your detailed reply.

Actually we looked into all these points you mention. Devani read the state machine example. It's very very well written.

I guess we just hoped for a quick and dirty fix, but now we will do a complete rewrite of the code to make it nice and clean.

Of course understanding the state change and the state machine will take some time.

We will keep you guys updated!

Thanks again

Devani + Olli

Hi again,

So, we managed to implement our code using the state change and state machine. It works (yay!), but it won't send the two sequences simultaneously.

Basically, the code is gonna check after certain time the button state. If pressed, then it will start a LED sequence.

Now, once we start a "wave" this sequence has to finish before we can check the button state and start the sequence again.

I have been reading Robin2's examples, and if I understood correctly, this is controlling different LED outputs at different rates, what makes it look like processes in parallel. But, because we use a single LED output, I struggle figuring out how we can get the same effect.

Am I missing something or do you have any ideas?

Thanks a lot again! The tutorials have been super useful!

Best,

Olli + Devani

#include <Adafruit_NeoPixel.h>
#define PIN 2
#define NUM_LEDS 95
#define buttonPin 4 //define input pin for switch
int potPin = A0;
// 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);
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button
int nextTime = 100;  // Do this every second or 1000 milliseconds
long int goTime;


void setup() {
  strip.begin();
  pinMode(buttonPin,INPUT_PULLUP);
}


void loop() {
  
  if(millis() >= goTime) functionGO();

}


void functionGO(){
  buttonState = digitalRead(buttonPin);
  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == LOW) {
      // if the current state is HIGH then the button went from off to on:
      meteorRain(0, 0, 255, 3, 280, true, 0);
    } 
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  // save the current state as the last state, for next time through the loop
  lastButtonState = buttonState;
  setAll(0, 0, 0);
  goTime = millis() + nextTime;
}

void meteorRain(byte red, byte green, byte blue, byte meteorSize, byte meteorTrailDecay, boolean meteorRandomDecay, int SpeedDelay) {  
  setAll(0,0,0);
 
  for(int i = 0; i < NUM_LEDS+NUM_LEDS; i++) {
   
   
    // fade brightness all LEDs one step
    for(int j=0; j<NUM_LEDS; j++) {
      if( (!meteorRandomDecay) || (random(10)>5) ) {
        fadeToBlack(j, meteorTrailDecay );        
      }
    }
   
    // draw meteor
    for(int j = 0; j < meteorSize; j++) {
      if( ( i-j <NUM_LEDS) && (i-j>=0) ) {
        setPixel(i-j, red, green, blue);
      }
    }
   
    showStrip();
    delay(SpeedDelay);
  }
}

void fadeToBlack(int ledNo, byte fadeValue) {
 #ifdef ADAFRUIT_NEOPIXEL_H
    // NeoPixel
    uint32_t oldColor;
    uint8_t r, g, b;
    int value;
   
    oldColor = strip.getPixelColor(ledNo);
    r = (oldColor & 0x00ff0000UL) >> 16;
    g = (oldColor & 0x0000ff00UL) >> 8;
    b = (oldColor & 0x000000ffUL);

    r=(r<=10)? 0 : (int) r-(r*fadeValue/256);
    g=(g<=10)? 0 : (int) g-(g*fadeValue/256);
    b=(b<=10)? 0 : (int) b-(b*fadeValue/256);
   
    strip.setPixelColor(ledNo, r,g,b);
 #endif
 #ifndef ADAFRUIT_NEOPIXEL_H
   // FastLED
   leds[ledNo].fadeToBlackBy( fadeValue );
 #endif  
}

void showStrip() {
 #ifdef ADAFRUIT_NEOPIXEL_H
   // NeoPixel
   strip.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));
 #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();
}

Set a bool variable to a state that prevents the button thing from doing its thing whiles the other thing is in progress. When the other thing is done, the other thing sets the bool variable to the other state to allow the button thing to start doing the thing it does.

Idahowalker:
Set a bool variable to a state that prevents the button thing from doing its thing whiles the other thing is in progress. When the other thing is done, the other thing sets the bool variable to the other state to allow the button thing to start doing the thing it does.

Maybe we don't understand correctly, but preventing the button from running the sequence is exactly what we don't want to do.

Basically the button press should always run another sequence on top of the prior sequence.

It sounds like you describe it the way our code is actually working right now:

Press button, sequence will start, can't press again until sequence is done.

Now, once we start a "wave" this sequence has to finish before we can check the button state and start the sequence again.

So that means you have not implemented the idea of a state machine correctly.

You have to unroll all the for structures with any sort of delay in them and implement them by hand. That is using a variable as a loop pointer and doing the comparison bit to see if the loop has finished at the end of what the for loop was doing. If the for loop has finished you increment a state variable, if not you simply return.

At the start of the animation function you check the state variable to see what section of the animation to perform.

This way you can interrupt the animation at any time and reset the function, wiping the old pattern or not as you see fit.

This might help you. It is all the Adafruit example animations translated into state machines. Compare these with the originals to see what you need to do.

// StrandTest from AdaFruit implemented as a state machine
// pattern change by push button
// By Mike Cook Jan 2016
// Fade function added Sept 2017

#define PINforControl   4 // pin connected to the small NeoPixels strip
#define NUMPIXELS1      64 // number of LEDs on 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 occurred
unsigned long intervals [] = { 20, 20, 50, 100, 30 } ; // speed for each pattern - add here when adding more cases 
int fadeStep = 0; // state variable for fade function
int numberOfCases = 4; // how many case statements or patterns you have
const byte button = 3; // pin to connect button switch to between pin and ground

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

void loop() {
  static int pattern = 4, lastReading; // start with the fade function
  int reading = digitalRead(button);
  if(lastReading == HIGH && reading == LOW){
    pattern++ ; // change pattern number
    fadeStep = 0; // reset the fade state variable
    if(pattern > numberOfCases) 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; 
         
    case 4:
         fade(0,255, 0,64, 0,0, 400); // fade from black to orange and back
         break;                  
  } 
}

void fade(int redStartValue, int redEndValue, int greenStartValue, int greenEndValue, int blueStartValue, int blueEndValue, int totalSteps) {
static float redIncrement, greenIncrement, blueIncrement;
static float red, green, blue;
static boolean fadeUp = false;

if (fadeStep == 0){ // first step is to initialise the initial colour and increments
  red = redStartValue;
  green = greenStartValue;
  blue = blueStartValue;
  fadeUp = false;

  redIncrement = (float)(redEndValue - redStartValue) / (float)totalSteps;
  greenIncrement = (float)(greenEndValue - greenStartValue) / (float)totalSteps;
  blueIncrement = (float)(blueEndValue - blueStartValue) / (float)totalSteps;
  fadeStep = 1; // next time the function is called start the fade
}
else { // all other steps make a new colour and display it
  // make new colour
  red += redIncrement;
  green +=  greenIncrement;
  blue += blueIncrement;
 
  // set up the pixel buffer
  for (int i = 0; i < strip.numPixels(); i++) {
  strip.setPixelColor(i, strip.Color((int)red,(int)green,(int)blue));
  }
 // now display it
  strip.show();
fadeStep += 1; // go on to next step
if(fadeStep >= totalSteps) { // finished fade
  if(fadeUp){ // finished fade up and back
     fadeStep = 0;
     return; // so next call re-calabrates the increments 
  }
  // now fade back
  fadeUp = true;
  redIncrement = -redIncrement;
  greenIncrement = -greenIncrement;
  blueIncrement = -blueIncrement;
  fadeStep = 1; // don't calculate the increments again but start at first change
}
 }
}

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;
     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);
}

Thanks again for the hints,

We have been trying around to remove the loops from our functions and this is the solution we found to keep simultaneous LED sequences (code attached).

Nevertheless, the code does not work for case 3. All leds go off. Also, in case 2 (where 2 sequences are introduces) it starts flickering and gets slower. Any idea why may this be happening??

// StrandTest from AdaFruit implemented as a state machine
// pattern change by push button
// By Mike Cook Jan 2016
// Fade function added Sept 2017

#define PINforControl   2 // pin connected to the small NeoPixels strip
#define NUM_LEDS      95 // number of LEDs on strip
#define button 4// pin to connect button switch to between pin and ground
#include <Adafruit_NeoPixel.h>
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, PINforControl, NEO_GRB + NEO_KHZ800);

unsigned long patternInterval = 20 ; // time between steps in the pattern
unsigned long lastUpdate = 0 ; // for millis() when last update occurred
unsigned long intervals [] = {20, 20, 20 } ; // speed for each pattern - add here when adding more cases
int fadeStep = 0; // state variable for fade function
int numberOfCases = 4; // how many case statements or patterns you have


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

void loop() {
  static int pattern = 4, lastReading; // start with the fade function
  int reading = digitalRead(button);
  if(lastReading == HIGH && reading == LOW){
    pattern++ ; // change pattern number
    fadeStep = 0; // reset the fade state variable
    if(pattern > numberOfCases) pattern = 0; // wrap round if too big
    patternInterval = intervals[pattern]; // set speed for this pattern
    setAll(0,0,0); // 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:
        meteorRain(0, 0, 255, 3, 280, true, 20);
        break;
    case 2:
        meteorRain2(0, 0, 255, 3, 280, true, 20);
        break;
    case 3:
        meteorRain3(0, 0, 255, 3, 280, true, 20);
        break;
    case 4:
         setup();                
  }
}

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
 
}
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);
}
////// METEOR FUNCTIONS 
int position1wave =0;
int position2wave =0;

void meteorRain3(byte red, byte green, byte blue, byte meteorSize, byte meteorTrailDecay, boolean meteorRandomDecay, int SpeedDelay) {  
  setAll(0,0,0);
  static int y =0;
  y++;
  position1wave++;
  position2wave++;
  for(int j = 0; j < meteorSize; j++) {
      if( ( y-j <NUM_LEDS) && (y-j>=0) ) {
        setPixel(y-j, red, green, blue);
      }
      showStrip();
  //    if( (position1wave -j <NUM_LEDS) && (position1wave-j>=0) ) {
     //   setPixel(position1wave-j, red, green, blue);
     // }
      //showStrip();
      if( (position2wave -j <NUM_LEDS) && (position2wave-j>=0) ) {
        setPixel(position2wave-j, red, green, blue);
      }
      showStrip();
    }

  if(y >= strip.numPixels()){
   y = 0;
  }
  //if(position1wave >= strip.numPixels()){
   // position1wave = 0;
  //}
  if(position2wave >= strip.numPixels()){
    position2wave = 0;
  }
  lastUpdate = millis();
  
}


void meteorRain2(byte red, byte green, byte blue, byte meteorSize, byte meteorTrailDecay, boolean meteorRandomDecay, int SpeedDelay) {  
  setAll(0,0,0);
  static int x =0;
  x++;
  position1wave++;
  for(int j = 0; j < meteorSize; j++) {
      if( ( x-j <NUM_LEDS) && (x-j>=0) ) {
        setPixel(x-j, red, green, blue);
        position2wave = x;
      }
      showStrip();
      if( (position1wave -j <NUM_LEDS) && (position1wave-j>=0) ) {
        setPixel(position1wave-j, red, green, blue);
      }
      showStrip();
    }

  if(x >= strip.numPixels()){
    x = 0;
  }
  if(position1wave >= strip.numPixels()){
    position1wave = 0;
  }
  lastUpdate = millis();
  
}

void meteorRain(byte red, byte green, byte blue, byte meteorSize, byte meteorTrailDecay, boolean meteorRandomDecay, int SpeedDelay) {  
  setAll(0,0,0);
  static int i =0;
  i++;
  for(int j = 0; j < meteorSize; j++) {
      if( ( i-j <NUM_LEDS) && (i-j>=0) ) {
        setPixel(i-j, red, green, blue);
        position1wave =i;
      }
    }
  if(i >= strip.numPixels()){
    i = 0;
  }
  showStrip();
  lastUpdate = millis();
  
}






void showStrip() {
 #ifdef ADAFRUIT_NEOPIXEL_H
   // NeoPixel
   strip.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));
 #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();
}

You are not getting it.

You have no state variable so that every time you call that function you tell it to turn off all the lights is that what you want to happen? I would think not but tell me exactly what should happen to the existing sequence when a new one starts up?

If you just want to start a new sequence there is no need for more than one function.

The code I posted only shows one animation at a time, it will not show more. If you want more to run then you have to take an other approach. Remove the case structure and replace it with a loop looking at a variable indicating if each of the animations is active or not, and then call them or not. But you have to get that state variable sorted out first.

Hi Mike,

yeah..we are obviously struggling in getting the state variable idea...

We would like that the first sequence keeps moving together with the new one. I just have a very hard time understanding how we can make the two sequences run in parallel...That's why I thought I might create a new function that will light LEDS from two different points of the stripe: where the last sequence finished and from LED position 0.

We have another question. Just out of curiosity (we understood the case structure should disappear)...the static local variable is supposed to store the last value of the variable. Is there an alternative way to create a variable that changes when the case is run for the second time? We tried many things...did not manage to make it work.

Bright side: it seems that we managed to get rid of loops and delays so that the button state is 'continuously' checked. So I believe we managed to implement the state machine idea correctly.

We really appreciate your help :slight_smile:

Olli + Devani

We would like that the first sequence keeps moving together with the new one.

That is more tricky but can be done with a bit more coding. You have to decide how you want it to look. That is the new sequence and the old sequence on at the same time. You might find yourself in a bit of a logic quandary.

It might be simpler to have three separate arrays, one for each instance of the sequence so you have them separately set, but you don’t simply show them. What you do is have a fourth array where you mix the results of the three sequences together.

However how you mix them is vital to how the final result looks.

One way is to simply add the LEDs from each sequence. That is the resulting output to the fourth array is the led colour found by Adding together of the first three arrays. This runs the risk of overflowing the 255 limit of the individual LED brightness. You could clamp this, that is set it to 255 if the sum comes out to be greater than 255. Or you could divide all the colours by three before adding them, or you could make sure you don’t set a colour to over a third of maximum brightness in the first place.

Another way to mix them is to set them to the brightest of the three, either by individual component or the total brightness by adding all three colour components together to decide which ones to choose.

Is there an alternative way to create a variable that changes when the case is run for the second time?

That is what a state variable should do. The case statement should be inside your animation function and should only run a sub section of the animation depending on the value of the state variable.