Pages: [1]   Go Down
Author Topic: AdaFruit_NeopPixel with programmable light strand = missing Serial characters  (Read 735 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 11
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Can anyone help me make this code more efficient?   This code uses a variable delay to sequence light strands at a specified speed (matches the speed of a conveyor belt).  The shorter the delay, the more frequent characters are missed when reading from / writing to the Serial port.  I am using the Arduino Mega and had the same issue with the Uno.

Am I missing something that insures all characters are passed?  Is there a buffer that can be configured?  I have tried this code using the serial monitor and a separate VB.NET project.  Both the same issue with dropped characters. 

For example, I send this.  The semi colon indicates the end of a character set.
         Lane:1 R:20 G:0 B:0;Lane:2 R:0 G:20 B:0;Lane:3 R:0 G:0 B:20;

The response:
        Set Lane:1 R:20 G:0 B:0;
        Set Lane:2 R:0 G:20 B:0;
        Set Lane:3 R:0 G:0 B:0;       <---Missing digit, it should say B:20;

This happens at random.  Sometimes it misses a single digit, sometimes an entire line.

Here is the code:

Code:
//  // Serial Input
//  // Lane:1 R:20 G:0 B:0;Lane:2 R:0 G:20 B:0;Lane:3 R:0 G:0 B:20;    (Pin 1 numeric, r, g, b 3 numeric)
//  // Delay:1000;  (delay between between moving lights in miliseconds)
//  // LightCount:300;  (total lights in a strand.  ie 300 lights = 15' strand)

#include <Adafruit_NeoPixel.h>
Adafruit_NeoPixel lane1 = Adafruit_NeoPixel(300, 2, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel lane2 = Adafruit_NeoPixel(300, 3, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel lane3 = Adafruit_NeoPixel(300, 4, NEO_GRB + NEO_KHZ800);


int lightcount = 300;  //initialize maximum number of lights.
int lightdelay = 300;  //initialize delay for light movement.

void setup() {
  Serial.begin(9600);
  Serial.println("Serial Light Sequencer 9.2");

  lane1.begin();
  lane1.show();  //Set all lights to off
  lane2.begin();
  lane2.show();  //Set all lights to off
  lane3.begin();
  lane3.show();  //Set all lights to off
}

void loop() {
  for (int i = lightcount; i >= 2 ; i--) {
    lane1.setPixelColor(i, lane1.getPixelColor(i - 1));
    lane1.setPixelColor(i - 1, 0);
    lane2.setPixelColor(i, lane2.getPixelColor(i - 1));
    lane2.setPixelColor(i - 1, 0);
    lane3.setPixelColor(i, lane3.getPixelColor(i - 1));
    lane3.setPixelColor(i - 1, 0);
  }
  lane1.show();
  lane2.show();
  lane3.show();
  delay(lightdelay);
}

void serialEvent() {
  GetSerial();
}

//Read Serial Data
void GetSerial () {
  byte lane, r, g, b;
  int length = Serial.available();
  //Serial.println(length);
  int i, loc, Delay, Count;
  char c;
  String readString, substring;
  //while (Serial.available() > 0) {
  for (i = 0; i < length; i++) {
    c =  Serial.read();
    if (c != ';') {
      readString += c;
    } else {
      break;
    }
  }
  readString.trim();
  if (readString.length() > 0 ) {
    //Check for Pin, R, G, B sequence
    loc = readString.indexOf("Lane:");
    if (loc != -1) {
      substring = readString.substring(loc + 5, loc + 7);
      lane = substring.toInt();
    } else {
      lane = 0;
    }
    if (lane > 0) {
      loc = readString.indexOf("R:");
      if (loc != -1) {
        substring = readString.substring(loc + 2, loc + 6);
        r = substring.toInt();
      } else {
        r = 0;
      }
      loc = readString.indexOf("G:");
      if (loc != -1) {
        substring = readString.substring(loc + 2, loc + 6);
        g = substring.toInt();
      } else {
        g = 0;
      }
      loc = readString.indexOf("B:");
      if (loc != -1) {
        substring = readString.substring(loc + 2, loc + 6);
        b = substring.toInt();
      } else {
        b = 0;
      }
      Serial.print ("Set Lane:");
      Serial.print (lane);
      Serial.print (" R:");
      Serial.print (r);
      Serial.print (" G:");
      Serial.print (g);
      Serial.print (" B:");
      Serial.print(b);
      Serial.println(";");
      switch (lane) {
        case 1:
          lane1.setPixelColor(1, r, g, b);
          break;
        case 2:
          lane2.setPixelColor(1, r, g, b);
          break;
        case 3:
          lane3.setPixelColor(1, r, g, b);
          break;       
      }
    }
    //Check Delay Number
    loc = readString.indexOf("Delay:");
    //Serial.println(loc);
    if (loc != -1) {
      substring = readString.substring(loc + 6, loc + 15);
      Delay = substring.toInt();
      //Serial.println(substring);
      if (delay > 0) {
        lightdelay = Delay;
        Serial.print ("Set Delay:");
        Serial.println (Delay);
      }
    }
    //Check light count
    loc = readString.indexOf("LightCount:");
    //Serial.println(loc);
    if (loc != -1) {
      substring = readString.substring(loc + 11, loc + 14);
      Count = substring.toInt();
      //Serial.println(substring);
      if (Count > 0) {
        lightcount = Count;
        Serial.print ("Set Light Count:");
        Serial.println (lightcount);
      }
    }
  }
}
Logged

West Yorkshire, UK
Offline Offline
Edison Member
*
Karma: 50
Posts: 1480
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

I would guess using String objects like that is so slow it can't keep up with 9600 baud. I would try using a normal character array type string to capture your incoming command string, then afterwards convert it to a String object for parsing. So declare a char array long enough to hold your longest possible command sequence (plus 1 for the null terminator) and read from Serial in a single command usingReadBytesUntil.

Paul
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 11
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I changed my code to use Serial.readBytesUntil().   Now, when I send data to the port, about half the time it receives unusual characters. 

Here is the code I am sending to the Serial port:   L;1;20;0;0

I sent the code twice using the Serial Monitor and here is what I received.  The first try, shows junk characters, the second worked. 

First try:
0
µÿ5€

Second Try:
20
0
0

Here is my code that reads and processes the Serial port:
Code:
//Read Serial Data
void GetSerial () {
  if (Serial.available()) {
    char *list[6];
    char buf[20] ;
    byte i;
    Serial.readBytesUntil('\n', buf, 20);
    Serial.flush();
    char *token = strtok(buf, ";");
    i = 0;
    list[i] = token;
    i++;
    while (token)
    {
      token =  strtok(NULL, ";"); // Use NULL as the 1st argument to keep parsing the same string
      list[i] = token;
      //Serial.println(token);
      i++;
    }
    char tmpproc;
    strncpy (&tmpproc, (list[0]), 1); //Copy Char* to Char * convert to INT for Switch comparison
    switch (tmpproc) {  //Check process
      case 'L':  //Set light
        switch (atoi(list[1])) {
          case 1:
            lane1.setPixelColor(1, byte(atoi(list[2])), byte(atoi(list[3])), byte(atoi(list[4])));  //(light1,r,g,b)
            break;
          case 2:
            lane2.setPixelColor(1, byte(atoi(list[2])), byte(atoi(list[3])), byte(atoi(list[4])));  //(light1,r,g,b)
            break;
          case 3:
            lane3.setPixelColor(1, byte(atoi(list[2])), byte(atoi(list[3])), byte(atoi(list[4])));  //(light1,r,g,b)
            break;
        }
        Serial.println ("LightSet");
        break;

      case 'D':  //Set Delay
        lightdelay = atoi(list[2]);
        Serial.println ("Delay Set");
        break;

      case 'C':  //Set Light Count
        lightcount = atoi(list[2]);
        Serial.println ("LightCountSet");
        break;
    }
    Serial.println(list[2]);
    Serial.println(list[3]);
    Serial.println(list[4]);
  }
}

Does anyone have any idea what I could be doing wrong?  I have the port set to the standard 9600.
Logged

West Yorkshire, UK
Offline Offline
Edison Member
*
Karma: 50
Posts: 1480
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hmm... there seems to be a similarity with this thread...
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 11
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

It sounds similar.  I think it is caused by the Adafruit_NeoPixel.  If I bypass the code for the lights,  the Serial port communication works fine.  I am not sure what else to try.
Logged

Offline Offline
Edison Member
*
Karma: 62
Posts: 1035
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Hello bishop0114

Have you tried experimenting with bit rates other than 9600? Both higher and lower?

And with the current bit rate, what happens if you remove the LED strips one at a time from the program, rather than all or nothing?

Regards

Ray
Logged

Hackscribble.  Writing about making things.
arduino@hackscribble.com | www.hackscribble.com

Offline Offline
Edison Member
*
Karma: 62
Posts: 1035
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Another thing to try is changing from the use of delay() in loop().  I believe that serialEvent() only gets called at the end of loop().  The delay() stops execution for the delay period, so my thinking is it reduces the opportunities for serialEvent() to be executed.

With the "blink without delay" approach, loop() becomes ...

Code:
void loop() {
    static unsigned long nextUpdate = millis();
    if (millis() > nextUpdate)
    {
        for (int i = lightcount; i >= 2 ; i--) {
            lane1.setPixelColor(i, lane1.getPixelColor(i - 1));
            lane1.setPixelColor(i - 1, 0);
            lane2.setPixelColor(i, lane2.getPixelColor(i - 1));
            lane2.setPixelColor(i - 1, 0);
            lane3.setPixelColor(i, lane3.getPixelColor(i - 1));
            lane3.setPixelColor(i - 1, 0);
        }
        lane1.show();
        lane2.show();
        lane3.show();
        nextUpdate += lightdelay;
    }
}

Logged

Hackscribble.  Writing about making things.
arduino@hackscribble.com | www.hackscribble.com

Offline Offline
Newbie
*
Karma: 0
Posts: 11
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I posted the same question on the ADAfruit site and from what I understand, when, Adafruit is sending data to the lights, it disables interrupts.  So while the interrupts are disabled, I wont receive data.  They suggest trying to setup a handshake.

https://forums.adafruit.com/viewtopic.php?f=25&t=54576
Logged

Pages: [1]   Go Up
Jump to: