I think I messed up math

I used this: Arduino Code | Larson Scanner Shades (Trinket-Powered NeoPixel LED Strip Glasses) | Adafruit Learning System and changed to use fastled library as it'd be easier to do color cycling.

#include <FastLED.h>

#define N_LEDS 10        // total number of LEDs on the strip. Higher LED makes smoother runs but uses more power
#define PIN     3        // usually any digital pin other than 0 and 1 works
#define LED_TYPE WS2812B // I assume you have WS2812B leds, if not just change it to whatever you have
#define HIBRIGHT 255     // Control the brightness of your leds, this is for center
#define MIDBRIGHT 127    // medium brightness for those on either side of the center
#define LOWBRIGHT 63    // low brightness for the fading part
#define SATURATION 127   // Control the saturation of your leds 
int pos = 0;
int dir = 1;             // Position, direction of "eye"
byte j = 0;
CRGB leds[N_LEDS];       // initial setup of LED array

void setup() {
  Serial.begin(9600);
  FastLED.addLeds<LED_TYPE, PIN>(leds, N_LEDS);
}

void loop() {
  // Draw 5 pixels centered on pos.  code will clip any LED
  // off the ends of the strip, we don't need to watch for that.
  leds[pos - 2] = CHSV(j++, SATURATION, LOWBRIGHT);
  leds[pos - 1] = CHSV(j++, SATURATION, MIDBRIGHT);
  leds[pos] = CHSV(j++, SATURATION, HIBRIGHT);
  leds[pos + 1] = CHSV(j++, SATURATION, MIDBRIGHT);
  leds[pos + 2] = CHSV(j++, SATURATION, LOWBRIGHT);
  FastLED.show();
  // since I'm using byte variable for J, it will roll over to 0
  pos += dir;       // Time to check and bounce off ends of strip
  if (pos <= 0) {        // reached one end, change direction
    pos = 1;
    dir = 1;
  }
  if (pos >= N_LEDS) {   // reached other end, change direction
    pos = N_LEDS - 2;
    dir = -1;
  }
  delay(80);            // smaller number for faster sweep
  FastLED.clear();      // clear all pixel data
  FastLED.show();       // code cycles back to top and displays LED before you can see it going off

  Serial.print(" Hue ");
  Serial.print(j);
  Serial.print(" Pos ");
  Serial.print(pos);
  Serial.print(" Dir ");
  Serial.println(dir);
}

Problem #1: checking the serial monitor when LED pos reached N_LEDS (set to 10), it's supposed to change dir to -1, set POS to 8 and also add dir to pos (8 + -1 should be 7). So when LED is chasing forward, dir is adding +1 to pos but when LED reaches the end and dir changes to -1 pos does not get deducted. It remains stuck at 8 (N_LEDS - 2).

For some reason the exact same code works as originally used with Neopixel library, maybe something didn't get translated over or I need to change variable?

#2 Also I don't think j variable is adding up correctly. When I skip the reversing and let it run forward and cycle back to 1 after reaching 255 (used byte variable to auto rollover to 0), j resets after reaching end of cycle rather than continuing toward 255

example of serial monitor: (Hue is j variable for LED color, Pos is pos variable, which LED is the center, and Dir is dir, 1 or -1 to indicate direction of scan

 Hue 0 Pos 0 Dir 1
 Hue 5 Pos 1 Dir 1
 Hue 10 Pos 2 Dir 1
 Hue 15 Pos 3 Dir 1
 Hue 20 Pos 4 Dir 1
 Hue 25 Pos 5 Dir 1
 Hue 30 Pos 6 Dir 1
 Hue 35 Pos 7 Dir 1
 Hue 40 Pos 8 Dir 1 

Looks normal up to here then dir changes as expected, POS does not change at all Also Hue resets to 1 and doesn't change while LED remains stuck at the end

 Hue 1 Pos 8 Dir -1
 Hue 1 Pos 8 Dir -1
 Hue 1 Pos 8 Dir -1
 Hue 1 Pos 8 Dir -1
 Hue 1 Pos 8 Dir -1

Can anyone look at the code and see what I messed up so I can get the Larson scanner working correctly and also color cycling smoothly?

At startup, pos == 0 so these are the same as leds[-2] and leds[-1] which means you are writing to memory you don't own. After that, all bets are off.

in the original code I suppose you address the pixels indirectly through some function or operator overload which knows how to reject negative index or addressing beyond the bounds of the strip.

here you have an array with fixed bounds :

when you do

you probably need to ensure pos is within 2 and N_LEDS-3 so your changing of direction should not happen when pos reaches 0 or N_LEDS

I don't get why you are happy (or seems...) that pos get stuck at 8? Shouldn't it go to until 9 before you change its value to N_LEDS - 2 ?

And why in your loop you use [pos - 1] ? With pos initialized to 0 then you are writing at the address -1 which is not part of your array...

Yet that works with Neopixel library.

#define PIN     4

Adafruit_NeoPixel strip = Adafruit_NeoPixel(N_LEDS, PIN, NEO_GRB + NEO_KHZ800);

It also allowed of leds[pos - 2] and leds[pos - 1] and it worked just fine. I guess Neopixel ignore illegal LED numbering?

Revised the code a bit to exclude out of bound LED

#include <FastLED.h>

#define N_LEDS 10        // total number of LEDs on the strip. Higher LED makes smoother runs but uses more power
#define PIN     3        // usually any digital pin other than 0 and 1 works
#define LED_TYPE WS2812B // I assume you have WS2812B leds, if not just change it to whatever you have
#define HIBRIGHT 155     // Control the brightness of your leds, this is for center
#define MIDBRIGHT 95     // medium brightness for those on either side of the center
#define LOWBRIGHT 31     // low brightness for the fading part
#define SATURATION 127   // Control the saturation of your leds 
int pos = 0;
int dir = 1;             // Position, direction of "eye"
byte hue = 0;
CRGB leds[N_LEDS];       // initial setup of LED array

void setup() {
//  Serial.begin(9600);
  FastLED.addLeds<LED_TYPE, PIN>(leds, N_LEDS);
}

void loop() {

//  Serial.print(" Hue ");  // for debugging values
//  Serial.println(hue);
//  Serial.print(" Pos ");
//  Serial.print(pos);
//  Serial.print(" Dir ");
//  Serial.println(dir);

  if (pos > 2); {
    leds[pos - 2] = CHSV(hue, SATURATION, LOWBRIGHT);
  }
  if (pos > 1); {
    leds[pos - 1] = CHSV(hue, SATURATION, MIDBRIGHT);
  }
  leds[pos] = CHSV(hue++, SATURATION, HIBRIGHT);
  if (pos < N_LEDS - 1) {
    leds[pos + 1] = CHSV(hue, SATURATION, MIDBRIGHT);
  }
  if (pos < N_LEDS - 2) {
    leds[pos + 2] = CHSV(hue, SATURATION, LOWBRIGHT);
  }
  FastLED.show();
                             // since I'm using byte setting for variable J, it will roll over to 0 after 255
  pos = pos + dir;           // Time to check and bounce off ends of strip
  if (pos < 0) {             // reached one end, change direction
    pos = 1;
    dir = 1;
  } else if (pos > N_LEDS) {  // reached other end, change direction
    pos = N_LEDS - 2;
    dir = -1;
  }
  delay(40);                  // smaller number for faster sweep
  FastLED.clear();            // clear all pixel data
  FastLED.show();             // code cycles back to top and displays LED before you can see it going off
}

Now it works going back and forth. But the color still doesn't work, it keeps getting reset. I changed the variable from j to hue in case of conflict, it still resets at the end of loop and not going to 255.

if you look at the operator overload for [] in the CRGB structure

there is no test for bounds

For the Adafruit_NeoPixel class you call pixels.setPixelColor() which does perform the test

(and as the indexes are unsigned, a negative value would be a very large number, for example -1 would become 65535 so above the number of pixels and thus the test

  if (n < numLEDs) {

works for that too

you still have bugs due to the wrong test and a semi colon that should not be there...

I don't know if it's relevent, but why do you have two times FastLED.show(); in your code without a FastLED.clear(); between ?

you would add clear() if you wanted to clear() the strip first

This one needs to be removed also!!

yeah - wanted to test if OP would go check the others

basically it has to be

  if (pos >= 2) leds[pos - 2] = CHSV(hue, SATURATION, LOWBRIGHT);
  if (pos >= 1) leds[pos - 1] = CHSV(hue, SATURATION, MIDBRIGHT);

  leds[pos] = CHSV(hue++, SATURATION, HIBRIGHT);

  if (pos <= N_LEDS - 2) leds[pos + 1] = CHSV(hue, SATURATION, MIDBRIGHT);
  if (pos <= N_LEDS - 3) leds[pos + 2] = CHSV(hue, SATURATION, LOWBRIGHT);

  FastLED.show();
1 Like

read carefully

  leds[pos] = CHSV(hue++, SATURATION, HIBRIGHT);
1 Like

don't delete a post after comments were made....
if you want to edit it, the make it clear you corrected it but keep the content there

Duplicate "show" deleted, no need to show it twice. I moved clear to the top just before setting LED variables.

Also removed semi colons, the code is working great.

I hid hue++ rather than a separate hue++; elsewhere No difference in final code size but a few bytes less file.

#include <FastLED.h>
#define N_LEDS 10        // total number of LEDs on the strip. Higher LED makes smoother runs but uses more power
#define PIN     3        // usually any digital pin other than 0 and 1 works
#define LED_TYPE WS2812B // I assume you have WS2812B leds, if not just change it to whatever you have
#define HIBRIGHT 255     // Control the brightness of your leds, this is for center
#define MIDBRIGHT 95     // medium brightness for those on either side of the center
#define LOWBRIGHT 31     // low brightness for the fading part
#define SATURATION 200   // Control the saturation of your leds 
int pos = 0;
int dir = 1;             // Position, direction of "eye"
byte hue = 127;          // color, just needed to set variable here. since I'm using byte
                         // setting for variable hue, it will roll over to 0 after 255

CRGB leds[N_LEDS];       // initial setup of LED array

void setup() {
  FastLED.addLeds<LED_TYPE, PIN>(leds, N_LEDS);
}

void loop() {
  FastLED.clear();           // clear all old pixel data
  if (pos > 2) {             // skipping out of range LEDs
    leds[pos - 2] = CHSV(hue, SATURATION, LOWBRIGHT);
  }
  if (pos > 1) {
    leds[pos - 1] = CHSV(hue, SATURATION, MIDBRIGHT);
  }
  leds[pos] = CHSV(hue++, SATURATION, HIBRIGHT);  // center of the eye, also incrementing hue
  if (pos < N_LEDS - 1) {
    leds[pos + 1] = CHSV(hue, SATURATION, MIDBRIGHT);
  }
  if (pos < N_LEDS + 2) {
    leds[pos + 2] = CHSV(hue, SATURATION, LOWBRIGHT);
  }
  FastLED.show();            // displays new value to LED
  pos = pos + dir;           // Time to check and bounce off ends of strip
  if (pos < 0) {             // reached one end, change direction
    pos = 1;                 // move to LED 1
    dir = 1;
  } else if (pos > N_LEDS) {  // reached other end, change direction
    pos = N_LEDS - 2;         // movie to 2 LED from end of the strip
    dir = -1;
  }
  delay(40);                  // smaller number for faster sweep
}

Final code if anyone wants to steal my rainbow Larson scanner mod.

If you want to change the direction of color cycling, change hue++ to --hue

Ok my bad, I'm new here and I though it would be better not to charge the forum with this kind of useless post...

Becarful with it
hue++; isn't exactly the same as ++hue;.
So to change the direction but with the exact same way here you need to put hue--;.

Just checking… do you know why that was important ?

no worries - the generally agreed rule is not to delete something if it has been commented upon as it makes the thread look weird afterwards, people would wonder what is that post about since the context is gone.

2 Likes

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.