Cylon/Larsen Scanner FastLED Sequence

I have a question regarding my code attached below. This sequence is designed to do a sweeping motion with 8 LEDs. I put it together from several different sources throughout the web. The problem I’m running into is a minor hiccup in the sequence. The lights should go like this:

1-2-3-4-5-6-7-8-7-6-5-4-3-2-1-2-3…

Instead, I see this:

1-2-3-4-5-6-7-8-8-7-6-5-4-3-2-1-1-2-3…

I feel like this would be fixed if the forward sequence used its 1-8 map, and the sequence back used 7-2. But I am not sure how to implement that here. Can anyone give me some suggestions? Thanks in advance!

#include "SoftwareSerial.h"
#include <FastLED.h>

#define NUM_LEDS 8        // How many leds in your strip?
#define DATA_PIN 6        // Data pin on Arduino
#define TAIL 5            // Lower dissapates faster
#define TAILSPEED 3       // Determines trail dissipation speed, 
#define COLOR CRGB::Red   // See http://fastled.io/docs/3.1/pixeltypes_8h_source.htm line 590 for list
int BRIGHT = 84;          // LED Brightness
int angle = 0;            //
int scan_speed = 6;       // Lower is faster.  Usable range 0-20, Default 6
bool scanner_on = true;   // Default to Scanner on
CRGB leds[NUM_LEDS];      // Defining the LED array

void setup() { 
  Serial.begin(9600);
  FastLED.addLeds<PIXIE,DATA_PIN>(leds,NUM_LEDS);
  FastLED.setBrightness(BRIGHT);
}

void scan() {
  uint8_t lead_dot = map(triwave8(angle), 0, 255, 0, NUM_LEDS);
  angle = angle + 1;
  leds[lead_dot] = COLOR;
}

void loop() { 
  EVERY_N_MILLISECONDS_I(scan_speedTimer, 0) {
    if (scanner_on) {
      scan_speedTimer.setPeriod(scan_speed);
      scan();   //patternsList[gCurrentPatternNumber]();
      FastLED.show();
    }
  }
  EVERY_N_MILLISECONDS(TAILSPEED) { if (scanner_on) {fadeToBlackBy(leds, NUM_LEDS, TAIL);} }
}

Thanks for using code tags, +1 karma, but I'm not sure what you posted is the complete code that you have working. I see a variable or object used that is not defined (scan_speedTimer).

No Problem, thanks for the karma! I am all about making it neat/easier to read. I am in IT by trade, and I know how annoying it is to troubleshoot something that isn’t laid out well.

I posted everything I have in my script. scan_speed is the variable, and it is declared. The timer is defined right inside the EVERY_N_MILLISECONDS_I block. It does compile and upload just fine, with no errors (just the behavior issue I’m trying to solve here), so I am assuming it’s not an issue, as Arduino IDE has no qualms about calling me out for any variables I don’t have declared.

Any ideas on what I can do to eliminate the doubling up on the ends?

Ah, I see. Seems every time a question is posted about FastLED, I find out about some new function or macro it has. Had not seen triwave8() before either.

I think that triwave8() function, combined with map() is causing the effect you don’t like. The triwave8() function is producing a value that varies between 0 and 255 and map is reducing that to a value between 0 and 7. So as triwave8() increases from 223 to 255, map() turns that into 7. Then as triwave() reduces from 255 down to 223, map() turns this into 7 also. Similar thing near zero.

#include "SoftwareSerial.h"
#include <FastLED.h>

#define NUM_LEDS 8        // How many leds in your strip?
#define DATA_PIN 6        // Data pin on Arduino
#define TAIL 5            // Lower dissapates faster
#define TAILSPEED 3       // Determines trail dissipation speed, 
#define COLOR CRGB::Red   // See http://fastled.io/docs/3.1/pixeltypes_8h_source.htm line 590 for list
int BRIGHT = 84;          // LED Brightness
int angle = 0;            //
int scan_speed = 6;       // Lower is faster.  Usable range 0-20, Default 6
bool scanner_on = true;   // Default to Scanner on
CRGB leds[NUM_LEDS];      // Defining the LED array

void setup() { 
  Serial.begin(9600);
  FastLED.addLeds<PIXIE,DATA_PIN>(leds,NUM_LEDS);
  FastLED.setBrightness(BRIGHT);
}

void scan() {
  angle = angle + 1;
  if (angle >= 14) angle = 0;
}

void loop() { 
  EVERY_N_MILLISECONDS_I(scan_speedTimer, 0) {
    if (scanner_on) {
      scan_speedTimer.setPeriod(scan_speed);
      scan();   //patternsList[gCurrentPatternNumber]();
    }
  }
  EVERY_N_MILLISECONDS(TAILSPEED) {
    if (scanner_on) {
      uint8_t lead_dot = angle < 7 ? angle : 7 - (angle - 7);
      leds[lead_dot] = COLOR;
      fadeToBlackBy(leds, NUM_LEDS, TAIL);
      FastLED.show();
      }
   }
}

Thanks for the explanation of what you found, it makes a lot of sense. I tried your modified code though, and it didn't quite work... all of the lights started flickering randomly. I might just see if I can modify the wave function to do less rounding, or maybe choose a different sine function that maybe maps it a little differently.

The code I posted was untested and written on my phone. Please don't just dismiss it, or my effort will have been wasted. Try increasing scan_speed to maybe 200.

You’re right, sorry, I didn’t mean to sound like I was dismissive of your efforts. In fact, you’re double right, when I bump it up to 200, it does look much better. Thanks! +1 kudos!

I am curious why you moved the main function in with the fadetoblack function (the second EVERY_N_MILLISECONDS). I had originally put the fade into a separate thread because I had wanted the fade to operate independent of speed of the LEDs, so that the fade would be constant. But in testing with different values, I see that it’s doing that anyway. ??? I’m very happy it works, regardless.

I’d to see if I can put them back inside of the function though, as I want to implement additional modes, and it would be easier to call them by function. Back to the grind! Thanks again!

It's a good question. I'm glad to see you asked, it's a good sign that you asked. Let me try to explain simply.

In your original code, "angle" increments every 6ms. But the output of the map() function only updates 32x slower. That's why I suggested increasing scan_speed by ~30 times, to get the timing back to around the same. But if that was the only change, the red dots would fade too quickly. The fading would, relatively, happen x32 more quickly, too fast to see, and the red dots would seem to dim. So I needed to re-draw the red dots more often, so they stay bright. Does that make sense?

PaulRB:
Let me try to explain simply.

Oh, sh!t, please let me clarify that. I did not mean explaining simply so you will understand. I'm not implying you are not very intelligent! What I mean is that explaining something in a simple way is a rare skill. A skill I hope I have, to a small degree, but a skill i know I have room/opportunity to improve on!

PaulRB:
Oh, sh!t, please let me clarify that. I did not mean explaining simply so you will understand. I'm not implying you are not very intelligent! What I mean is that explaining something in a simple way is a rare skill. A skill I hope I have, to a small degree, but a skill i know I have room/opportunity to improve on!

No worries, I didn't take it to be any sort of insult! :). I appreciate you taking the time to explain it more simply. I may be a veteran in IT, and am pretty good at bash scripting, but I am more green with Arduino programming. Strong proponent of the teaching a man to fish methodology. But sometimes you just have to be fed a fish here and there when your line is coming up empty.

BTW, Do you see an easy way to consolidate these back into a function? Started experimenting with adding back into a function, as I'm hoping to make this one function of many, but just thought I'd ask, while we're on the subject.

Yes, you could put those lines back in the function and have the function run every 6ms as before. But you would have to slow down the dot movement by ~30x, but not the drawing of the dot, which must be done each time to stop them fading. You might be able to put another EVERY_N_MILLISECONDS macro in for that, or have another variable which counts from 0 to 30 and "angle" gets updated only when the new variable hits 30.