Strange Arduino Behavior

For some reason, after about a minute of running our Arduino program that controls our lights they start to go haywire. It’s as if the update rate of the main loop() has stopped updating regularly. The LEDs don’t appear to recieve values that are not sent by the program, only the timing is wrong. I have tried removing the delay; the problem persisted.

Oddly enough, the problem resolves itself if a new value is sent over Serial by the RIO. Not immediately, but within a second or two. And the problem isn’t permanently fixed, it will come back eventually.

#include "FastLED.h"
#define COLOR_ORDER GRB
#define MAX_BRIGHTNESS 255
//Tell it how many leds are in the strip. AndyMark's 2.5 meter strip has 150 leds
#define NUM_LEDS 265
// This is an array of leds. One item for each led in your strip
CRGB leds[NUM_LEDS];
//CSK 3/17/2014 I moved this to a pin that doesn't conflict with Ethernet functions in case you want to control LEDs via Ethernet
#define DATA_PIN 6 //White wire from the http://www.andymark.com/product-p/am-2917.htm power connector


int mode = 0;


//This function is used to setup things like pins, Serial ports etc.
//Here we specify which chipset our LEDs run off of by our choice of config function
void setup()
{
 // Uncomment one of the following lines for your leds arrangement.
 // FastLED.addLeds<TM1803, DATA_PIN, RGB>(leds, NUM_LEDS);
 // FastLED.addLeds<TM1804, DATA_PIN, RGB>(leds, NUM_LEDS);
 // FastLED.addLeds<TM1809, DATA_PIN, RGB>(leds, NUM_LEDS);
 //FastLED.addLeds<WS2811, DATA_PIN, RGB>(leds, NUM_LEDS);
 // FastLED.addLeds<WS2812, DATA_PIN, RGB>(leds, NUM_LEDS);
 //CSK 2/12/2016 This is the correct chipset for the am-2916 LED strip
 FastLED.addLeds<WS2812B, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS);
 // FastLED.addLeds<UCS1903, DATA_PIN, RGB>(leds, NUM_LEDS);
 //FastLED.addLeds<WS2801, RGB>(leds, NUM_LEDS);
 // FastLED.addLeds<SM16716, RGB>(leds, NUM_LEDS);
 // FastLED.addLeds<LPD8806, RGB>(leds, NUM_LEDS);
 //***This is the chipset in the AM-2640 LED strip***
 //CSK 3/17/2013 Changed to this function to allow direct data and clock pin specification
 //FastLED.addLeds<WS2801, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
 // FastLED.addLeds<SM16716, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
 // FastLED.addLeds<LPD8806, DATA_PIN, CLOCK_PIN, RGB>(leds, NUM_LEDS);
 FastLED.clear();
 FastLED.show();
 delay(250);
 //clear() turns all LEDs off
 FastLED.clear();
 FastLED.setBrightness(MAX_BRIGHTNESS);
 fill_solid( leds, NUM_LEDS /*number of leds*/, CRGB( 125, 125, 125) );
 FastLED.show();
 // start serial port at 9600 bps:
 Serial.begin(9600);
 makelookuptable();
}

void loop()
{
 FastLED.show();
 delay( 50 );
 FastLED.clear();
 int curTime = millis();
 for( int led_number = 0; led_number < NUM_LEDS; led_number++ ){
  switch( mode ){
    case 0: //PULSE_RED
      leds[led_number] = CRGB( 125 * (fastSin( curTime * 0.005 ) + 1), 0, 0 );
      break;
    case 1: //PULSE_GREEN
      leds[led_number] = CRGB( 0, 125 * (fastSin( curTime * 0.005 ) + 1), 0 );
      break;
    case 2: //PULSE_BLUE
      leds[led_number] = CRGB( 0, 0, 125 * (fastSin( curTime * 0.005 ) + 1) );
      break;
    case 3: // SOLID_RED
      leds[led_number] = CRGB( 255, 0, 0 );
      break;
    case 4: // SOLID_GREEN
      leds[led_number] = CRGB( 0, 255, 0 );
      break;
    case 5: // SOLID_BLUE
      leds[led_number] = CRGB( 0, 0, 255 );
      break;
    case 6: // MOVING_RED
      leds[led_number] = CRGB( 125 * (fastSin(curTime * 0.005 + led_number * 0.5) + 1), 0, 0 );
      break;
    case 7: // MOVING_GREEN
      leds[led_number] = CRGB( 0, 125 * (fastSin(curTime * 0.005 + led_number * 0.5) + 1), 0 );
      break;
    case 8: //MOVING_BLUE
      leds[led_number] = CRGB( 0, 0, 125 * (fastSin(curTime * 0.005 + led_number * 0.5) + 1) );
      break;
  }
 }
}

String last = "";
void serialEvent() {
  while (Serial.available()) {
     char c = Serial.read();
     if( c == '
' ){
      mode = last.toInt();
      last = "";
     }else{
        last += c;
     }
  }
}

const int approx_2pi = 63;
double sin_lookup[approx_2pi];

void makelookuptable(){
  for( int x = 0; x < approx_2pi; x++ ){
    sin_lookup x ] = sin( x * 0.1 );
  }
}

double fastSin( double input ){
  int places3 = (int)(input * 10);
  int approximation = (places3 % approx_2pi );
  return sin_lookup approximation ];
}

does your Arduino and your RoboRio share a common ground?

The issue sounds like you have a floating high and they are not able to communicate because of that

The communication works perfectly fine. As the arduino in question is a RIODuino, I assume it shares a common ground with the RIO.

I would put a millis() call at the top and bottom of the loop() to see how long it’s taking to run.

If you need to speed it up a bit, you could replace the curTime * 0.005 instances with curTime/200 (integer math is faster) and make the argument to fastSin an integer. Better yet, ditch the call and just use an array lookup. Whenever feasible in tight loops on slower CPUs, replace floating point math with integer math and remove function calls which add little value.

Oh - you could also put the switch/case statement OUTSIDE of the loop. It would mean writing six separate loops, but you would not have to evaluate the test every pass.

1 - I can do that, but how would I get the output? Send it to the RIO?

2 - I was not aware of that - I thought multiplying is always faster than dividing. I’m not going to ditch the function altogether, though I’ve changed it so the compiler will inline it for me. I’ve also gone through and replaced all doubles with floats.

3 - I really don’t want to do this. Switch statements are usually very fast, and I don’t think my loop() is taking very long to execute anyway… If it was, wouldn’t there be problems well before a minute of execution?

If there were no common ground between them, the lights would be a mess from the beginning, not a minute after starting.

Since the Arduino is humming in it’s own little world getting the occasional signal from the robot, programming fast routines is probably not an issue.

I’m wondering if you need a bit of code to sort of reset each of your light displays. Does the haywire happen at the end of a sequence, when it goes “off the top” and has to reset back to zero?

When I do arduino LEDs I have two sections for each code, one that is called once when that light sequence is chosen (each time it is chosen), and one that is the actual “loop”. You may have it already, using curTime.

Make sure you have the number of LEDs you say you have:

//Tell it how many leds are in the strip. AndyMark’s 2.5 meter strip has 150 leds
#define NUM_LEDS 265

I’m sure you did but this got me wondering.

Oddly enough, the problem resolves itself if a new value is sent over Serial by the RIO. Not immediately, but within a second or two. And the problem isn’t permanently fixed, it will come back eventually.
This may be a hint of the answer. The arduino switches to new code, resetting (maybe?) the variables, then running to the end, then going haywire again.

It runs through the full sequence a few times before the problem occurs.

Really, there isn’t a “sequence” per say - the whole thing is designed to be asynchronous.

I’ve now changed the number of LEDs. I had previously copied that from the example code for the RGB strip here, didn’t realize it was the wrong number of LEDs. Very confusing.

We had several issues with the serial communication. We ended up wiring 2 DIO channels which works great and it’s fast. You could do this with three to handle your different cases. Save lot of time getting tricky serial comms debugged.

The communication works perfectly fine. I was actually very surprised because it worked on the first try :yikes:.

But… could it be introducing timing issues? Have you tried removing the serial processing and just setting the mode to a value to see if the problem goes away?

I mean… I suppose it’s possible. If the arduino documentation is entirely wrong.

According to the documentation, serialEvent is only called when there is data available - it should not matter what code is put in that function.

The problem occurs after a minute of the RIO not sending any data to the arduino. Therefore the code inside serialEvent should not be executed, nor should any other code on the arduino related to serial communication.

I will, however, comment out my serial code at the next opportunity. If that fixes it, I will be questioning the validity of all arduino documentation and refrain from purchasing any arduino products in the future.

Not sure if this is your issue, but still something you should definitely fix.

In your void serialEvent() function, you use string concatenation. This is a really, really bad idea, as Arduino’s string library has well documented memory leaks and fragmentation issues, especially with string concatenation. This is because it uses dynamic memory allocation. I think they’ve fixed the memory leak issues, but there’s inherently nothing they can do about fragmenting the memory.

You should move away from using String, and instead use char arrays of a fixed size so you’re not dynamically allocating memory. I’m happy to explain in more detail if you’d like, or even help convert the code to use c-style strings (char arrays).

Wow, really?

Looks like I should stop usingexample code… I’m used to official tutorials showing good practice.

Sample code is often for illustration of concepts and with little consideration of performance (or of library bugs that should get squished).

In what you’re doing it shouldn’t matter a lot, because the string moves from empty, to containing one character (your valid input range is less than two digits), then being read and emptied when the new line is typed.

In any case, I had originally planned for a different system - I just wasn’t sure how to implement it in C and Java (just a couple other languages). I’ve researched how to do that now and am transmitting single characters (ASCII codes). Turns out it just type casting.

After quite a bit of testing, I think my issue cannot be solved by optimization. The behavior of the strip while it isn’t functioning properly changes when I optimize, but for the worse, not better. I also found it quite interesting how mode 8 would randomly fix itself, but one led at a time! Very weird, since I should be sending a value to every LED each loop().

I think my issue could be related to this issue, and I’m going to try adding #define FASTLED_ALLOW_INTERRUPTS 0 to my code.

Sometimes when a microcontroller falls off the rails, the problem is that the program stack has collided with its heap.

If you do enough Googling you can find statements you can sprinkle into your code to track those locations (stack & heap) in the microcontroller memory as your program executes.

Alternatively, you can just try drastically reducing memory use (Only do half of what you originally planned … Don’t dive as deeply down into trees of subroutines …), and see what happens. If the problems go away you will have a learned something.

Blake

When we were debugging our LEDs we removed all of the FastLED demos from our displays because they have delays/timing inside of them. Suggest putting the most basic solid color changes in each of your cases to get the comms working first. For example, we had the “cylon” routine as our default which caused some sync/timing issues and delays. Once removed, testing became much more straight forward. Also, as I mentioned earlier in this thread, DIOs were very simple and removed the serial comms debugging.

Did I mention I removed the serial code and nothing changed, except for the fact that serial no longer worked?

It’s not the serial code. Really. It’s not.

All the FastLED demos have been removed, this is entirely my code. My code is designed to run asynchronously, ei without delays or timing.

You suggested I use basic colors to get comms working. Comms work fine. They have worked fine throughout ever iteration of this script. In fact, comms work so well, sending a value over them FIXES the script.

PLEASE don’t tell me serial doesn’t work, because it is NOT the problem. Timing is not the issue either. I proved that with case 8. For some reason, the for loop inside the main loop is breaking early on occasion.

If this is a problem with heap/stack collisions, I suppose I’ll have to give up my lookup table and move my logic to non-sinusoidal waves. If anyone knows how to get an approximate sin wave without actually using sin, that’d be helpful.