HC-05 Bluetooth, out of range reset/stop

Hi!

Im currently working on a RC-car project, using an Arduino Nano and the HC-05 Bluetooth module. The car uses several actuators, like servo's, LED's and a DC-motor.

I have everything working 100% smoothly, including my Bluetooth connection. Everlything works as it's supposed to. Nothing more, nothing less.

However, I noticed that when I control the speed and I cut the Bluetooth connection (just stop powering the Bluetooth module), my car keeps driving. That means when I drive my RC car out of range, it keeps going!

I would like to program a emergency stop for when Bluetooth connection is lost, cutting the cars acceleration and letting it roll out. I've tried several codes already, but no luck. I would like to ask if any of you have already had success programming something similar.

Here's my code:

// Control DC motor speed (both directions) over Bluetooth using RoboRemo app

// Hardware setup:
// BT module   Arduino
// GND ------- GND
// VCC ------- 5V
// TX-O ------ pin0
// RX-I ------ pin1

// H bridge -- Arduino
// Vcc ------- Vin
// GND ------- GND
// A --------- pin9
// B --------- pin10


#define bluetooth Serial      //Defining libraries (bluetooth and servo)
#include <Servo.h>

Servo stuurServoFRNT;         //Servo's used
Servo stuurServoBCK;
Servo railServoFRNT;
Servo railServoBCK;

int In1 = 5;                  //Integers for motor controller
int In2 = 3;
int enA = 12;

const int LedPin = 13;
int ledState = LOW;
unsigned long previousMillis = 0;
const long interval = 250; 

char cmd[100];
int cmdIndex;

boolean cmdStartsWithh(const char *st) {
	for (int i = 0; ; i++) {
		if (st[i] == 0) return true;
		if (cmd[i] == 0) return false;
		if (cmd[i] != st[i]) return false;;
	}
	return false;
}

int SteeringChoice;           //Integer for the choice between steering backwheels and frontwheels

void exeCmd() {

//Steering + Choice button (front/rear)

  if (cmdStartsWithh("tog") ) { //Toggle string for steering choice (button)
    if(SteeringChoice) {
      Serial.print("Optie IF");
        Serial.print('\n');
      SteeringChoice = 0;
    } else {
      Serial.print("Optie Else");
      Serial.print('\n');
      SteeringChoice = 1;
  }
}

  if (cmdStartsWithh("servo ")) {           //String for the servo slider
    int val = atoi(cmd + 6);
    if(SteeringChoice == 0) {               //If Stringchoice = 0, Steering Front is active
      Serial.print("IF = 0");
      Serial.print('\n');
      stuurServoFRNT.writeMicroseconds(val);
    }
    if(SteeringChoice == 1) {               //If Stringchoice = 1, Steering Back is active
      Serial.print("IF = 1");
      Serial.print('\n');
       stuurServoBCK.writeMicroseconds(val);
  }
}

//Driving lights

  if (cmdStartsWithh("speed ")) {            //String for Driving Lights
    int val = atoi(cmd + 6);

    Serial.print("LED: ");           //Write this in the serial monitor
    Serial.print(val);
    Serial.print('\n');

    if (val > 0) {
      analogWrite(14, 500);
    } else {
      analogWrite(14,0);
    }
    if (val < 0) {
      analogWrite(15, 500);
    } else {
      analogWrite(15,0);
    }
  }
  
//RailWheels1
	if (cmdStartsWithh("servorail1 ")) {      //String for Railwheels Servo 1
	int val = atoi(cmd + 11);

	railServoFRNT.writeMicroseconds(val);

	Serial.print("Servo angle rail: ");
	Serial.print(val);
	Serial.print('\n');
  }

//RailWheels2
  if (cmdStartsWithh("servorail2 ")) {       //String for Railwheels Servo 1
  int val = atoi(cmd + 11);

  railServoBCK.writeMicroseconds(val);
  }

//Speed
	if (cmdStartsWithh("speed ")) {            //String for DC-Motor (acceleration)
		int val = atoi(cmd + 6);

		Serial.print("Motor speed: ");           //Write this in the serial monitor
		Serial.print(val);
		Serial.print('\n');

		// Forward motion
		if (val >= 0) {
			analogWrite(In1, val);
			analogWrite(In2, 0);
		}

		// Backward motion
		if (val <= 0) {
			analogWrite(In1, 0);
			analogWrite(In2, -val);
	  }
  }
}

void setup() {

	//delay(500);

	bluetooth.begin(230400);                  //Bluetooth baud rate (raised to 230400, standard HC-05 baud rate is 9600)

	digitalWrite(enA, LOW);

	pinMode(In1, OUTPUT);                     //L298N forward/backward pin
	pinMode(In2, OUTPUT);                     //L298N forward/backward pin
  pinMode(14, OUTPUT); //RedFront - WhiteBack
  pinMode(15, OUTPUT); //WhiteFront - RedBack
  pinMode(LedPin, OUTPUT);
	//analogWrite(In1, 0);
	//analogWrite(In2, 0);

	stuurServoFRNT.attach(9, 800, 1800);      //Attach the front steering servo to pin 8, turn between 800/1800
  stuurServoBCK.attach(11, 800, 1800);      //Attach the back steering servo to pin 11, turn between 800/1800
	railServoFRNT.attach(6, 800, 2200);       //Attach the front rail servo to pin 6, turn between 800/2200
  railServoBCK.attach(10, 1000, 2000);      //Attach the back rail servo to pin 10, turn between 1000/2000

  //SteeringChoice = 0;

	cmdIndex = 0;
}

void loop() {

  if (cmdStartsWithh("speed ")) {            //String for DC-Motor (acceleration)
    int val = atoi(cmd + 6);
        if (val != 0) {

  
unsigned long currentMillis = millis();
 if (currentMillis - previousMillis >= interval) {
  previousMillis = currentMillis;
  if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }
    digitalWrite(LedPin, ledState);  
    }
    }
    if (val == 0) {
      digitalWrite(LedPin, 0);
    }
  }
  
	if (bluetooth.available()) {

		digitalWrite(enA, HIGH);                //Motorcontroller Enable pin = High
 
		char c = (char)bluetooth.read();

		if (c == '\n') {
			cmd[cmdIndex] = 0;
			exeCmd();                             //Execute the command
			cmdIndex = 0;                         //Reset the cmdIndex
		}
		else {
			cmd[cmdIndex] = c;
			if (cmdIndex<99) cmdIndex++;
		}
	}
}

Thanks in advance,

CC

  if (cmdStartsWithh("speed ")) {            //String for Driving Lights

What does "speed" have to do with driving lights?

  railServoBCK.writeMicroseconds(val);
  }

//Speed
	if (cmdStartsWithh("speed ")) {            //String for DC-Motor (acceleration)
		int val = atoi(cmd + 6);

Drinking and coding don't go together. Use Tools + Auto Format to remove the evidence of your drunken tabbing.

void loop() {

  if (cmdStartsWithh("speed ")) {            //String for DC-Motor (acceleration)

First, so, now, "speed" has something to do with acceleration. WTF?

Second, when loop() starts, cmd doesn't have a value. Why the hell would you start with dealing with the value in cmd BEFORE getting a value in cmd?

How would you determine that the bluetooth device is "out of range"? How does out-of-range differ from dead-battery?

The point is that the car should stop if there is no communication with the controller for some period of time, regardless of why there is no communication. To know that that period of time has elapsed, you need to record when you get data from the controller. You need to, on every pass through loop(), determine (FIRST) that there has been recent data before deciding what to do.

Getting data, if there is any, should be done before making the decision, too.

Hello,

Most HC-05 modules have a STATE pin. If you have one of those, you can connect this STATE pin to an Arduino input and read the state of the HC-05 (connected or disconnected). If you don't have this pin available, you will have to solder a wire on PIO9 (see datasheet).

On mine, 0 mean connected, 1 mean disconnected, I don't remember what's the default because it depends on the value of the AT+POLAR setting, which I modified.

@PaulS

First: The model has front and back lights (white and red). These lights switch depending on if you drive forward or backwards. Thats why I use the speed string in the driving lights code.

Second: Thank you for pointing out my "drunken tabbing". Cleaned that up too. Still, that has nothing to do with my question.

Third: Speed, is the id of my 'speed' slider in my smartphone control app. Thats why "speed" has everything to do with acceleration.

Fourth: You're correct on the 'out of range' matter. Its all about communication between the controller and the module. But how would I record this recieved data, and how do I make a decision when there is no data recieved anymore?

CC

There is a very good example right in front of you. You posted your question at 12:52 AM. I replied at 02:00 AM. You read my reply (noticed that there was data to read and read it) and responded at 02:16 (and 02:21).

Now, how will you determine that I am going to, or not going to, reply? You are the car; I am the controller. You have to make some decision on what to do based on how long it has been since you got data from me.

You know when there is data (from the bluetooth controller) - bluetooth.available() will return a non-zero value. You can record when that happens (just like the forum software records when it gets data).

Periodically (read that as on every pass through loop()), see how long it has been since data was available. If you haven't heard from the controller balls-to-the-wall-full-speed-ahead() probably isn't the function to call.

@PaulS

Great example. Gonna try that.

Weird. The solution I proposed is probably the best and fastest, but you completely ignored it.

@guix

Im sorry I didnt thank you for your advice. Im currently working on your example. Trying to figure out how to modify my module, so connected is 1 and disconnected is 0. Currently the state pin on my module sends a stream of analog data, so Im trying to change that to a simple logical 1/0 state.

CC

hello dear CrazyCreature45, dear PaulS and guix,

many many thanks for raising this - i was getting afraid of the issues discussed.

means when I drive my RC car out of range, it keeps going!

that is just a horrible idea - i love to see this solution

Many thanks for sharing