HC.05 bluetooth data saturation problem App Inventor

Hello,
This is my first time here, I hope I am posting at the right place. I have searched this problem for a few weeks on internet but have not found anything like it

I am trying to build a very simple RC bluetooth car with an arduino nano, two dc motors, motor driver L9110, bluetooth HC-05 and an app created from App Inventor.

Everuthing works fine for the fist 1-2 minutes, after that for some unknow reason the serial input signal from the HC-05 gets "stock" and repeats the same value all the time no matter what the phone/app is sending. The only way to get it back to work is to turn off the phone bluetooth, turn it on and reconnect to the HC-05.

Here the copy of the code:

int lefA = 5;
int lefB = 6;
int rigA = 9;
int rigB = 10;
int vel1 = 255;
int state = 'a';

void setup() {
Serial.begin(9600);
pinMode(rigA, OUTPUT);
pinMode(rigB, OUTPUT);
pinMode(lefA, OUTPUT);
pinMode(lefB, OUTPUT);
}

void loop() {

if(Serial.available()>0){
state = Serial.read();
}

if(state=='a'){
analogWrite(rigA, 0);
analogWrite(rigB, 0);
analogWrite(lefA, 0);
analogWrite(lefB, 0);
Serial.println(state);
}
if(state=='b'){
analogWrite(rigA, vel1);
analogWrite(rigB, 0);
analogWrite(lefA, 0);
analogWrite(lefB, 0);
Serial.println(state);
}

if(state=='d'){
analogWrite(rigA, vel1);
analogWrite(rigB, 0);
analogWrite(lefA, vel1);
analogWrite(lefB, 0);
Serial.println(state);
}
if(state=='f'){
analogWrite(rigA, 0);
analogWrite(rigB, 0);
analogWrite(lefA, vel1);
analogWrite(lefB, 0);
Serial.println(state);
}
if(state=='h'){
analogWrite(rigA, 0);
analogWrite(rigB, vel1);
analogWrite(lefA, 0);
analogWrite(lefB, vel1);
Serial.println(state);
}

Thank you for your help

I think that you cause a feedback loop, by sending the received character back to Serial. Remove the Serial.println(), and it should work.

You cannot use Serial to communicate with the Serial Monitor (USB) and Bluetooth module at the same time.

Hi,

I only included the Serial.writeln() to debug the program and see the readings form the bluetooth, before it was not there and it gave the problem

Thanks

How do you know what the app is sending? Or in other words, are you sure your app is not stuck?

That is avery good question! and the root of the problem (I think)

Which I tried to solve it with the serial.print, but I do not know how to separate if the app is sending the same value and got stuck or if the arduino got stuck on the the last value received.

Is tehre a way to verify?

Thanks

I have written some BT apps using MIT App Invetor 2 before..

from reading.. sounds like its on the app side of things..

to be sure, remove the HC-05 module all together..

you should be able to control it using serial monitor..

does it display the same behavior? if not.. most likely on the apps side of things.

and yes you can for sure check what the app is sending..

its just sending serial data to your BT device.. and that in turn is just passing it on.

all incoming serial data can be displayed in the serial monitor as well... does it look like duplicated data?

Hi! Did you manage to solve the problem? I'm in the same situation... The last command which is sent by the android program is stucked on the arduino. It's always showing it just recieving the data all over again.
Thanks!

ZsoCza:
Hi! Did you manage to solve the problem? I'm in the same situation... The last command which is sent by the android program is stucked on the arduino. It's always showing it just recieving the data all over again.
Thanks!

Show your code (using code tags !). With the Arduino code that was posted in the opening post that will be the case as the received character is remembered.

sterretje:
Show your code (using code tags !). With the Arduino code that was posted in the opening post that will be the case as the received character is remembered.

My code:

char command;
String string;
#define forward 4
#define backward 5
#define left 6
#define right 7

 void setup()
 {
   Serial.begin(9600);
   pinMode(forward, OUTPUT);
   pinMode(backward, OUTPUT);
   pinMode(left, OUTPUT);
   pinMode(right, OUTPUT);
 }

 void loop()
 {
   if (Serial.available() > 0) 
   {string = "";}
   
   while(Serial.available() > 0)
   {
     command = ((byte)Serial.read());
     
     if(command == ':')
     {
       break;
     }
     
     else
     {
       string += command;
     }
     
     delay(1);
   }
   
if(string == "FO")
   {
     digitalWrite(forward, HIGH);
   delay(10);
   }
else {
   digitalWrite(forward, LOW);
}
   
if(string == "BO")
   {
     digitalWrite(backward, HIGH);
     delay(10);
   }
else {
   digitalWrite(backward, LOW);
}

if(string == "LO")
   {
     digitalWrite(left, HIGH);
     delay(10);
   }
else {
   digitalWrite(left, LOW);
}

if(string == "RO")
   {
     digitalWrite(right, HIGH);
     delay(10);
   }
else {
   digitalWrite(right, LOW);
}
}

I tried to play with the delay, but with no effort.

Your code will indeed get stuck and repeat the last command. Just check what your doing in loop().
First you check if data is available (and clear the string if that is the case) and next you read the data in the while().

So you send one command (and assuming it is valid; e.g. 'FO:') it will move the motor forward. Next there is no data available, so you don't clear the string and you don't add anything to it; as a result string still contains the last data and the motor will move again. You need to clear string once you have taken the action.

There is another weak point and that is that there is no guarantee in communication that all data is received in one go. It might very well be that you receive two bytes followed by one byte in which case your code will not do what you expect. The 1ms delay might ease the problem but what if it takes 2ms?

You can use the second example in Serial Input Basics - updated; just change the endmarker form '\n' to ':'. And rename showNewData() to e.g. processData() and place your motor control (if(string == ...) statements) in that function.

const byte numChars = 32;
char receivedChars[numChars];   // an array to store the received data
#define forward 4
#define backward 5
#define left 6
#define right 7

boolean newData = false;

void setup() {
    Serial.begin(9600);
    Serial.println("<Arduino is ready>");
    pinMode(forward, OUTPUT);
    pinMode(backward, OUTPUT);
    pinMode(left, OUTPUT);
    pinMode(right, OUTPUT);
}

void loop() {
    recvWithEndMarker();
    controlData();
}

void recvWithEndMarker() {
    static byte ndx = 0;
    char endMarker = ':';
    char rc;
    
    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (rc != endMarker) {
            receivedChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars) {
                ndx = numChars - 1;
            }
        }
        else {
            receivedChars[ndx] = '\0'; // terminate the string
            ndx = 0;
            newData = true;
        }
    }
}

void controlData() {
if(receivedChars == "FO")
    {
      Serial.println(receivedChars);
      digitalWrite(forward, HIGH);
      delay(10);
    }
else {
    digitalWrite(forward, LOW);
}
    
if(receivedChars == "BO")
    {
      digitalWrite(backward, HIGH);
      delay(10);
    }
else {
    digitalWrite(backward, LOW);
}

if(receivedChars == "LO")
    {
      digitalWrite(left, HIGH);
      delay(10);
    }
else {
    digitalWrite(left, LOW);
}

if(receivedChars == "RO")
    {
      digitalWrite(right, HIGH);
      delay(10);
    }
else {
    digitalWrite(right, LOW);
}
 }

First of all thank you for your help!
I did what you adviced, but now it seems that there is something with the the receivedChars…
It seems it is never equals somewhy with the control characters…
Do you have maybe some advice why could it be?

Sorry, forgot to tell you that you needed to use strcmp.

if (strcmp(receivedChars,"FO") == 0)
{
  // match
}
]/code]

sterretje:
Sorry, forgot to tell you that you needed to use strcmp.

if (strcmp(receivedChars,"FO") == 0)

{
  // match
}
]/code]

Like this?

void controlData() {
if(strcmp(receivedChars,"FO") == 0)
    {
      digitalWrite(forward, HIGH);
      delay(10);
    }
else {
    digitalWrite(forward, LOW);
}

Because like this it doesn't work :confused:

Please be more specific with regards to "it does not work".

Add debug prints in e.g. controlData() so you can see what is received. Also in controlData(), you might want to check if 'newData' equals true before taking action. And clearing 'newData' once you have performed the action implied by the 'command'.

I tried to print out what the program receive, but maybe I didn’t do it in the proper way.
In attachment I send a picture what its receiving, so when I push the forward button on the phone it just continuously send the FO command.

My code now looks like this:

const byte numChars = 32;
char receivedChars[numChars];
#define forward 4
#define backward 5
#define left 6
#define right 7

boolean newData = false;

void setup() {
    Serial.begin(9600);
    Serial.println("<Arduino is ready>");
    pinMode(forward, OUTPUT);
    pinMode(backward, OUTPUT);
    pinMode(left, OUTPUT);
    pinMode(right, OUTPUT);
}

void loop() {
    recvWithEndMarker();
    controlData();
}

void recvWithEndMarker() {
    static byte ndx = 0;
    char endMarker = ':';
    char rc;
    
    while (Serial.available() > 0 && newData == false) {
        rc = Serial.read();

        if (rc != endMarker) {
            receivedChars[ndx] = rc;
            ndx++;
            if (ndx >= numChars) {
                ndx = numChars - 1;
            }
        }
        else {
            receivedChars[ndx] = '\0'; // terminate the string
            ndx = 0;
            newData = true;
        }
    }
}

void controlData() {
    Serial.println(receivedChars);
if(strcmp(receivedChars,"FO") == 0)
    {
      digitalWrite(forward, HIGH);
      delay(10);
    }
else {
    digitalWrite(forward, LOW);
}
    
if(strcmp(receivedChars,"BO") == 0)
    {
      digitalWrite(backward, HIGH);
      delay(10);
    }
else {
    digitalWrite(backward, LOW);
}

if(receivedChars == "LO")
    {
      digitalWrite(left, HIGH);
      delay(10);
    }
else {
    digitalWrite(left, LOW);
}

if(receivedChars == "RO")
    {
      digitalWrite(right, HIGH);
      delay(10);
    }
else {
    digitalWrite(right, LOW);
}
 }

rec.JPG

See reply #13. In controlData you do not check if newData is true and you never set newData to false once your done processing the received data and as a result of those you will keep on processing the last received command.

It seems that with my friend we managed to correct the code to the right way as you suggested!
So again many thanks for your help! :slight_smile: