Delay in processing data sent to Arduino using HC-06 from Android app

I have built a Mecanum wheel car using an Arduino Mega 2560, a motor shield, and an HC-06 to receive data from the app. The system is all working except that there is a noticeable delay between pressing or releasing the button on the app and the response of the car motor. If I use the Serial Bluetooth Terminal to send the code (a single integer from 0 to 18) the response is immediate. If I use the app I created, there is a delay in execution.

It is a simple program, both on the Arduino and in AI2. I'm new to AI2 so I'm not sure if I'm missing something or if this is just the nature of Bluetooth communications. I expect I'm missing something in the AI2 code since it works fine using the Terminal.

I'm not including the Arduino sketch (although I'd be glad to if anyone wants to look at it) or the wiring diagram because it doesn't seem to me to be related to the issue. I'm using Serial1 on the Arduino to connect the HC-06. I did try it with an HC-05 and I get the same results.

I did search the forum to see If there was a similar issue but couldn't find anything that directly addresses this issue. If I missed something, please let me know.

Thanks for any assistance you can provide.

These are the blocks for the app:

Include it.

I suspect a timing loop.

#include <AFMotor.h>
AF_DCMotor motor1(1);  //define motor1 BACK_LEFT_MOTOR
AF_DCMotor motor2(2);  //define motor2 BACK_RIGHT_MOTOR
AF_DCMotor motor3(3);  //define motor3 FRONT_RIGHT_MOTOR
AF_DCMotor motor4(4);  //define motor4 FRONT_LEFT_MOTOR


#define CAR_STOP 0
#define CAR_STRAIGHT_FORWARD 1
#define CAR_STRAIGHT_BACKWARD 2
#define CAR_SIDEWAYS_LEFT 3
#define CAR_SIDEWAYS_RIGHT 4
#define CAR_DIAGONAL_RR 5
#define CAR_DIAGONAL_RF 6
#define CAR_DIAGONAL_LR 7
#define CAR_DIAGONAL_LF 8
#define CAR_ROTATE_COUNTERCLOCKWISE 9
#define CAR_ROTATE_CLOCKWISE 10
#define CAR_PIVOT_LEFT_FORWARD 11
#define CAR_PIVOT_LEFT_BACKWARD 12
#define CAR_PIVOT_RIGHT_FORWARD 13
#define CAR_PIVOT_RIGHT_BACKWARD 14
#define CAR_PIVOT_SIDEWAYS_FRONT_LEFT 15
#define CAR_PIVOT_SIDEWAYS_FRONT_RIGHT 16
#define CAR_PIVOT_SIDEWAYS_REAR_LEFT 17
#define CAR_PIVOT_SIDEWAYS_REAR_RIGHT 18

#define BACK_RIGHT_MOTOR 0
#define BACK_LEFT_MOTOR 1
#define FRONT_RIGHT_MOTOR 2
#define FRONT_LEFT_MOTOR 3

#define motorSpeed 200

int cmdCode = 0;

void setup() {
  //Set initial speed of the motor
  motor1.setSpeed(motorSpeed);
  motor2.setSpeed(motorSpeed);
  motor3.setSpeed(motorSpeed);
  motor4.setSpeed(motorSpeed);
  Serial1.begin(9600);
}

void loop() {
  while (Serial1.available() == 0) {
    // Wait for input
  }
  if (Serial1.available() > 0) {
    cmdCode = Serial1.parseInt();
    processCarMovement(cmdCode);
  }
}

void processCarMovement(int inputValue) {
  switch (inputValue) {
    case CAR_STRAIGHT_FORWARD:
      motor1.run(FORWARD);
      motor2.run(FORWARD);
      motor3.run(FORWARD);
      motor4.run(FORWARD);
      break;

    case CAR_STRAIGHT_BACKWARD:
      motor1.run(BACKWARD);
      motor2.run(BACKWARD);
      motor3.run(BACKWARD);
      motor4.run(BACKWARD);
      break;

    case CAR_SIDEWAYS_LEFT:
      motor3.run(FORWARD);
      motor2.run(BACKWARD);
      motor4.run(BACKWARD);
      motor1.run(FORWARD);
      break;

    case CAR_SIDEWAYS_RIGHT:
      motor3.run(BACKWARD);
      motor2.run(FORWARD);
      motor4.run(FORWARD);
      motor1.run(BACKWARD);
      break;

    case CAR_DIAGONAL_RR:
      motor3.run(FORWARD);
      motor2.run(RELEASE);
      motor4.run(RELEASE);
      motor1.run(FORWARD);
      break;

    case CAR_DIAGONAL_RF:
      motor3.run(RELEASE);
      motor2.run(FORWARD);
      motor4.run(FORWARD);
      motor1.run(RELEASE);
      break;

    case CAR_DIAGONAL_LR:
      motor3.run(RELEASE);
      motor2.run(BACKWARD);
      motor4.run(BACKWARD);
      motor1.run(RELEASE);
      break;

    case CAR_DIAGONAL_LF:
      motor3.run(BACKWARD);
      motor2.run(RELEASE);
      motor4.run(RELEASE);
      motor1.run(BACKWARD);
      break;

    case CAR_ROTATE_COUNTERCLOCKWISE:
      motor3.run(FORWARD);
      motor2.run(FORWARD);
      motor4.run(BACKWARD);
      motor1.run(BACKWARD);
      break;

    case CAR_ROTATE_CLOCKWISE:
      motor3.run(BACKWARD);
      motor2.run(BACKWARD);
      motor4.run(FORWARD);
      motor1.run(FORWARD);
      break;

    case CAR_PIVOT_LEFT_FORWARD:
      motor3.run(FORWARD);
      motor2.run(FORWARD);
      break;

    case CAR_PIVOT_LEFT_BACKWARD:
      motor3.run(BACKWARD);
      motor2.run(BACKWARD);
      break;

    case CAR_PIVOT_RIGHT_FORWARD:
      motor4.run(FORWARD);
      motor1.run(FORWARD);
      break;

    case CAR_PIVOT_RIGHT_BACKWARD:
      motor4.run(BACKWARD);
      motor1.run(BACKWARD);
      break;


    case CAR_PIVOT_SIDEWAYS_FRONT_LEFT:
      motor3.run(FORWARD);
      motor4.run(BACKWARD);
      break;

    case CAR_PIVOT_SIDEWAYS_FRONT_RIGHT:
      motor3.run(BACKWARD);
      motor4.run(FORWARD);
      break;

    case CAR_PIVOT_SIDEWAYS_REAR_LEFT:
      motor2.run(BACKWARD);
      motor1.run(FORWARD);
      break;

    case CAR_PIVOT_SIDEWAYS_REAR_RIGHT:
      motor2.run(FORWARD);
      motor1.run(BACKWARD);
      break;

    case CAR_STOP:
      motor1.run(RELEASE);
      motor2.run(RELEASE);
      motor3.run(RELEASE);
      motor4.run(RELEASE);
      break;

    default:
      motor1.run(RELEASE);
      motor2.run(RELEASE);
      motor3.run(RELEASE);
      motor4.run(RELEASE);
      break;
  }
}

Okay, so it's not that easy.

But you are expecting to receive numbers as text in the sketch from the Bluetooth stream.

In the AI2 app, you just send strings of digits.

How does the AI2 Bluetooth component know to immediately send the text, rather than to save it up to save on bandwidth?

How does the sketch know that the AI2 app has sent a complete message, and should it wait for more digits to arrive?

We are venturing into the realm of message Delimiters.

How does the Arduino know its incoming message is complete?

Thanks for the explanation - I think I understand the problem but not how to solve it. That's the problem with following random YouTube videos. I was just trying to implement an app based on that source. I'll need to work through some of the AI2 tutorials to understand the correct way to do what I want.

I just assumed that my sketch was good because in testing with the serial monitor and then the terminal app, I was getting the results I was expecting.

Thanks for not spoon-feeding the solution to me but pointing me in the right direction. I really do appreciate that.

I'm trying to get to the FAQ section but it redirects to a Google group that either doesn't exist or I don't have access to.

Dear @tjblair1951 may I add something to what @abg as already said.
Arduino side:
I suggest you to don't use the serial1.parseint(), but rather the simple Serial1.read().
The parseint() waits until a non valid int is received or until a timeout elapses (to be set with an appropriate instruction).
Since you send text (the characters '1', '2', etc.) each one is terminated by a CRLF pair (Carriage Return Line Feed ; in hex 0x0D, 0x0A) what you receive on the Mega is in hex 310D0A. Therefore what you receive are characters and you have to convert them in integers.

Your loop should look like:

void loop() 
{
String cmdChar = ""';                  //  initializes the input buffer to empty 
while (!Serial1.available() ;         // waits for input from BT
 while  (Serial1.available() > 0)
 {
     cmdChar += Serial1.read();
 }                                                 // no more characters on BT
    if ( (cmdCode = cmdChar.toint()) !=0) processCarMovement(cmdCode);
}                                                 // end loop

On app side:
you don't need to wait for any button to touch up and transmit a 0 to close the command. Touch down doesn't repeat the transmission until the button is pressed. It just transmits only once. therefore I would rather have used another type of event, like the "click" to transmit the command. Then all the touch-up column can be avoided: you just transmit the command and that's all (no need to transmit the zeroes).

I hope I've been clear, if not, please do not hesitate to ask more. :hugs:

Which FAQ?

What link to a group you can't access?

Thank you for your input. The Touch Down and Up are used because the desired action is that the car will start moving when the button s pressed, and keep moving as long as the button stays down. It should stop when the button is released. The 0 is the stop command.

perhaps the old forum,

i bet their account is managed to not open google groups?

I figured out a solution and it turned out to be simple. The question you asked "How does the AI2 Bluetooth component know to immediately send the text, rather than to save it up to save on bandwidth?" gave me the key to solving my code problem. I hadn't realized that the app might buffer data before sending. I added a Carriage Return \r to each Send Text block and now the app/car interface works as I had wanted it to. Here are the revised blocks:

1 Like

Thanks for checking that out!
I honestly did not know the answer.

(added to FAQ)

I also found an error in my Arduino sketch - I had the motor direction for a couple of the diagonal movements wrong. In case anyone is interested, here is the corrected sketch to go along with the blocks in the app:

#include <AFMotor.h>
AF_DCMotor motor1(1);  //define motor1 BACK_LEFT_MOTOR
AF_DCMotor motor2(2);  //define motor2 BACK_RIGHT_MOTOR
AF_DCMotor motor3(3);  //define motor3 FRONT_RIGHT_MOTOR
AF_DCMotor motor4(4);  //define motor4 FRONT_LEFT_MOTOR


#define CAR_STOP 0
#define CAR_STRAIGHT_FORWARD 1
#define CAR_STRAIGHT_BACKWARD 2
#define CAR_SIDEWAYS_LEFT 3
#define CAR_SIDEWAYS_RIGHT 4
#define CAR_DIAGONAL_RR 5
#define CAR_DIAGONAL_RF 6
#define CAR_DIAGONAL_LR 7
#define CAR_DIAGONAL_LF 8
#define CAR_ROTATE_COUNTERCLOCKWISE 9
#define CAR_ROTATE_CLOCKWISE 10
#define CAR_PIVOT_LEFT_FORWARD 11
#define CAR_PIVOT_LEFT_BACKWARD 12
#define CAR_PIVOT_RIGHT_FORWARD 13
#define CAR_PIVOT_RIGHT_BACKWARD 14
#define CAR_PIVOT_SIDEWAYS_FRONT_LEFT 15
#define CAR_PIVOT_SIDEWAYS_FRONT_RIGHT 16
#define CAR_PIVOT_SIDEWAYS_REAR_LEFT 17
#define CAR_PIVOT_SIDEWAYS_REAR_RIGHT 18

#define BACK_RIGHT_MOTOR 0
#define BACK_LEFT_MOTOR 1
#define FRONT_RIGHT_MOTOR 2
#define FRONT_LEFT_MOTOR 3

#define motorSpeed 200

int cmdCode = 0;

void setup() {
  //Set initial speed of the motor
  motor1.setSpeed(motorSpeed);
  motor2.setSpeed(motorSpeed);
  motor3.setSpeed(motorSpeed);
  motor4.setSpeed(motorSpeed);
  Serial1.begin(9600);
}

void loop() {
  while (Serial1.available() == 0) {
    // Wait for input
  }
  if (Serial1.available() > 0) {
    cmdCode = Serial1.parseInt();
    processCarMovement(cmdCode);
  }
}

void processCarMovement(int inputValue) {
  switch (inputValue) {
    case CAR_STRAIGHT_FORWARD:
      motor1.run(FORWARD);
      motor2.run(FORWARD);
      motor3.run(FORWARD);
      motor4.run(FORWARD);
      break;

    case CAR_STRAIGHT_BACKWARD:
      motor1.run(BACKWARD);
      motor2.run(BACKWARD);
      motor3.run(BACKWARD);
      motor4.run(BACKWARD);
      break;

    case CAR_SIDEWAYS_LEFT:
      motor3.run(FORWARD);
      motor2.run(BACKWARD);
      motor4.run(BACKWARD);
      motor1.run(FORWARD);
      break;

    case CAR_SIDEWAYS_RIGHT:
      motor3.run(BACKWARD);
      motor2.run(FORWARD);
      motor4.run(FORWARD);
      motor1.run(BACKWARD);
      break;

    case CAR_DIAGONAL_RR:
      motor3.run(BACKWARD);
      motor2.run(RELEASE);
      motor4.run(RELEASE);
      motor1.run(BACKWARD);
      break;

    case CAR_DIAGONAL_RF:
      motor3.run(RELEASE);
      motor2.run(FORWARD);
      motor4.run(FORWARD);
      motor1.run(RELEASE);
      break;

    case CAR_DIAGONAL_LR:
      motor3.run(RELEASE);
      motor2.run(BACKWARD);
      motor4.run(BACKWARD);
      motor1.run(RELEASE);
      break;

    case CAR_DIAGONAL_LF:
      motor3.run(FORWARD);
      motor2.run(RELEASE);
      motor4.run(RELEASE);
      motor1.run(FORWARD);
      break;

    case CAR_ROTATE_COUNTERCLOCKWISE:
      motor3.run(FORWARD);
      motor2.run(FORWARD);
      motor4.run(BACKWARD);
      motor1.run(BACKWARD);
      break;

    case CAR_ROTATE_CLOCKWISE:
      motor3.run(BACKWARD);
      motor2.run(BACKWARD);
      motor4.run(FORWARD);
      motor1.run(FORWARD);
      break;

    case CAR_PIVOT_LEFT_FORWARD:
      motor3.run(FORWARD);
      motor2.run(FORWARD);
      break;

    case CAR_PIVOT_LEFT_BACKWARD:
      motor3.run(BACKWARD);
      motor2.run(BACKWARD);
      break;

    case CAR_PIVOT_RIGHT_FORWARD:
      motor4.run(FORWARD);
      motor1.run(FORWARD);
      break;

    case CAR_PIVOT_RIGHT_BACKWARD:
      motor4.run(BACKWARD);
      motor1.run(BACKWARD);
      break;


    case CAR_PIVOT_SIDEWAYS_FRONT_LEFT:
      motor3.run(FORWARD);
      motor4.run(BACKWARD);
      break;

    case CAR_PIVOT_SIDEWAYS_FRONT_RIGHT:
      motor3.run(BACKWARD);
      motor4.run(FORWARD);
      break;

    case CAR_PIVOT_SIDEWAYS_REAR_LEFT:
      motor2.run(BACKWARD);
      motor1.run(FORWARD);
      break;

    case CAR_PIVOT_SIDEWAYS_REAR_RIGHT:
      motor2.run(FORWARD);
      motor1.run(BACKWARD);
      break;

    case CAR_STOP:
      motor1.run(RELEASE);
      motor2.run(RELEASE);
      motor3.run(RELEASE);
      motor4.run(RELEASE);
      break;

    default:
      motor1.run(RELEASE);
      motor2.run(RELEASE);
      motor3.run(RELEASE);
      motor4.run(RELEASE);
      break;
  }
}

Yep, I knew that what you wanted is a continuous movement as long as the down event is raised, but what stops the movement on your Arduino code is the up event, i.e. when it receives the zero, because the down event is not continuously generated (therefore it sends only once the relevant movement command).
Your sequence of buttons seem to implement a joystick behaviour. The following link shows how to do it:

I see that you continue to use the parseint() function. If it works for you, it's fine, but remember that it suffers of a timeout that, if too short can interrupt your receiving, if too long can introduce a lag in the commands handling.
Anyway thanks for having shared your solution, so also other users can benefit of that.
Rgds.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.