How to add a slow transition to my NeoPixel stripe?

Hey Folks,

I am a rookie tryind to get into Arduino since 2 years. But in the past there where always some issues that forced me to delay my projects.
But since 4 weeks I am trying really hard…

And now I am at a point where I don’t know how to proceed.

Basic information:
I want to build a LED-stripe to my cars interieur that shall have the same color thatn the cockpit and controls. If you open the door, the stripe shall lighten up to white white a sliding animation. If you close the door = vise versa.

Here is the code so far:

#include "FastLED.h"

#define NUM_LEDS 15
#define DATA_PIN 6

CRGB leds[NUM_LEDS];

void setup()
{ 
	Serial.begin(57600);
	Serial.println("resetting");
	LEDS.addLeds<WS2812B,DATA_PIN,GRB>(leds,NUM_LEDS);
  LEDS.setBrightness(100);
  
for(int i = 0; i < NUM_LEDS; i++)
  {leds[i] = CHSV(128, 255, 50);}
  

}


void DoorClose(){
    for(int i = 0; i < NUM_LEDS; i++) // First slide the led in one direction
  {
    leds[i] = CHSV(105, 150, 130);    // Set the i'th led to red
    leds[i-1] = CHSV(105, 150, 90);    // Set the i'th led to red
    leds[i-2] = CHSV(128, 255, 50);    // Set the i'th led to red
    FastLED.show();     // Show the leds
    delay(100);    // Wait a little bit before we loop around and do it again
  }
}

void DoorOpen(){
    for(int i = (NUM_LEDS)-1; i >= 0; i--)  // Now go in the other direction.  
  {
    leds[i] = CHSV(55, 150, 100);    // Set the i'th led to red
    leds[i+1] = CHSV(55, 150, 130);    // Set the i'th led to red
    leds[i+2] = CHSV(55, 150, 170);    // Set the i'th led to red
    FastLED.show();   // Show the leds
    delay(100);    // Wait a little bit before we loop around and do it again
  }
}

void loop()
{ 
	static uint8_t hue = 0;
	
	Serial.print("x");
  DoorOpen();
      delay(1000);
  
	Serial.print("x");
  DoorClose();
      delay(1000);
 
}

And here is a YT-Clip of the programm running:

I know my code seems simple, but that is all what I can effort with my poor knowledge about programming. The terms [i+1] and [i+2] where the only option I had with my knowledge to add some kind of “fading” to it.

But here a some issues with it.
The greenish collor wil have a different brigthness in the end of the stripe and also the white color will have a sligthly lower brightness then the rest of the stripe at the last 2 pixels.
Another huge problem (maybe the more importantone) is that the ligths should change a lot slower. but by just increase the delay, the “Fake-fade” won’t work anymore, because you can clearly see how every pixel is changin its values.

Some days before I found a nice code, where each pixel was somehow seperated into 16 sections. By that, it was able to lighten pixels up and down with a very smooth transition. but I lost the code and aren’T able to find it in the internet again.

Maybe someone can help me out?
Thanks in advance and seasonal greetings to all!

Dirk

Check your indexing. You should not access pixels below 0 and above NUM_LEDS-1, by adding or subtracting constants from i.
Except if you are sure that the library skips invalid indices.

Also check your CHSV values, they look a bit weird (unsystematic).

You can increase the number of LEDs, changing inside the loops, e.g. 6 instead of only 3, with half-valued steps.

You may have to add multiple power connections, e.g. at both ends of the stripe, eventually more in between for longer stripes. The wires in the stripes are quite thin, resulting in power loss with increasing distance from the power entry point.

Having a little trouble understanding what you are looking for.

It seems like you have a base color, currently its kind of greenish.

When the door opens you'd like..

A) A wipe to white to travel down the strip?
B) A wipe to white to travel down the strip, while they are all fading to white?
C) ?? Maybe both guesses are wrong??

When the door closes you want the opposite to happen. This would be?
A) Does the wipe from white to base color (greenish) go the other direction? Same direction as before?
B) No wipe at all, they just fade to base color?

Lets get this nailed down first, then the code will make much more sense.

-jim lee

First let me thank you booth for your replies.

@DrDiettrich:
I am currently at work and will check your suggestions when I am at home and have the chance to take my time to understand everything.

@jimLee:
I am sorry for my weird code :-[ . But even that code was hard work for my knowledge.
To define what I want to achieve, I will answer your questions with "B & A" ???

Have you seen the YouTube clip? Basicaly the animations already does exactly what I want to.
I have the animation in Loop, just for testing. Later on, I will add door contacts into the loop.

My problem is that this

    leds[i] = CHSV(105, 150, 130);    // Set the i'th led to red
    leds[i-1] = CHSV(105, 150, 90);    // Set the i'th led to red
    leds[i-2] = CHSV(128, 255, 50);    // Set the i'th led to red

is not the best solution to have a smooth fade from greenish to white and back again.
I tried to adjust the color manually. thats the reason for the differen hue settings. But it doesn't work well.
With this "solution " also comes that slowing down the speed of the animation will show how poor this animation works.

And the second problem with this kind of animation is, that (obvisiouly) the both pixels in the end of an animation wont have the same values as the rest of the pixels.

FINALY… at least I was able to find that code again during my break. It took me 3 days to find it.

Here is the link:

And here is the code:

#include <FastLED.h>
 
#define DATA_PIN 6
#define NUM_LEDS 30
CRGB leds[NUM_LEDS];
 
 
// Anti-aliased light bar example
//   v1 by Mark Kriegsman <kriegsman@tr.org>, November 29, 2013
//
// This example shows the basics of using variable pixel brightness
// as a form of anti-aliasing to animate effects on a sub-pixel level,
// which is useful for effects you want to be particularly "smooth".
//
// This animation shows two bars looping around an LED strip, one moving
// in blocky whole-pixel "integer" steps, and the other one moving
// by smoothly anti-aliased "fractional" (1/16th pixel) steps.
// The use of "16ths" (vs, say, 10ths) is totally arbitrary, but 16ths are
// a good balance of data size, expressive range, and code size and speed.
//
// Notionally, "I" is the Integer Bar, "F" is the Fractional Bar.
 
int     Ipos   = NUM_LEDS / 2; // position of the "integer-based bar"
int     Idelta = 1; // how many pixels to move the Integer Bar
uint8_t Ihue = 20; // color for Integer Bar
 
int     F16pos = 0; // position of the "fraction-based bar"
int     F16delta = 1; // how many 16ths of a pixel to move the Fractional Bar
uint8_t Fhue = 20; // color for Fractional Bar
 
int Width  = 4; // width of each light bar, in whole pixels
 
int InterframeDelay = 40; //ms
 
 
void setup() {
  delay(3000); // setup guard
  FastLED.addLeds<WS2811, DATA_PIN, GRB>(leds, NUM_LEDS);
  FastLED.setBrightness(128);
}
 
// Draw an "Integer Bar" of light starting at pixel 'pos', with given
// width (in whole pixels) and hue.
// This is not the interesting code.
void drawIntegerBar( int intpos, int width, uint8_t hue)
{
  int i = intpos; // start drawing at "I"
  for( int n = 0; n < width; n++) {
    leds[i] += CHSV( hue, 255, 255);
    i++;
    if( i == NUM_LEDS) i = 0; // wrap around
  }
}
 
 
// Draw a "Fractional Bar" of light starting at position 'pos16', which is counted in
// sixteenths of a pixel from the start of the strip.  Fractional positions are
// rendered using 'anti-aliasing' of pixel brightness.
// The bar width is specified in whole pixels.
// Arguably, this is the interesting code.
void drawFractionalBar( int pos16, int width, uint8_t hue)
{
  int i = pos16 / 16; // convert from pos to raw pixel number
  uint8_t frac = pos16 & 0x0F; // extract the 'factional' part of the position
 
  // brightness of the first pixel in the bar is 1.0 - (fractional part of position)
  // e.g., if the light bar starts drawing at pixel "57.9", then
  // pixel #57 should only be lit at 10% brightness, because only 1/10th of it
  // is "in" the light bar:
  //
  //                       57.9 . . . . . . . . . . . . . . . . . 61.9
  //                        v                                      v
  //  ---+---56----+---57----+---58----+---59----+---60----+---61----+---62---->
  //     |         |        X|XXXXXXXXX|XXXXXXXXX|XXXXXXXXX|XXXXXXXX |  
  //  ---+---------+---------+---------+---------+---------+---------+--------->
  //                   10%       100%      100%      100%      90%        
  //
  // the fraction we get is in 16ths and needs to be converted to 256ths,
  // so we multiply by 16.  We subtract from 255 because we want a high
  // fraction (e.g. 0.9) to turn into a low brightness (e.g. 0.1)
  uint8_t firstpixelbrightness = 255 - (frac * 16);
 
  // if the bar is of integer length, the last pixel's brightness is the
  // reverse of the first pixel's; see illustration above.
  uint8_t lastpixelbrightness  = 255 - firstpixelbrightness;
 
  // For a bar of width "N", the code has to consider "N+1" pixel positions,
  // which is why the "<= width" below instead of "< width".
 
  uint8_t bright;
  for( int n = 0; n <= width; n++) {
    if( n == 0) {
      // first pixel in the bar
      bright = firstpixelbrightness;
    } else if( n == width ) {
      // last pixel in the bar
      bright = lastpixelbrightness;
    } else {
      // middle pixels
      bright = 255;
    }
   
    leds[i] += CHSV( hue, 255, bright);
    i++;
    if( i == NUM_LEDS) i = 0; // wrap around
  }
}
 
 
void loop()
{
  // Update the "Fraction Bar" by 1/16th pixel every time
  F16pos += F16delta;
 
  // wrap around at end
  // remember that F16pos contains position in "16ths of a pixel"
  // so the 'end of the strip' is (NUM_LEDS * 16)
  if( F16pos >= (NUM_LEDS * 16)) {
    F16pos -= (NUM_LEDS * 16);
  }
   
  // For this demo, we want the Integer Bar and the Fraciton Bar
  // to move at the same speed down the strip.
  // The Fraction Bar moves 1/16th of a pixel each time through the
  // loop, so to get the same speed on the strip for the Integer Bar,
  // we need to move it by 1 full pixel -- but only every 16 times
  // through the loop.  'countdown' is used to tell when it's time
  // to advance the Integer Bar position again.
  static byte countdown = 0;
  if( countdown == 0) {
    countdown = 16; // reset countdown
     
    // advance Integer Bar one full pixel now
    Ipos += 1;
    // wrap around at end
    if( Ipos >= NUM_LEDS) {
      Ipos -= NUM_LEDS;  
    }
   }
   // countdown is decremented every time through the loop
   countdown -= 1;
   
   // Draw everything:
   // clear the pixel buffer
   memset8( leds, 0, NUM_LEDS * sizeof(CRGB));
   // draw the Integer Bar, length=4px, hue=180
   drawIntegerBar( Ipos, Width, Ihue);
   // draw the Fractional Bar, length=4px, hue=180
   drawFractionalBar( F16pos, Width, Fhue);
   
   FastLED.show();
   delay(InterframeDelay);
}

When I am back home, I will try to merge both together…

I think I get what you're looking for. A color wipe that has a fade in length from background to foreground. And, its anti aliased as well.

Not tough with the proper s-ware toolkit and an understanding of math.. How are you with math?

I'd not try to "merge" the programs. Therein lies madness.

For the first pass I'd drop everything but a simple color wipe Color A to color B. Write it yourself, from scratch, not copy pasting. Make a simple wipe function as simple as possible. Use this to start building your your kit of tools.

THEN

Try extending this SIMPLE program, you fully understand because you wrote it and didn't merge or copy paste it, to do a wipe from color A to color B using a short line of intermediate colors. That's about where your at now but thrashing.

Once you have color wipe running with the intermediate color line, you can have a go at the anti alias thing and play with math.

Then there's all the cases like where a door is closed before the open animation is complete. What do we do then?

Well, your milage may vary, but that's how I'd go at it.

-jim lee