HELP! LEGO Millennium Falcon FASTLED engine starting sequence

Hi! I´m new to neopixels and fastled coding. I am a LEGO collector and usually modify my sets with micro smd led. Now with neopixels I can do more.

I´m trying to create a starting sequence for the millennium falcon where I have two rows of 55 pixels each, the sequence should run once and then loop in a wave that creates the sensation that the engine is on.

I have the wave already running but been unable to figure out how to create and insert the starting sequence that should run like this:

  • First row should turn on led 27 and then go from 26 to 0 and 28 to 54 one by one
  • Second row should turn on led 82 then go from 83 to 109 and 81 to 55 one by one

any ideas what should I do? thanks in advance.

current code below:

#include <FastLED.h>

#define NUM_LEDS 110
#define LED_PIN   6

CRGB leds[NUM_LEDS];
uint8_t colorIndex[NUM_LEDS];

DEFINE_GRADIENT_PALETTE( mfengine_gp ) {
    0,   1,   8,  87,
   71,  23, 195, 130,
  122, 186, 248, 233,
  168,  23, 195, 130,
  255,   1,   8,  87
  };

CRGBPalette16 mfengine = mfengine_gp;

void setup() {
  FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
  FastLED.setBrightness(50);
  FastLED.clear();  // clear all pixel data

}

void loop() {

  //Creat a sin wave with period of 2 seconds (30bpm) to change the brightness of the strip
  uint8_t sinBeat = beatsin8(10, 50, 255, 0, 0); //bpm, low brightness, high brightness,
  uint8_t sinBeat1 = beatsin8(30, 50, 255, 0, 60);
  
  // Color each pixel from the palette using the index from colorIndex[]
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = ColorFromPalette(mfengine, colorIndex[i], sinBeat);
  }

  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = ColorFromPalette(mfengine, colorIndex[i], sinBeat1);
  }
  
  EVERY_N_MILLISECONDS(25){
    for (int i = 0; i < NUM_LEDS; i++) {
      colorIndex[i]++;
    }
  }
  FastLED.show();
}

Hi, @taropty
Welcome to the forum.

Please read the post at the start of any forum , entitled "How to use this Forum".

It will show you how to post your code in its own scrolling window.

Thanks.. Tom.. :smiley: :+1: :coffee: :australia:

Use a for loop that runs from 0 to 26. Light LEDs 26+i (loop counter) and 26-i.

done!.. thanks.

how exactly? do you have a sample code I could try?

I tried something similar but it first fill one portion and then the other.. not at the same time.

Thanks,
Taro

If you want to do more than one thing at a time you can't use delay() and you can't use for or while loops. You need to learn how to multitask using millis() for timing. The several things at a time and the multiple things at a time tutorials will get you started.

1 Like

That needs a little finessing, even for a beginner: You can't use for-loops or while-loops that have delay() inside them.

Also you must not put FastLED.show() inside a for-loop or while-loop, because that is like a delay() in that it takes quite a long time. FastLED.show() takes about 3ms for each 100 LEDs. Even if you only update one led, FastLED.show() takes the same time.

thanks for the tip. but any idea on how to start the leds from the center to the end at the same time?

Post that example.

here is something I was testing with. I looking for them to run at the same time and only once.

#include <FastLED.h>

#define NUM_LEDS  30
#define LED_PIN   6

CRGB leds[NUM_LEDS];

void setup() {
  FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
  FastLED.setBrightness(50);
}

void loop() {

  for(int i = 15; i < NUM_LEDS; i++) {
    leds[i] = CRGB::White;
    FastLED.show();
    delay(100);
    leds[i] = CRGB::Blue;
  }

  for(int i = 14; i >= 0; i--) {
    leds[i] = CRGB::White;
    FastLED.show();
    delay(100);
    leds[i] = CRGB::Blue;
  }
  
}```
  for(int i = 0; i < NUM_LEDS/2; i++) {
    leds[NUM_LEDS/2+i] = CRGB::White;
    leds[NUM_LEDS/2-1-i] = CRGB::White;
    FastLED.show();
    delay(100);
    leds[NUM_LEDS/2+i] = CRGB::Blue;
    leds[NUM_LEDS/2-1-i] = CRGB::Blue;
  }

I have not removed the delay() from within the loop at this point, wanted to demonstrate that what you asked can be done even without doing that.

1 Like
  static int i = 0;
  static unsigned long lastUpdate = 0;

  if (millis() - lastUpdate >= 100) {
    lastUpdate = millis();
    leds[NUM_LEDS/2+i] = CRGB::Blue;
    leds[NUM_LEDS/2-1-i] = CRGB::Blue;
    if (++i >= NUM_LEDS/2) i = 0;
    leds[NUM_LEDS/2+i] = CRGB::White;
    leds[NUM_LEDS/2-1-i] = CRGB::White;
    FastLED.show();
  }
1 Like

this looks beautiful! I was already able to split them for both strips.

One question, how can i make it run only once then jump to the wave in my original code and keep the wave in loop?

Thanks again!

Run the startup pattern in setup.

1 Like

Only once when? When power is connected or reset is pressed? If that, then see @wildbill 's suggestion. But if you do put that code in setup() then it may be easiest to continue to use delay() inside your for-loop, because setup() gets called only once.

But if you mean once after some other button is pressed or after some other triggering event, then you can't use setup() and you need to make a "state machine" inside your code. A state machine is just a way of writing code where the code knows which of a number of states it is currently in, and executes only the required parts of the code for that state. It also checks for events or timeouts and changes to another state as required.

For example you might want to have 3 states: the "starting" state, the "wave" state and an off/sleep state. You could have the code start in the sleep state, and when a button is pressed or a pir sensor detects movement in the room, switch to the starting state. When the starting pattern has completed, it would change to the wave state. Then, after maybe 10 minutes, it would go back to sleep state.

that is a fantastic idea. This set will actually be an exhibition millennium falcon and my idea is to have buttons available for the kids (far from the set) where they can interactive with the different lights. Cockpit turning on off, turrets firing, etc.

Will try to code everything and come back if I am stuck (most probably)

Thanks again for all your help!

Taro

Thank you all for your help, I was able to put together the code with your help.

I have a new question. With Paul´s suggestion I was wondering how can I set some kind of timer so it can run the starting sequence, then the wave (for at 5 minutes), then off sequence and remain off for 1 minute and start over. is that possible?

Taro

#include <FastLED.h>

#define NUM_LEDS 110
#define LED_PIN   6

CRGB leds[NUM_LEDS];
uint8_t colorIndex[NUM_LEDS];

DEFINE_GRADIENT_PALETTE( mfengine_gp ) {
    0,   1,  8, 87,
   71,  23,195,130,
  122, 186,248,233,
  168,  23,195,130,
  255,   1,  8, 87};

CRGBPalette16 mfengine = mfengine_gp;

void setup() {
  FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
  FastLED.setBrightness(50);
  FastLED.clear();  // clear all pixel data

  for(int i = 0; i < NUM_LEDS/4; i++) {
    leds[27+i] = CRGB(0,212,255);
    leds[27-1-i] = CRGB(0,212,255);
    leds[82+i] = CRGB(0,212,255);
    leds[82-1-i] = CRGB(0,212,255);
    FastLED.show();
    delay(125);
    leds[27+i] = CRGB(255,2555,255);
    leds[27-1-i] = CRGB(255,2555,255);
    leds[82+i] = CRGB(255,2555,255);
    leds[82-1-i] = CRGB(255,2555,255);
  }
}

void loop() {

  //Creat a sin wave with period of 2 seconds (30bpm) to change the brightness of the strip
  uint8_t sinBeat = beatsin8(10, 50, 255, 0, 0); //bpm, low brightness, high brightness,
  uint8_t sinBeat1 = beatsin8(30, 50, 255, 0, 60);
  
  // Color each pixel from the palette using the index from colorIndex[]
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = ColorFromPalette(mfengine, colorIndex[i], sinBeat);
  }

  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = ColorFromPalette(mfengine, colorIndex[i], sinBeat1);
  }
  
  EVERY_N_MILLISECONDS(25){
    for (int i = 0; i < NUM_LEDS; i++) {
      colorIndex[i]++;
    }
  }

FastLED.show();

}


If it was not possible I would not have suggested it in reply #15.

So where is your attempt? Post that and we can help you get it working.

Hi PaulRB,

Below what I tried so far. The wave for some reason does not work, it remains on one color only and no pattern.

any help will be appreciated.
Taro

#include <FastLED.h>

#define NUM_LEDS 110
#define LED_PIN   6

CRGB leds[NUM_LEDS];
uint8_t colorIndex[NUM_LEDS];

DEFINE_GRADIENT_PALETTE( mfengine_gp ) {
    0,   1,  8, 87,
   71,  23,195,130,
  122, 186,248,233,
  168,  23,195,130,
  255,   1,  8, 87};

CRGBPalette16 mfengine = mfengine_gp;

void setup() {
  FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
  FastLED.setBrightness(50);
  engineOff();
}


void loop(){
  engineStart();
  delay(500);

  engineWave();
  delay(12000);

  engineOff();
  delay(1000);
  
  
}

void engineStart() {
    for(int i = 0; i <= NUM_LEDS/4; i++) {
    leds[27+i] = CRGB(0,212,255);
    leds[27-1-i] = CRGB(0,212,255);
    leds[82+i] = CRGB(0,212,255);
    leds[82-1-i] = CRGB(0,212,255);
    FastLED.show();
    delay(125);
    leds[27+i] = CRGB(255,2555,255);
    leds[27-1-i] = CRGB(255,2555,255);
    leds[82+i] = CRGB(255,2555,255);
    leds[82-1-i] = CRGB(255,2555,255);
  }
}

void engineWave() {

  //Creat a sin wave with period of 2 seconds (30bpm) to change the brightness of the strip
  uint8_t sinBeat = beatsin8(10, 50, 255, 0, 0); //bpm, low brightness, high brightness,
  uint8_t sinBeat1 = beatsin8(30, 50, 255, 0, 60);
  
  // Color each pixel from the palette using the index from colorIndex[]
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = ColorFromPalette(mfengine, colorIndex[i], sinBeat);
  }

  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = ColorFromPalette(mfengine, colorIndex[i], sinBeat1);
  }
  
  EVERY_N_MILLISECONDS(25){
    for (int i = 0; i < NUM_LEDS; i++) {
      colorIndex[i]++;
    }
  }

FastLED.show();

}

void engineOff()
{
    for(int i = 0; i <= NUM_LEDS/4; i++) {
    leds[54-i] = CRGB::Black;
    leds[0+i] = CRGB::Black;
    leds[109-i] = CRGB::Black;
    leds[55+i] = CRGB::Black;
    FastLED.show();
    delay(125);
}
}

The problem is you are at the stage of cutting & pasting bits of "found" code together without actually reading or understanding them, and hoping for the best. I could easily re-write and correct your code for you, but that would not help you get beyond the stage you are stuck in.

For example, your engineStart() function, when called, runs for around 3.5 seconds, performing it's animation for that time. But your engineWave() function runs for only an instant, setting one colour and then finishing. If you read those two functions, line by line, and try to understand what each line is doing and why, eventually you will understand why the two functions behave so differently. This is an important step to getting beyond that cut & paste stage, so if you need any help understanding any parts of those functions, please ask.