Arduino Distance Meassuring through Bluetooth Classic Signal Strength (RSSI) Project

When I started working at this Application (about 1 month ago) there was not too much documentation if any at all, in regards to meassuring distance via Bluetooth Classic (BT) for the Esp32.
There are, however, some tutorials and there is some documentation for Bluetooth Low Energy (BLE) which you may find by doing a simple Google Search using the apropriate keywords.

With all of that being said I am sharing here the progress I've made to try and make this task a bit more easy on those who wanted to use this technology and to improve it and play with it.

The reason I went with using Bluetooth Classic over Bluetooth Low Energy is that of range, BT Classic having a much bigger range at which it can operate at, unlike BLE (at least that's what I've read).

Both Bluetooth Modes have their ups and downs so it's up to you what's the best option, depending on your project terms, the range of operability and the battery consumption aspects, etc.

What does this code do, more exacly?

-It allows anyone with an Esp32 at their disposal to develop aplications that can trigger events based on the distance between the Esp32 module and the other device it is connected to *(in my case I used an Android Smartphone (Nexus 5x)). *
*The RSSI meassurement is incredibily decent, with high values that stop at 0 when you're near the Esp32 and low values that go down to -50 aprox. when you move at arpoximative 15-25 meters away. *
I tested the algorythm indoors (through walls) and in open air and it's pretty stable (meaning the signal will not tend to drop or increase too much when stationary or walking towards or away from the Esp32)
-The code comes already equiped with an applied Kalman noise filter, which can be calibrated even further
-It can trigger a certain PIN on your Esp32 devices (or more) at whatever signal strength or distance range you want to

I've heard alot of people saying that you can't really use the Bluetooth for Distance meassuring but I can tell you one thing about this, from my tests:

Yes, maybe it can't tell exacly at what distance you are standing from the Esp32, but it can sure tell if you're far or close, if you come close or go further away and the big signal fluctuations are pretty rare, at least in my case.

A Serial Plot Monitor Screenshot with the code in action:

There are a few things that are currently functional but not properly calibrated:

-Some variables of the distance meassuring algorythm (this is the most uncalibrated one)
What does it mean?
It means that if you are 1 meter away from the device it will indeed show that you're that far away, but the problem is that it ain't yet calibrated to add enough distance when you move away and the signal strength drops.
-The Kalman Filter works pretty good as it is right now, it really smoothens the RSSI and it makes it a bit more stable but it could be calibrated even further if you need to

Note: Until someone properly calibrates the Distance algorythm, I advise you to use the RSSI values as the trigger for any proximty application you may want to create, trust me on this one.

Before using the code, make sure to install all the Required Arduino Dependencies:

The Arduino Code: 0bin - encrypted pastebin

(paste this into a new sketch and it will be ready to run!)

Note: I may update this post and the code in order to make it more readable whenever I have some time.

If you do make any improvements or find smart ways to improve the code and its aplications, share it with the community if you wish, that'd be awesome.

This project wouldn't have been possible without all the help I've received from some very special people: from the Arduino and Electronicity Discord Channel Communities (thank you guys for all the help if you read this!) and with the help of some very special people from this community here: @SteveJG @Taifun @ABG @TIMAI2 and @Salman_Dev (you guys are awesome and have alot of patience!)

Much love, my dears!

e931fde4256ad1d1ef31e05e374176ed

4 Likes

Here is the 0bin code, for those of you wary of other sites ...

#include "esp_bt_main.h"
#include "esp_gap_bt_api.h"
#include "esp_bt_device.h"
#include "BluetoothSerial.h" //Header File for Serial Bluetooth, will be added by default into Arduino
#include "esp_gap_bt_api.h"
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "Kalman.h"
 
// My function prototypes
void gap_callback (esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param);
void spp_callback (esp_spp_cb_event_t event, esp_spp_cb_param_t *param);
 
 
//Creates the variables:
double measurement, filteredMeasurement;
Kalman myFilter(0.125,32,1023,0); //suggested initial values for high noise filtering
 
       // this->q = process_noise;
       // this->r = sensor_noise;
       // this->p = estimated_error;
       // this->x = intial_value; //x will hold the iterated filtered value
 
uint8_t link_master;
 
BluetoothSerial SerialBT;
 
int rssi = 0; //RSSI
 
/* Kalman filter variables */
 
    double q; //process noise covariance
    double r; //measurement noise covariance
    double x; //value
    double p; //estimation error covariance
    double k; //kalman gain
 
        
//distance = pow(10, ((refOneMeter - recvRSSI) / (10 * estPathLossExp))) //formula for distance meassurement
// we need variables to hold refOneMeter, recvRSSI, and estPathLossExp
 
byte addr[6] = {0, 0, 0, 0, 0, 0}; //to keep MAC address of the remote device , 8 bit value
 
static int PAIRING_VARIANT_PIN; //The user will be prompted to enter a pin or an app will enter a pin for user
 
struct read_rssi_delta_param;
struct esp_bt_gap_cb_param_t::read_rssi_delta_param read_rssi_delta; //read rssi parameter struct
 
esp_bd_addr_t bda; //remote bluetooth device address
 
int8_t rssi_delta; //rssi delta value range -128 ~127, The value zero indicates that the RSSI is inside the Golden Receive Power Range, the Golden Receive Power Range is from ESP_BT_GAP_RSSI_LOW_THRLD to ESP_BT_GAP_RSSI_HIGH_THRLD
 
esp_err_t esp_bt_gap_read_rssi_delta(esp_bd_addr_t remote_addr); //This function is called to read RSSI delta by address after connected. The RSSI value returned by ESP_BT_GAP_READ_RSSI_DELTA_EVT.
 
BluetoothSerial ESP32Mini_Bluetooth; //Object for Bluetooth
 
 
//ESP32Mini_Bluetooth_GAP_READ_RSSI_DELTA_EVT; //read RSSI event
//ESP_BT_GAP_DEV_PROP_RSSI; // Received Signal strength Indication, value type is int8_t, ranging from -128 to 127
//ESP_BT_GAP_RSSI_LOW_THRLD; // Low RSSI threshold
//ESP_BT_GAP_RSSI_HIGH_THRLD; //     RSSI threshold. High RSSI threshold
 
//esp_bd_addr_t bda; //remote bluetooth device address
//esp_bt_status_t stat; //read rssi status
 
 
const int PIN = 32;
const int CUTOFF = -60;
int incoming;
int best;
 
float distance = 0.0;
 
void setup() {
 
  ESP32Mini_Bluetooth.setPin("4321"); //This should solve the Secured Pin Connection
 
  SerialBT.begin();
 
  Serial.begin(9600); //Start Serial monitor in 9600 ; this is the line where it initialize serial to 9600 baud speed
 
  // this->q = process_noise;
  // this->r = sensor_noise;
  // this->p = estimated_error;
  // this->x = intial_value; //x will hold the iterated filtered value
 
 // float temp1  = ((-6) - (rssi));
 // float temp2 = (temp1 / 100);
 //  distance= pow(10,temp2);
 // distance = pow(10, (-6 - rssi) / (100));  
  
  ESP32Mini_Bluetooth.begin("Esp32-Mini"); //Name of your Bluetooth Signal
  Serial.println("Bluetooth Device is Ready to Pair");
 
  pinMode (PIN, OUTPUT);//Specify that Vibration Motor pin is output
 
  esp_bt_gap_register_callback (gap_callback); //register the RSSI callback function by calling this line
 
  //register SPP service callback to get remote address:
  SerialBT.register_callback(spp_callback);
 
  // //This is Legacy Pairing Code
  //ESP_BT_GAP_PIN_REQ_EVT //Legacy Pairing Pin code request
  //ESP_BT_GAP_CFM_REQ_EVT //Simple Pairing User Confirmation request.
  //ESP_BT_GAP_KEY_NOTIF_EVT //Simple Pairing Passkey Notification
  //ESP_BT_GAP_KEY_REQ_EVT //Simple Pairing Passkey request
 
}
 
void loop() {
 
  delay(100);
  if (SerialBT.hasClient()) { //this is where we get and handle RSSI value
 
    //when we need RSSI call this:
    esp_bt_gap_read_rssi_delta (addr); //now variable rssi contains RSSI level
    byte b = rssi; //etc....
 
    //reads measurement and filter it
  measurement = (double) rssi; //read new value from rssi
  filteredMeasurement = myFilter.getFilteredValue(measurement);
 
       float temp1 = (3) - (rssi);
       float temp2 = (temp1 / 100);
       distance = pow(10,temp2);
        
    if (rssi < -10)
    {
      digitalWrite(PIN, HIGH);
      //ESP32Mini_Bluetooth.println("Vibration Motor ON");
      //Serial.print ("PIN turned ON");
    }
 
    if (rssi > -10)
    {
      digitalWrite(PIN, LOW);
      //ESP32Mini_Bluetooth.println("Vibration Motor OFF");
      //Serial.print ("PIN turned OFF");
 
    }
 
    
 
    //ESP32Mini_Bluetooth.print("RSSI: "); //println add linefeed for end of printed string
    //ESP32Mini_Bluetooth.println(rssi); //println add linefeed for end of printed string
    
     
      //ESP32Mini_Bluetooth.print(", ");
       //ESP32Mini_Bluetooth.println(filteredMeasurement);     
      
      ESP32Mini_Bluetooth.print(rssi);      
      ESP32Mini_Bluetooth.print(", ");
      ESP32Mini_Bluetooth.println(distance);
 
//So building up the serial, we have  filtered: <value>  TAB
//we are adding   filtered: <value>  TAB distance: <value> TAB  rssi: <value>
      
      Serial.print ("filtered:");
      Serial.print (filteredMeasurement);
      Serial.print ("\t distance:");
      Serial.print (distance);
      Serial.print ("\t rssi:");
      Serial.print (rssi);
    
    delay (1000);    //DELAY OF 1 SECONDS
  }
  else
  {
    // Disconnected state
      digitalWrite(PIN, LOW);
     // Serial.println ("Disconnected. PIN turned OFF");
      Serial.println (rssi);
      delay(1000); // wait 1s
  }
 
  if (ESP32Mini_Bluetooth.available()) //Check if we receive anything from Bluetooth // is telling that BT has received some data and it need to be processed
  {
    incoming = ESP32Mini_Bluetooth.read(); //Read what we recevive
    Serial.print("Received:"); Serial.println(incoming);
    digitalWrite(PIN, best > CUTOFF ? HIGH : LOW);
    
  }
}
 
 
//RSSI callback function
void gap_callback (esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t *param)
{
  if (event == ESP_BT_GAP_READ_RSSI_DELTA_EVT)
  {
    rssi = param->read_rssi_delta.rssi_delta; // it checks it has connection
    Serial.print("\t RSSI Delta: ");
    Serial.println (param->read_rssi_delta.rssi_delta);
  }
}
 
//SPP service callback function (to get remote MAC address)
void spp_callback (esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
{
  if (event == ESP_SPP_SRV_OPEN_EVT)
    memcpy(addr, param->srv_open.rem_bda, 6);
}
 
2 Likes

Hi MelodyApril, may I know issit all the other library I have to download somewhere? Because I only have Kalman.h inside my libraries.

I'm sorry for asking this newbie question.. :sweat_smile:

Because my Serial Monitor only show "0" in result after paired it with my smartphone

Update:
Ohhhh~!!!!! Every bluetooth usage in ESP32 need a smartphone App to activate it, it works well!!!

1 Like

And do not worry, I am also working on an App as well but it's not yell ready, when it is I will also share the App here to be used with the code (have to figure out some chart related stuff).

1 Like

Update:

The Bluetooth Low Energy version of the code is ready and you can find it here:

Arduino Distance Meassuring through Bluetooth Low Energy Signal Strength (RSSI) Project - App Showcase - MIT App Inventor Community

1 Like

Still available to help to work on similar project?


Can you confirm this error?