how to do smoth transitions with the fastled lib

Hi,
I'm using a WS2812b xy matrix as a lamp (all pixels always have the same color) inside an IKEA
LAMPAN table lamp, this lamps are very cheap and are excellent difusers,
I'm using a Wemos D1 mini by no special reason.

The idea is to generate a random color do a smooth slow transition to that color, generate another color and repeat.

I have 2 problems.

  • I try to randomize the sequence with randomSeed( analogRead(A0) ); inside setup() but I always get the same sequence, analogRead(A0) always return the value 3. Not a major problem, I just find that somewhat strange as A0 is not connected to anything.

  • The transition is far from smooth, in fact it's a bit jumpy. I wasn't able to find on the net a simple way to do this, most info is about led strips, so I come up with the idea of creating a big array (4096), use fill_gradient to fill that array and set the 64 keds of the matrix from each position of that big array. It works, but it is not very smooth. I'd like to ask for help to do this.

I made a small video with the phone, the colors are all washed out, it looks much better in reality, but you can see what I'm complaining about at about 55sec. - https://youtu.be/RyBnDxMUh1g

#include <FastLED.h>

#define WIDTH 8
#define HEIGHT 8
#define NUM_LEDS WIDTH*HEIGHT

#define DATA_PIN 5
CRGBArray<NUM_LEDS> leds;
CRGBArray<4096> leds1;

void setup() { 
    int x;
    x=analogRead(A0); // always return 3 !!!
    randomSeed(x);
    Serial.begin(9600);
    Serial.print("BEGIN ");
    Serial.println(x);
    LEDS.addLeds<WS2812B,DATA_PIN,GRB>(leds,NUM_LEDS);
    LEDS.setBrightness(16);
    FastLED.show();
    leds[0].r=128;
    leds[NUM_LEDS-1].r=128;
    FastLED.show();
    delay(3000);
}

void loop()
{
    int f;
    byte x1=0, x2=0, x3;

    while(1)
    {
        // try to keep the hue difference between 16 and 32, not sure if this helps
        while(abs(x1-x2)<16 || abs(x1-x2)>32) 
        {
            x2=random8();
            Serial.print(".");
        }
        Serial.print(abs(x1-x2));
        Serial.print(" ");
        Serial.print(x1);
        Serial.print(" ");
        Serial.println(x2);
        
        fill_gradient(&leds1[0], 4096, CHSV(x1, 255,255), CHSV(x2,255,255), LONGEST_HUES);
        for(f=0;f<4096;f++)
        {
            fill_solid(leds, 64, leds1[f]);
            FastLED.show();
            delay(10);
            yield();
        }
        x1=x2;
    }
}

I don't use fastled (I use my modified version of adafruit neopixel, and ignore all their abstractions for setting colors and directly write to the frame buffer), but I had to deal with a similar thing for my LED controller. I used a scratch buffer, calculated smooth transitional values between the two colors when I picked a new color, and then referred back to that when doing the animation (I had to have the ability to have each pixel set to a different value along that spectrum, so recalculating the value as I needed it for each LED made the calculations take so long that other parts of my code broke).

Are you sure nothing is connected to that pin? A value of 3 would be consistent with it being shorted to ground (sanity check to rule out damaged chip: analogReadSerial example and make sure that you can get different values out by applying an external voltage to the pin).

I've never had problems with analogRead() of an unconnected pin not returning a value that was at least marginally unpredictable (though it's been noted that it's a crap way to seed it, as randomSeed() takes an unsigned long, ie, a number from 0 ~ 4.2 billion) - so it's odd that you're having that issue.

ocsav:
Hi,
I'm using a Wemos D1 mini by no special reason.

  • I try to randomize the sequence with randomSeed( analogRead(A0) ); inside setup() but I always get the same sequence, analogRead(A0) always return the value 3. Not a major problem, I just find that somewhat strange as A0 is not connected to anything.

I had seen this trick using an unconnected Analog input as a seed for random(), so I set up a test on a Wemos that I had on my desk. I also got a consistent 1 or 2. Pretty useless as a seed for random().

OH! Of course, I missed the fact that it's on a D1 mini.

Like many ESP8266 breakout boards, the board has a resistor divider to divide a 0~3.3v input down to 0~1v (the analog pin on the esp8266 can only read 0~1v). But this of course means that when nothing is connected, the lower leg of the divider pulls it down to 0.

You can't use the unconnected analog pin trick on those boards to get a random seed. Might be able to it if you located and removed that resistor from the board. I'm not sure how amenable the analog pin is to this sort of use - the esp8266's on-chip peripherals are all pretty crap, which is about what you should expect from a 160MHz microcontroller with tens of kb of ram and megabyte-size flash space with native wifi that costs less than a cup of coffee).

Here's a function I wrote, playing with the ESP.getCycleCount() function in the ESP library.
I call it mostlyRandom, because I haven't tested the randomness of the output.

unsigned long mRandom(unsigned long rLow, unsigned long rHigh) {
  unsigned long randomNumber;
  static int lastRandomNumber = 0;


  if (rHigh > 4294967295) {
    rHigh = 4294967295;
  }
  if (rLow < 0) {
    rLow = 0;
  }
  if (rHigh = 4294967295) {   // Fixes a bug?? in random(low,high) where the high is 
    rHigh < 4294967295 + 1;   // "up to but not including"
  }
  
  uint32_t cycleCount = ESP.getCycleCount();
  randomSeed(cycleCount);
  randomNumber = random(rLow, rHigh);
  while (randomNumber == lastRandomNumber) {    // No duplicates
    randomNumber = random(rLow, rHigh);
  }
  lastRandomNumber = randomNumber;
  return (randomNumber);
}

Thanks Steve,

randomSeed(ESP.getCycleCount()); inside setup() now makes the start point different every time.
Curiouslly, FastLED's random8() is not affected, so I had to change to random(255), but for this case is more than good enough.

But I'm still not happy with the color transitions, I was able to get it a bit better using FastLED.delay(6) instead of a delay(10); and I quit trying to keep the last/new hue distance small.

Is this the best "spread" I can do ?

fill_gradient(&leds1[0], 4096, CHSV(x1, 255,255), CHSV(x2,255,255), LONGEST_HUES);