Serial comunication with HC-05 - Arduino UNO

I am new to the site and this is my first question. I'm going to try to describe my issue the best I can.

I got the following code for my project which consists basically of getting a car to have 2 driving mode, automatic and manual.

As far as I can tell, I got it all working except it's not. I got an HC-05 connected to my L293D motor shield (attached to an Arduino UNO), as well as 2 dc motors, an ultrasonic sensor HC-SR04 and a LED. The circuit part is not the problem, I’ve managed to connect it all and it's working (I tested the obstacle avoiding part by itself, before adding the mode selection code, so I know the motors and sensor do their job). I should also mention that I’m sending the information through the BT from an app I made in APP Inventor. The app is working fine, and I do receive the correct data in the Serial Monitor.

What’s puzzling me is, why can’t I get to assign the Serial.read(); value to my response variable (resp). I’m going to try to explain this a bit further. In my serial monitor I get the intended chars from the app buttons, however, my “resp” variable doesn’t seem to be getting any value from Serial.read(); for some reason, because when it gets to the switch statement, even though the char is printed on the monitor the cases don’t start, for instance, and I might be completely off here, once I get ‘1’ on the monitor I should also start getting the distance measurement printed in the monitor and it’s not.

For what I gather, I believe the issue is between the Serial.write() and the Serial.println()/.read(); since the serial.write() seems to be taking priority over all others, since setting this lines as comments don’t affect the writing in the monitor:

if(Serial.available()>0){
//resp = Serial.read();
//Serial.println(resp);

I’m out of ideas so, any help or guidance towards the right direction will be greatly appreciated.

I've attached an image of what I get on my serial monitor.

RetoFinal.ino (3.4 KB)

To get more people to look at your question you need to use Code Tags, these make it easier for others to try out your code and find possible errors. I've done it for you this time...

The OP's code:

//Incluir librerias para controlar motor shield y sensor ultrasonico.
#include <AFMotor.h>
#include <NewPing.h>
#include <SoftwareSerial.h>

//Definir constantes y variables.
#define TRIG_P A4 
#define ECHO_P A5
#define MAX_DIST 300
#define MAX_Vel 200
int led = A0;
int speedSet;
int iteraciones = 5;
float distancia, duracion;
char resp;

//Inicializar objetos del sensor y motores.
NewPing sonar(TRIG_P, ECHO_P, MAX_DIST); 
AF_DCMotor motorD(2); 
AF_DCMotor motorI(1);
SoftwareSerial BTSerial(A1, A2); // RX | TX

void setup() {
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  BTSerial.begin(9600);
}

void loop() {

  //Lee información del BT y la escribe en el monitor serial.
  if (BTSerial.available()){
    Serial.write(BTSerial.read());
    Serial.write('\n');
  }  

  delay(24); //Tiempo maximo que tarda en recibir una medición.

      /*Calcular la distancia frente al sensor utilizando la duración de la señal, 
      la cual mide ida y vuelva por lo cual se divide entre 2 
      y se multiplica por la velocidad del sonido (343 m/s).
      */
      
      duracion = sonar.ping_median(iteraciones);
      distancia = (duracion/2)*0.0343;

  if(Serial.available()>0){  
    resp = Serial.read();
    Serial.println(resp);
    
    switch(resp){

      case '1':

      delay(24); //Tiempo maximo que tarda en recibir una medición.

      /*Calcular la distancia frente al sensor utilizando la duración de la señal, 
      la cual mide ida y vuelva por lo cual se divide entre 2 
      y se multiplica por la velocidad del sonido (343 m/s).
      */
      
      duracion = sonar.ping_median(iteraciones);
      distancia = (duracion/2)*0.0343;
      
      Serial.print("Distancia: ");
      Serial.print(distancia);
      Serial.println(" cm"); 
      
      if(distancia!=0 && distancia<=20){
        digitalWrite(led,HIGH);
        ALTO();
        delay(100);
        REVERSA();
        delay(400);
        IZQUIERDA();
        delay(100);
      }else 
        digitalWrite(led,LOW);
        ADELANTE();
      break;
      
      case '2':
      ALTO();
        
        switch(resp){

          case 'A':
            ADELANTE();
          break;
          case 'R':
            REVERSA();
          break;
          case 'I':
            IZQUIERDA();
          break;
          case 'D':
            DERECHA();
          break;
          case 'O':
            ALTO();
          break;
        }
        break;
       }       
    }
 }


  // Inician metodos que definen las acciones del carro.
  
void ADELANTE(){
   motorD.run(FORWARD);      
   motorI.run(FORWARD);
    for (speedSet = 0; speedSet < MAX_Vel; speedSet +=2){
      motorD.setSpeed(speedSet + 20);
      motorI.setSpeed(speedSet - 20);
    }
  }

void REVERSA(){
   motorD.run(BACKWARD);      
   motorI.run(BACKWARD);  
    for (speedSet = 0; speedSet < MAX_Vel; speedSet +=2){
      motorD.setSpeed(speedSet + 20);
      motorI.setSpeed(speedSet - 20);
    }
  }  

void DERECHA() {
   motorD.run(RELEASE);
   motorI.run(FORWARD);     
   delay(300);
   motorD.run(FORWARD);      
   motorI.run(FORWARD);      
  } 
 
void IZQUIERDA() {
   motorD.run(FORWARD);     
   motorI.run(RELEASE);     
   delay(300);
   motorD.run(FORWARD);     
   motorI.run(FORWARD);
  }  

void ALTO(){
   motorD.run(RELEASE); 
   motorI.run(RELEASE);
  }

The Serial output (9600 / Newline / COM5):

1
2
A
R
I
D
0
1

You can use SerialTransfer.h to automatically packetize and parse your data for inter-Arduino communication without the headace. The library is installable through the Arduino IDE and includes many examples.

Here are the library's features:

This library:

  • can be downloaded via the Arduino IDE's Libraries Manager (search "SerialTransfer.h")
  • works with "software-serial" libraries
  • is non blocking
  • uses packet delimiters
  • uses consistent overhead byte stuffing
  • uses CRC-8 (Polynomial 0x9B with lookup table)
  • allows the use of dynamically sized packets (packets can have payload lengths anywhere from 1 to 254 bytes)
  • can transfer bytes, ints, floats, and even structs!!

Example TX Arduino Sketch:

#include "SerialTransfer.h"

SerialTransfer myTransfer;

void setup()
{
  Serial.begin(115200);
  Serial1.begin(115200);
  myTransfer.begin(Serial1);
}

void loop()
{
  char buff[] = "hi";

  myTransfer.txObj(buff, sizeof(buff));
  myTransfer.sendData(sizeof(buff));
  delay(100);
}

Example RX Arduino Sketch:

#include "SerialTransfer.h"

SerialTransfer myTransfer;

void setup()
{
  Serial.begin(115200);
  Serial1.begin(115200);
  myTransfer.begin(Serial1);
}

void loop()
{
  if(myTransfer.available())
  {
    char buff[40];
    
    myTransfer.rxObj(buff, sizeof(buff));
    
    Serial.println("New Data: ");
    Serial.write(buff, sizeof(buff));
    Serial.println();
  }
  else if(myTransfer.status < 0)
  {
    Serial.print("ERROR: ");

    if(myTransfer.status == -1)
      Serial.println(F("CRC_ERROR"));
    else if(myTransfer.status == -2)
      Serial.println(F("PAYLOAD_ERROR"));
    else if(myTransfer.status == -3)
      Serial.println(F("STOP_BYTE_ERROR"));
  }
}

For theory behind robust serial communication, check out the tutorials Serial Input Basics and Serial Input Advanced.

Thanks!

Update:

I'm now looking at it from a different approach.

I was sending the BT information to the serial monitor when the idea in the first place is having the car run around without being connected to the pc at all.

So instead of sending the information to serial monitor and trying to take it from there, I simply asigned the value from BTSerial to my variable and it kinda works as intended now.

"Automatic mode" is working, my switch statement recognises the resp value and starts measuring and prints the distance, however, once I push '2', the first command activates and the motors stop but all the other instructions don't work. I even changed my second switch statemate to if's but that didnt help either.

Here's my new Serial output (9600 / Newline / COM5):

1
Distancia: 46.84 cm
Distancia: 154.74 cm
Distancia: 154.33 cm
Distancia: 154.68 cm
Distancia: 154.33 cm
Distancia: 155.70 cm
Distancia: 13.09 cm
Distancia: 12.74 cm
Distancia: 155.16 cm
Distancia: 155.77 cm
Distancia: 155.22 cm
Distancia: 154.81 cm
Distancia: 155.29 cm
Distancia: 155.22 cm
Distancia: 155.22 cm
2
A
R
I
@
D
O
1
Distancia: 155.43 cm
Distancia: 155.50 cm
Distancia: 155.57 cm
Distancia: 155.50 cm
Distancia: 155.09 cm
Distancia: 155.50 cm
Distancia: 155.09 cm
Distancia: 156.32 cm
Distancia: 155.57 cm
Distancia: 155.16 cm
Distancia: 155.09 cm
Distancia: 155.09 cm
Distancia: 155.50 cm
2

And my updated code:

//Incluir librerias para controlar motor shield y sensor ultrasonico.
#include <AFMotor.h>
#include <NewPing.h>
#include <SoftwareSerial.h>

//Definir constantes y variables.
#define TRIG_P A4 
#define ECHO_P A5
#define MAX_DIST 300
#define MAX_Vel 200
int led = A0;
int speedSet;
int iteraciones = 5;
float distancia, duracion;
char resp;

//Inicializar objetos del sensor y motores.
NewPing sonar(TRIG_P, ECHO_P, MAX_DIST); 
AF_DCMotor motorD(2); 
AF_DCMotor motorI(1);
SoftwareSerial BTSerial(A1, A2); // RX | TX

void setup() {
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  BTSerial.begin(9600);
}

void loop() {

  //Lee información del BT y la escribe en el monitor serial.
  if (BTSerial.available()){
    resp = BTSerial.read();
    Serial.println(resp);
  }  

//  if(Serial.available()>0){      
//    resp = Serial.read();
//    Serial.println(resp);
    
    switch(resp){

      case '1':

      delay(24); //Tiempo maximo que tarda en recibir una medición.

      /*Calcular la distancia frente al sensor utilizando la duración de la señal, 
      la cual mide ida y vuelva por lo cual se divide entre 2 
      y se multiplica por la velocidad del sonido (343 m/s).
      */
      
      duracion = sonar.ping_median(iteraciones);
      distancia = (duracion/2)*0.0343;
      
      Serial.print("Distancia: ");
      Serial.print(distancia);
      Serial.println(" cm"); 
      
      if(distancia!=0 && distancia<=20){
        digitalWrite(led,HIGH);
        ALTO();
        delay(100);
        REVERSA();
        delay(400);
        IZQUIERDA();
        delay(100);
      }else 
        digitalWrite(led,LOW);
        ADELANTE();
      break;
      
      case '2':
      ALTO();
      
       if(resp == 'A'){
         ADELANTE();
       } else if (resp == 'R'){
         REVERSA();
       } else if (resp == 'I'){
         IZQUIERDA();
       } else if (resp == 'D'){
         DERECHA();
       } else if (resp == 'O'){
         ALTO();
       }
      break;
       }       
    }
// }


  // Inician métodos que definen las acciones del carro.
  
void ADELANTE(){
   motorD.run(FORWARD);      
   motorI.run(FORWARD);
    for (speedSet = 0; speedSet < MAX_Vel; speedSet +=2){
      motorD.setSpeed(speedSet + 20);
      motorI.setSpeed(speedSet - 20);
    }
  }

void REVERSA(){
   motorD.run(BACKWARD);      
   motorI.run(BACKWARD);  
    for (speedSet = 0; speedSet < MAX_Vel; speedSet +=2){
      motorD.setSpeed(speedSet + 20);
      motorI.setSpeed(speedSet - 20);
    }
  }  

void DERECHA() {
   motorD.run(RELEASE);
   motorI.run(FORWARD);     
   delay(300);
   motorD.run(FORWARD);      
   motorI.run(FORWARD);      
  } 
 
void IZQUIERDA() {
   motorD.run(FORWARD);     
   motorI.run(RELEASE);     
   delay(300);
   motorD.run(FORWARD);     
   motorI.run(FORWARD);
  }  

void ALTO(){
   motorD.run(RELEASE); 
   motorI.run(RELEASE);
  }

The switch variable 'resp' is '2', that's why ALTO() is executed. You then check if (resp == 'A') which will never be true because the value hasn't been changed.

Alright, so how do I change it? I thought it was already being changed since the "new" value is printed in the serial monitor every time I press a different button, and it shows as A, R, I, D, O.

It changes from 1 to 2 and vice versa when I press the two "mode" buttons, but it doesn't when I press the others, what am I missing here?

I appreciate you pointing out where im wrong, but can I get a clue on how to fix it?

Why ask this question in so many places?

Because I'm trying to find a solution to my problem, I wasn't aware it's agaisnt the rules posting to other forums, there might be people in the other one that don't necessarily use this one, so I posted on both.

I wasn't aware it's agaisnt the rules posting to other forums

No forum can have a rule about not posting in other fora, although there are legitimately rules about not posting in other parts of the same forum.

I do love this part of your opening post:

I got it all working except it's not

Gave me a good chuckle to start the day :wink: