Help Me with Implementing a few Formulas that I need in my Arduino code

Hello guys,

I am trying to improve the way my App meassures point to point distance (distance meassuring between two Bluetooth devices through Bluetooth Classic);

I need some assistance with coding the follwing formulas into my code:

1. Rssi Smoothing formula

Formula: Screenshot_48

The feedback filter used for eliminating noise in different environments is the filter utilized in this algorithm. If a filter approximation is employed, it can be expressed as where Ī± represents the weighted value. In this equation, although the range of Ī± value is 0-1, here the variable Ī± is 0.75. RSSI š‘› has represented the most recently measured value, and RSSI š‘›āˆ’1
represents the previous averaged value. This approach ensures that a large difference in RSSI values will be smoothed: This means that the average RSSI value corresponding to the signal strength at a distance depends on both the previous averaged value and the most recently measured value.

2. RSSI distance conversion formula: Screenshot_49

To obtain distances based on the measured RSSI the mathematical model in the equation.
Where, RSSI: is the RSSI value received (dBm), n: is the path-loss exponent is the distance, A: is the RSSI value at a ā€œ1ā€ meter reference distance.

  1. The Path Loss Model Formula: Screenshot_52

where R S S d 0 is the measured reference value at the distance of d 0. For further experiments in this work, d 0 is set to 1 m, so that R S S d 0 represents the measured RSSI at a distance of 1 m to the transmitter. Since there is no large obstacle in the environment to be tested, shadowing is not expected, and X Ļƒ is set to zero. The path loss exponent n depends on the environmental conditions.

4. Kalman Filter Formulas:

For the RSSI filtering, a one-dimensional Kalman filter is used. As previously mentioned, the Kalman filter has some parameters that have to be determined first. Looking at the RSSI values, their change is random. Therefore, the transition matrix F and the measurement matrix H are set to one. Furthermore, there is no external control input. Therefore, B Ɨ u t āˆ’1 is also set to zero. With these assumptions, the prediction and update phase can be shown as above.
The initial values are set to x^āˆ’t=0 and Pāˆ’t=0. The values for Q = 0.065 and R = 1.4 are determined experimentally. After the filters are applied, the curve form of the RSSI values is smoother than before.

For the Kalman filter I have two more options available, not sure if these are more suitable:

  1. Make my MIT 2 App use this .js file somehow:

kalmanjs/kalman.js at master Ā· wouterbulten/kalmanjs Ā· GitHub

  1. Install this Kalman library and implement it in Arduino (still don't know how to use it after installing it)

GitHub - bachagas/Kalman: A simplified one dimensional Kalman filter implementation for Arduino.

My Arduino code in its current form:

#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 "esp_gap_bt_api.h"
#include <esp_spp_api.h>
#include <esp_gattc_api.h>
#include "sdkconfig.h"
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

uint8_t link_master;
 
 
BluetoothSerial SerialBT;
int rssi = 0; //RSSI
int distance = 0; //DISTANCE
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;
 
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
  ESP32Mini_Bluetooth.begin("ESP32_Vibration_Control"); //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....
 
    if (rssi < -20)
    {
      digitalWrite(PIN, HIGH);
      //ESP32Mini_Bluetooth.println("Vibration Motor ON");
      Serial.print ("PIN turned ON");
    }

    if (rssi > -20)
    {
      digitalWrite(PIN, LOW);
      //ESP32Mini_Bluetooth.println("Vibration Motor OFF");
      Serial.print ("PIN turned OFF");
 
    }

    if (rssi > -20) {
  distance = 2;
} else if (rssi < -20) {
  distance = 1;
} else {
  distance = 0;
}
 
    //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(rssi);
      ESP32Mini_Bluetooth.print(", ");
      ESP32Mini_Bluetooth.println(distance);
    
    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("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);
}

Resources:

jayakody-2016-ijca-909028.pdf (ijcaonline.org)

An Improved BLE Indoor Localization with Kalman-Based Fusion: An Experimental Study (nih.gov)

Update 1: Trying to implement the Kalman filter, altough not sure how and where I'm supposed to use it in the code;

I followed the instructions here:

GitHub - bachagas/Kalman: A simplified one dimensional Kalman filter implementation for Arduino.

Unsure if I've managed to implement it or not:

#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";

//Creates the variables:
double measurement, filteredMeasurement;
Kalman myFilter(0.125,32,1023,0); //suggested initial values for high noise filtering

uint8_t link_master;
 
 
BluetoothSerial SerialBT;
int rssi = 0; //RSSI
int distance = 0; //DISTANCE
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;
 
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
  ESP32Mini_Bluetooth.begin("ESP32_Vibration_Control"); //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);
    
    if (rssi < -20)
    {
      digitalWrite(PIN, HIGH);
      //ESP32Mini_Bluetooth.println("Vibration Motor ON");
      Serial.print ("PIN turned ON");
    }

    if (rssi > -20)
    {
      digitalWrite(PIN, LOW);
      //ESP32Mini_Bluetooth.println("Vibration Motor OFF");
      Serial.print ("PIN turned OFF");
 
    }

    if (rssi > -20) {
  distance = 2;
} else if (rssi < -20) {
  distance = 1;
} else {
  distance = 0;
}
 
    //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(rssi);
      ESP32Mini_Bluetooth.print(", ");
      ESP32Mini_Bluetooth.println(distance);
    
    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("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);
}

Edit: It doesn't seem to do anything, RSSI values still fluctuate quite alot while not moving at all.

You should be able to do that. You can exchange values between the App and a simple function, so the values could be sent from the Arduino to the App, filtered and displayed. From the App Inventor Help:

http://ai2.appinventor.mit.edu/reference/components/userinterface.html#WebViewer

1 Like

Since I've set up a vibration motor to trigger at a certain signal strength, shouldn't this filter be implemented into the Arduino ? Because, I am afraid that if I implement the filter in my App, the Esp32 will not apply any filter to the RSSI, resulting in the Esp32 activating my vibration motor from unfiltered RSSI values instead of filtered ones, am I right?

If you look at my code, perhaps you could shine a light over my confusion.

I'd gladly set it up via the .js since it would be easier of course, but if that means the vibration motor will get triggered from unfiltered RSSI values, then the filter would be half useless.
Wouldn't it be wiser to get the Rssi filtering process happen in Arduino and then have the App receive already filtered values as well?

Actually, I'm sure I was wrong and it is necessary to filter on the hardware side, but how to implement it properly, I do not know. There must be some parameters that you can tweak? You may just need a little trial and error.

Edit: If triggering a vibration motor is going to cause so much interference, why use it?

Managed to implement all the formulas. Now I need to set up Highcharts.

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