Go Down

Topic: faulty transmission/retrieval of bluetooth data  (Read 621 times) previous topic - next topic

Ziayakens

I have a phone app in react native sending data over bluetooth to light a digital led stip.
When I change the slider the value is added to an array. if the array is greater than 0, it will shift from the array and send the value every 20ms.
The issue is that even if I send only 10 values a second it seems to  process incorrectly and incorrect colors are displayed.

For testing purposes I have an array, 360 values, all are the same: 42. I am sending the values of the array one by one every 20ms. (even at 100ms interval the issue still occurs).

Code: [Select]
sendBatchValues = (deviceObject, writeService, writeChar) => {
for (let i = 0; i < 361; i++) {
this.dataToSend.push(45);
}
this.theInterval = setInterval(this.intervalCallBack, 20);
}
intervalCallBack = (value) => {
let currentSliderValueToSend = this.dataToSend.shift();
this.sendDataThroughService(currentSliderValueToSend, this.props.bluetooth.deviceObject, this.props.bluetooth.connectionData.writeServiceUUID, this.props.bluetooth.connectionData.writeCharacteristicUUID)
if (this.dataToSend.length == 0) {
clearInterval(this.theInterval);
}
}
sendDataThroughService = (value, deviceObject, writeService, writeChar) => {
value = Math.floor(value);
let hsaValue = this.hslToRgb(value/360);
let fullCommandRGB = "c:" + hsaValue[0] + "," + hsaValue[1] + "," + hsaValue[2] + ";";
let encodedString = btoa(fullCommandRGB);
if(Object.keys(deviceObject).length > 0) {
deviceObject.writeCharacteristicWithoutResponseForService(writeService, writeChar, encodedString);
}
}



and on the arduino I am processing the data by splitting on : , and ;
first value is the command, second third and forth and the red green and blue. I send those values to the function that changes the led strip.

Code: [Select]
void loop() {
  while (mySerial.available () > 0) {
    processIncomingByte (mySerial.read ()); 
  }
  if (_patternLoop != NULL) {
  //    Serial.println("pointer has been set - now looping a pattern");
    _patternLoop();
  }
}


const unsigned int MAX_INPUT = 50;

void processIncomingByte (const byte inByte) {
  static int parse_the_string = 0;
  static char commandString [MAX_INPUT];
  static char red [MAX_INPUT];
  static char green [MAX_INPUT];
  static char blue [MAX_INPUT];
  static unsigned int input_pos = 0;
  switch (parse_the_string) {
    case 0:
      switch (inByte) {
        case ':':
          commandString [input_pos] = '\0';  // terminating null byte
          input_pos = 0;
          parse_the_string ++;
          break;
        default:
          if (input_pos < (MAX_INPUT - 1))
            commandString [input_pos++] = inByte;
          break;
      }
      break;
    case 1:
      switch (inByte) {
        case ',':   // end of text
          red [input_pos] = '\0';  // terminating null byte
          input_pos = 0;
          parse_the_string ++;
          break;
        default:
          if (input_pos < (MAX_INPUT - 1))
            red [input_pos++] = inByte;
          break;
      }
      break;
    case 2:
      switch (inByte) {
        case ',':   // end of text
          green [input_pos] = '\0';  // terminating null byte
          input_pos = 0;
          parse_the_string ++;
          break;
        default:
          if (input_pos < (MAX_INPUT - 1))
            green [input_pos++] = inByte;
          break;
      }
      break;
    case 3:
      switch (inByte) {
        case ';':   // end of text
          blue [input_pos] = '\0';  // terminating null byte
          // terminator reached! process input_line here ...
          process_data (commandString, red, green, blue);
          input_pos = 0;
          parse_the_string = 0;
          break;
        case '\r':   // discard carriage return
          break;
        default:
          if (input_pos < (MAX_INPUT - 1))
            blue [input_pos++] = inByte;
          break;
      }  // end of switch
      break;
    default:
      break;
  }
}


void process_data (const char * commandString, const char * red, const char * green, const char * blue) {
  int redValue = atoi(red) - 255;
  int greenValue = atoi(green) - 255;
  int blueValue = atoi(blue) - 255;
  redValue = abs(redValue);
  greenValue = abs(greenValue);
  blueValue = abs(blueValue);
  manuallyChangeBladeColor(redValue, greenValue, blueValue);
}




I uploadeda video showing that, when sending the same value 360 times every 20ms, it glitches and shows the wrong value.
https://www.youtube.com/watch?v=QkHDk15BfPg&feature=youtu.be

What options do I have to improve this/ avoid the glitch.

Nick_Pyner


Robin2

Please post one or two examples of the messages that are sent to the Arduino.

And post the complete Arduino program.

...R
Serial Input Basics - simple reliable ways to receive data.
Two or three hours spent thinking and reading documentation solves most programming problems.

Ziayakens

first tab

Code: [Select]
#include <Wire.h>
#include <SparkFunSX1509.h>
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
#define PIN            6
#define NUMPIXELS      60
//144
#include <SoftwareSerial.h>
SoftwareSerial mySerial(7,8); // RX, TX

typedef void (*voidFuncPtr)();// Create a type to point to a funciton.
static voidFuncPtr  _patternLoop;

const byte SX1509_ADDRESS = 0x3E;  // SX1509 I2C address

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
SX1509 io;

byte leds[] = {8, 9, 10, 11, 12, 13, 14, 15, 7, 6, 5};


int redbrightlvl = 225;                  // starting color will be yellow
int greenbrightlvl = 255;
int bluebrightlvl = 0;
int currentGreenValue[150];
int currentBlueValue[150];
int currentRedValue[150];

int sideA = 29;
int sideB =30;
int LedsHaveBeenSet = 0;

void setup() {
  Serial.begin(57600);
  //setting up the hm10 blue chip
  mySerial.begin(57600); //required when using the hm-10 with an arduino nano
  mySerial.listen();
  //setting up the i/o expander for the 3 led strips
  if (!io.begin(SX1509_ADDRESS)) {
    while (1) ; // If we fail to communicate, loop forever.
  }
  //setting led colors of each strip to off
  for (int indx = 1; indx < 16; indx++) {
    io.pinMode(indx, ANALOG_OUTPUT);
    io.analogWrite(indx, 255);
  }
  //setting up digital led strip
  pixels.begin();
  setBladeBrightness(15);
  for (int i = 0; i < 60; i++) {
    pixels.setPixelColor(i, pixels.Color(0, 0, 0));
  }
  pixels.show();
  //starting with the "ult" pattern for the led strip
  setupULT();
}

void loop() {
  while (mySerial.available () > 0) {
    processIncomingByte (mySerial.read ());  
  }
  if (_patternLoop != NULL) {
    //continue updating the digital led strip
    _patternLoop();
  }
}


void setPointer(voidFuncPtr loopFunc) {
    _patternLoop =  loopFunc;
}

void setBladeBrightness(int brightLevel) {
  pixels.setBrightness(brightLevel);
}



const unsigned int MAX_INPUT = 50;
//process incoming data from the bluetooth chipp
void processIncomingByte (const byte inByte) {
  static int parse_the_string = 0;
  static char commandString [MAX_INPUT];
  static char red [MAX_INPUT];
  static char green [MAX_INPUT];
  static char blue [MAX_INPUT];
  static unsigned int input_pos = 0;
  switch (parse_the_string) {
    case 0:
      switch (inByte) {
        case ':':
          commandString [input_pos] = '\0';  // terminating null byte
          input_pos = 0;
          parse_the_string ++;
          break;
        default:
          if (input_pos < (MAX_INPUT - 1))
            commandString [input_pos++] = inByte;
          break;
      }
      break;
    case 1:
      switch (inByte) {
        case ',':   // end of text
          red [input_pos] = '\0';  // terminating null byte
          input_pos = 0;
          parse_the_string ++;
          break;
        default:
          if (input_pos < (MAX_INPUT - 1))
            red [input_pos++] = inByte;
          break;
      }
      break;
    case 2:
      switch (inByte) {
        case ',':   // end of text
          green [input_pos] = '\0';  // terminating null byte
          input_pos = 0;
          parse_the_string ++;
          break;
        default:
          if (input_pos < (MAX_INPUT - 1))
            green [input_pos++] = inByte;
          break;
      }
      break;
    case 3:
      switch (inByte) {
        case ';':   // end of text
          blue [input_pos] = '\0';  // terminating null byte
          // terminator reached! process input_line here ...
          process_data (commandString, red, green, blue);
          input_pos = 0;
          parse_the_string = 0;
          break;
        case '\r':   // discard carriage return
          break;
        default:
          if (input_pos < (MAX_INPUT - 1))
            blue [input_pos++] = inByte;
          break;
      }  // end of switch
      break;
    default:
      break;
  }
}


void process_data (const char * commandString, const char * red, const char * green, const char * blue) {
  int redValue = atoi(red) - 255;
  int greenValue = atoi(green) - 255;
  int blueValue = atoi(blue) - 255;
  redValue = abs(redValue);
  greenValue = abs(greenValue);
  blueValue = abs(blueValue);
  Serial.println("value ->");
  Serial.print("red: ");
  Serial.println(redValue);
  Serial.print("green: ");
  Serial.println(greenValue);
  Serial.print("blue: ");
  Serial.println(blueValue);
  manuallyChangeBladeColor(redValue, greenValue, blueValue);
}



Code: [Select]
int delayval = 10; // delay for half a second

int transition = 1;
bool runULT = false;

void manuallyChangeBladeColor(int red, int green, int blue) {
  Serial.println("manually changing");
  redbrightlvl = red;                  // starting color will be yellow
  greenbrightlvl = green;
  bluebrightlvl = blue;
  setPointer(loopULT);
  runULT = false;
}

void setupULT() {
  redbrightlvl = 225;                  // starting color will be yellow
  greenbrightlvl = 255;
  bluebrightlvl = 0;
  transition = 1;
  setPointer(loopULT);
  runULT = true;
}


void loopULT() {
  for(int i=LedsHaveBeenSet; i>=0;i--){
    //the pattern starts in the middle of the strip, shifting the color down the left and right side of the strip
    if(i==0){
      currentGreenValue[sideA] = greenbrightlvl;
      currentRedValue[sideA] = redbrightlvl;
      currentBlueValue[sideA] = bluebrightlvl;
      
      currentGreenValue[sideB] = greenbrightlvl;
      currentRedValue[sideB] = redbrightlvl;
      currentBlueValue[sideB] = bluebrightlvl;  
    }
    else{
      currentGreenValue[sideA - i] = currentGreenValue[sideA - i + 1];
      currentBlueValue[sideA - i] = currentBlueValue[sideA - i + 1];
      currentRedValue[sideA - i] = currentRedValue[sideA - i + 1];

      currentGreenValue[sideB + i] = currentGreenValue[sideB + i - 1];
      currentBlueValue[sideB + i] = currentBlueValue[sideB + i - 1];
      currentRedValue[sideB + i] = currentRedValue[sideB + i - 1];
    }
  }
  if(LedsHaveBeenSet < 29){
    LedsHaveBeenSet++;
  }
  for(int k=0; k <= LedsHaveBeenSet; k++){
    pixels.setPixelColor(sideA -k, pixels.Color(currentRedValue[sideA -k], currentGreenValue[sideA -k], currentBlueValue[sideA -k]));
    pixels.setPixelColor(sideB +k, pixels.Color(currentRedValue[sideB +k], currentGreenValue[sideB +k], currentBlueValue[sideB +k]));
    
  }
  pixels.show();
  delay(20);


  //if running the ULT pattern this automatically updates the color, other wise it will use  the color set via manuallyChangeBladeColor()
  if (runULT) {
    if (transition == 1) {
      yellowtogreen();
    }
    else if (transition == 2) {
      greentoblue();
    }
    else if (transition == 3) {
      bluetogreen();
    }
    else if (transition == 4) {
      greentoyellow();
    }
  }
}


void yellowtogreen(){
  if (redbrightlvl <= 11) {
    redbrightlvl = 0;
    transition = 2;
  } else {
    redbrightlvl -= 10;  
  }
}

void greentoblue(){
  if (greenbrightlvl <= 11) {
    greenbrightlvl = 0;
  } else {
    greenbrightlvl -= 10;
  }
  if (bluebrightlvl >= 244) {
    bluebrightlvl = 255;
  } else {
    bluebrightlvl += 10;
  }
  
  
  if (bluebrightlvl == 255 && greenbrightlvl == 0) {
    transition = 3;
  }
}

void bluetogreen(){
  
  if (greenbrightlvl >= 244) {
    greenbrightlvl = 255;
  } else {
    greenbrightlvl += 10;
  }
  if (bluebrightlvl <= 11) {
    bluebrightlvl = 0;
  } else {
    bluebrightlvl -= 10;
  }
  if (greenbrightlvl == 255 && bluebrightlvl == 0) {
    transition = 4;
//    Serial.println("GREEN -> red green blue");
//    Serial.println(redbrightlvl);
//    Serial.println(greenbrightlvl);
//    Serial.println(bluebrightlvl);
  }
}

void greentoyellow(){
  if (redbrightlvl >= 244) {
    redbrightlvl = 255;
    transition = 1;
//    Serial.println("YELLOW -> red green blue");
//    Serial.println(redbrightlvl);
//    Serial.println(greenbrightlvl);
//    Serial.println(bluebrightlvl);
  } else {
    redbrightlvl += 10;
  }
}



Ziayakens

When I send the same value (45) many times this is what is printed to the monitor:

Code: [Select]

value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 253 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 253 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 255 blue: 64
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 64
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 253 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 255 blue: 64
value ->
red: 0 green: 64 blue: 255



Robin2

first tab
I don't understand?

This seems to be a complex program with function pointers. Can you produce a short program that illustrates the problem?

In Reply #4 you say
Quote
When I send the same value (45) many times
Does that mean that you literally send the characters ( 4 5 ) with no linefeed for carriage return?

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

PaulS

Code: [Select]
      switch (inByte) {
        case ':':
          commandString [input_pos] = '\0';  // terminating null byte
          input_pos = 0;
          parse_the_string ++;
          break;
        default:
          if (input_pos < (MAX_INPUT - 1))
            commandString [input_pos++] = inByte;
          break;
      }

A switch statement is appropriate when you have more than 2 cases.

Code: [Select]
  static char commandString [MAX_INPUT];
  static char red [MAX_INPUT];
  static char green [MAX_INPUT];
  static char blue [MAX_INPUT];

This set of arrays does not mesh with you sending "45".
The art of getting good answers lies in asking good questions.

Ziayakens

45 is the H value is a hls color. On the javascript side on the phone app. it converts 45 to rgb and constructs the string "c:255,191,0;" base64 encodes it, and sends it.
I have
Code: [Select]
  static char commandString [MAX_INPUT];
  static char red [MAX_INPUT];
  static char green [MAX_INPUT];
  static char blue [MAX_INPUT];


and the switch case statement because it breaks apart the incoming message on : , and ;
using ; as the identifier to send the values off where "c" will eventually be used to identify which function to send the color to.

I am guessing the switch case that parses the data could be refactored but I had found someone elses example for parsing incoming serial data and modified it a bit to handle the format of my data.

I might have taken it too literally when you asked for complete code. Would you like me to make a new sketch containing only the code in question and repost the sketch?

PaulS

Quote
base64 encodes it, and sends it.
So, what is being sent is NOT "c:255,191,0;", but you assume, on the receiver, that it is. I'm not understanding why.

Did I somehow miss the part where you base64 decode the text coming in one serial port and send it out to the serial port you are reading from in the code above?
The art of getting good answers lies in asking good questions.

Ziayakens

#9
Nov 20, 2018, 06:05 pm Last Edit: Nov 20, 2018, 06:08 pm by Ziayakens
I am using a third party package with react native  to access bluetooth capabilities within the phone app, which if i recall correctly, needed to base64 encode the string before sending it.

Then I am using the hm10 with software serial. I am not super experienced with managing serial data, but I thought  was on the right path.
When processing the data with processIncomingByte, despite sending the string as base64 encoded, I am able to parse the characters correctly. It just starts to breakdown when I send data too quickly.

You did not miss any decoding on the arduino side. I'm not clear how, but when I assume I am receiving the string (not base64 encoded) and parse each byte with that assumption, saving in the char arrays, it seems to match the assumption and get parsed as expected.

I am willing to attempt this process in a different manner if you believe I am doing something incorrectly and I can post the results.  Should I try everything the same, but send the string without base64 encoding?


PaulS

Quote
Should I try everything the same, but send the string without base64 encoding?
The string being sent, if you can read it, is NOT base64 encoded. Whether that happens because the phone app decodes it before sending, or for some other reason, I do not know.

With all your arrays, how much SRAM are you using? Do the arrays NEED to be that big?

What I would do is comment out all the code that USES the data, and just print the values parsed. Send the data as fast as possible. If that data all gets through, then it is the process of using the data that is causing problems. If not, then it is the process of sending or reading the data that is causing problems.

When we know which problem you are trying to solve, we can solve it faster.
The art of getting good answers lies in asking good questions.

Ziayakens

#11
Nov 20, 2018, 07:34 pm Last Edit: Nov 20, 2018, 07:46 pm by Ziayakens
I commented out the
Code: [Select]
//manuallyChangeBladeColor(redValue, greenValue, blueValue);

so that it only parses the data and prints to the console.

Code: [Select]
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 253 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 253 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 64 blue: 255
value ->
red: 0 green: 19000 blue: 64


it seems to mess up about 2-10% of the time.

I supposed the r,g,b would not be more than 3 characters and I could limit the command to no more than 10 characters

PaulS

Quote
I supposed the r,g,b would not be more than 3 characters and I could limit the command to no more than 10 characters
Your string looks, at max, like "c:rrr,ggg,bbb;". Looks more like 14 characters plus a terminating NULL.

Again, you are doing more than just reading the data. Just read, and print the strings. Do NOT convert to integers.

You want to pick up the speed of Serial. It does not have to match the speed of the software serial instance, which is running pretty fast, for the volume of data you are sending.

Using a board with more than one hardware serial port would be a better idea.
The art of getting good answers lies in asking good questions.

Robin2

45 is the H value is a hls color. On the javascript side on the phone app. it converts 45 to rgb and constructs the string "c:255,191,0;" base64 encodes it, and sends it.
Make your Arduino program print out exactly what it receives before it attempts to parse it. Then post some examples of what it receives.

Telling us earlier that you "send the same value (45) many times" was not much help.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

Ziayakens

sorry >_<
I brought  it up to
Code: [Select]
Serial.begin(115200);

and have

Code: [Select]
void loop() {
  while (mySerial.available () > 0) {
    Serial.print(mySerial.read());
  }
  Serial.println("");
}


which gives me

Code: [Select]
995850535344495749444859
 
995850535344495749444859995850535344495749444859
995850535344
49
995850535344495749444859
 
995850535344495749444859
 
995850535344495749444859
995850535344495749444859
 
995850535344495749444859
 
995850535344495749444859
995850
53995850535344495749444859
995850535344495749444859
 
995850535344495749444859
 
995859
995850535344495749444859
 
 
 
995850535344495749444859995850535344495749444859995850535344495749444859
995850535344495749444859
 
995850535344495749444859
 
995850535344495749444859
9958505353444957
4944
995850535344495749444859
 
995850535344495749444859
 
99495749444859
99585053534449574944485999585053
53
995850535344495749444859
 
995850535344495749444859
995850535344495749444859
 
995850535344495749444859
 
995850535344495749444859
995850
53
995850535344495749444859
 
995850535344495749444859
 
995850535344495749444859
995850535344495749444859
9949444859
995850535344495749444859
 
995850535344495749444859
9958505353444957494448
59
995850535344495749444859
 
995850535344495749444859
 
9949444859
995850535344495749444859
 
995850535344495749444859995850535344495749444859
 
 
99585053534449
5750535344495749444859
995850535344495749444859
 
995850535344495749444859
9958505353
4449
995850535344495749444859
 
995850535344495749444859
 
99535344495749444859
995850535344495749444859
995859
995850535344495749444859
 
995850535344495749444859
995850535344495749444859
 
995850535344495749444859
 
995850535344495749444859
 
99444859
995850535344495749444859
 
995850535344495749444859
 
995850535344495749444859995850535344495749444859
995850535344495749444859
 
995850535344495749444859
 
995850535344495749444859
9958505353444957
49
995850535344495749444859
 
995850535344495749444859
 
9944495749444859
995850535344495749444859
 
995850535344495749444859
 
995850535344495749444859
995850535344495749444859

Go Up