Sparkfun OBDII UART - Arduino Uno Stuck at 832RPM-13Kmh[SOLVED]

Hi,

I'm working on a hobby project with Sparkfun OBDII UART + Arduino Uno + 16x2 LCD Screen, i'm trying to read my car's RPM-Speed-Coolant Temprature-Oxy Sensor on runtime.

Wired OBDII to Arduino as:
OBD TX -> ARDUINO RX
OBD RX-> ARDUINO TX
OBD GND -> ARDUINO GND

As far as i understand OBDII board does all the job and it's just communicating with arduino through serial, they provided an example here : OBD II UART Hookup Guide - learn.sparkfun.com

I haven't sparkfun serial lcd, so i've changed codes according to my lcd as follow;

#include <SoftwareSerial.h>
#include "DFRobot_RGBLCD.h"
const int colorR = 255;
const int colorG = 0;
const int colorB = 0;
DFRobot_RGBLCD lcd(16,2);  //16 characters and 2 lines of show
char rxData[20];
char rxIndex=0;
int vehicleSpeed=0;
int vehicleRPM=0;
void setup() 
{
lcd.init();
lcd.setRGB(colorR, colorG, colorB);
Serial.begin(9600);
lcd.clear();  
lcd.setCursor(0,0);
lcd.print("Hiz: ");
lcd.setCursor(0,1);
lcd.print("Devir: ");
delay(1500);
Serial.println("ATZ");
delay(2000);
Serial.flush();
}

void loop() 
{
Serial.println("010D");
getResponse();
getResponse();
vehicleSpeed = strtol(&rxData[6],0,16);
lcd.setCursor(4,0);
lcd.print(vehicleSpeed);
lcd.print(" km/h");
delay(100);
Serial.flush();
Serial.println("010C");
getResponse();
getResponse();
vehicleRPM = ((strtol(&rxData[6],0,16)*256)+strtol(&rxData[9],0,16))/4;
lcd.setCursor(6,1);
lcd.print(vehicleRPM);
delay(100);
}
void getResponse(void){
  char inChar=0;
  while(inChar != '\r'){
    if(Serial.available() > 0){
      if(Serial.peek() == '\r'){
        inChar=Serial.read();
        rxData[rxIndex]='\0';
        rxIndex=0;
      }
      else{
        inChar = Serial.read();
        rxData[rxIndex++]=inChar;
      }
    }
  }
}

with above code i believe arduino receives last rpm and speed record before i shut down the engine which is 832RPM - 13 Kmh (at this point i'm not sure if arduino receive speed value correctly because when i shut down the engine i was parked the car and speed was 0kmh), in normal case when i start the car rpm and speed value should have changed but even after started the car the value stands still,it's not changing.

I bought waveshare's USB FTDI(TTL) adapter to figure it out is this board communicate with car or pc properly, connected usb ttl as;
OBD TX -> TTL RX
OBD RX-> TTL TX
OBD GND -> TTL GND

connected to OBDII port of my car, opened tera term, connected to COM20 (ttl defined as com20 on the pc) and run below commands as suggested in their manual;

ATZ -- resetted card successfully
ATRV -- returned 12.4 V as it should be, which is my battery voltage 
ATSP0 -- auto find and select car's protocol it returned OK
010C -- RPM of the car it returned 41 0C 00 00 (engine wasn't started)
010C -- RPM of the car it returned 41 0C 10 F4 (engine started--idle RPM arround 1.000 rpm) 
010D -- speed of the car it returned 41 00 00
010D -- speed of the car it returned 41 00 00 both value is the same because the car is not moving :)

According to above outcome the board is fine and communicating with car or pc or arduino without any problem.

But when i try with arduino when i connect the board to my car and turn my ignition to battery mode it reads rpm as 832 and speed as 13 and don't update those values even i start the engine.

What am i doing wrong?





i thought maybe the obd board not sending \r, so i added \r end of the commands but no luck so far

If your vehicle speed is always coming back 13, then rxData[6] must be 'D' (hex 13).

Have you tried displaying the rxData buffer on your LCD to see what you have? I'm guessing something is amiss in your getResponse() function

blh64:
If your vehicle speed is always coming back 13, then rxData[6] must be 'D' (hex 13).

Have you tried displaying the rxData buffer on your LCD to see what you have? I'm guessing something is amiss in your getResponse() function

when i print rxData it says STOPPED

ATZ
010C

010C
ELM327 v1.3a
010C
>010C
010C
STOPPED
010C
>010C
010C
STOPPED
010C

and if rxData = "STOPPED" then rxData[6] = 'D' which is 0x13 in hex notation

blh64:
and if rxData = “STOPPED” then rxData[6] = ‘D’ which is 0x13 in hex notation

exactly.

with manufacturer sample code it returns STOPPED no matter what you do, so wrote an simple sketch as below;

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2);
char rxData[20];
char rxIndex=0;

void setup() 
{
lcd.init();
lcd.backlight();
Serial.begin(9600);
lcd.setCursor(0,0);
lcd.print("ATZ->");
Serial.println("ATZ");
getResponse();
getResponse();
lcd.setCursor(0,1);
lcd.print(rxData);
delay(3000);
Serial.flush();
lcd.clear();
//lcd.setCursor(0,1);
//lcd.print("010C->");

}

void loop() 
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("010C->");
Serial.println("010C");
getResponse();
getResponse();
lcd.setCursor(0,1);
lcd.print(((strtol(&rxData[6],0,16)*256)+strtol(&rxData[9],0,16))/4);
delay(3000);
lcd.clear();
}

void getResponse(void)
{
  char inChar=0;
  //Keep reading characters until we get a carriage return
  while(inChar != '\r'){
    //If a character comes in on the serial port, we need to act on it.
    if(Serial.available() > 0){
      //Start by checking if we've received the end of message character ('\r').
      if(Serial.peek() == '\r'){
        //Clear the Serial buffer
        inChar=Serial.read();
        //Put the end of string character on our data string
        rxData[rxIndex]='\0';
        //Reset the buffer index so that the next character goes back at the beginning of the string.
        rxIndex=0;
      }
      //If we didn't get the end of message character, just add the new character to the string.
      else{
        //Get the new character from the Serial port.
        inChar = Serial.read();
        //Add the new character to the string, and increment the index variable.
        rxData[rxIndex++]=inChar;
      }
    }
  }
}

with above code it reads rpm without any problem but due to long delays (3 seconds) it is dead slow(seems like serial.flush() doesn’t work at all),when you push to throttle (like when you hold on 2.000 rpm) it takes arround 10 seconds to show 2.000 rpm, when i shortened the delays (i’ve tried 1000-1500-2000-2500) it returns “STOPPED”.

I also have this bluetooth obdII module https://www.ebay.com/c/1038655933

when i plug this module to car and start it’s phone app it shows runtime RPM with very short delay (like 1 second or less).

Sparkfun’s OBDII board uses STN1110 which is identical of ELM327 and supports all OBD commands, also those bluetooth diagnostic tools uses the same STN1110, in this case sparkfun’s board shouldn’t this slow, most probably i’m doing something wrong but i couldn’t figure it out what is it yet.

when i was searching found an user message like this "For the peoples who receives STOPPED, this is caused by sending any characters on the UART after you have issued a command. So if your serial terminal is sending CRLF (carriage return, line feed), change it to only send CR and it'll solve the problem." i don't send the CRLF(carriage return, line feed) with my commands, what is this means? is there even any settings arduino's serial.print related to CRLF?

Serial.println() adds a newline '\n' to the end of the print. If your string contains '\r' at the end, then you are sending CR+LF.

If you just want a CR, you have to do this

Serial.print("ATZ\r");

and never use println()

blh64:
Serial.println() adds a newline '\n' to the end of the print. If your string contains '\r' at the end, then you are sending CR+LF.

If you just want a CR, you have to do this

Serial.print("ATZ\r");

and never use println()

thank you i didn't know that.

I've finally managed the reproduce same problem on terminal app, connected obd board to my pc through usb ftdi and connected with tera term app, when i send "010C" car returned rpm, in tera term if you don't write anything and just press enter it repeats last command, so when i hit enter with 1second delays (maybe hundered times :slight_smile: ) car returned rpm value in hexadecimal without any problem, but when i hold my finger on enter button then command send period speeds up (obivously) and car started to turn "OBD ERROR" & "STOPPED" as i see on arduino,in my case it seems like problem is not related to CRLF, arduino's speed is the problem.

So i wrote a small exe with Delphi to see what will happen if i send commands with 1 second delays, connected obd board to pc throuh ftdi and started the program i wrote, it worked perfectly, but when i use "delay(1000);" with arduino it returns "STOPPED" so it means that arduino sending commands to obd too fast, and when i observe the lights on arduino it's really seems like blinking faster than 1second delay, you know lights on arduino goes crazy when you use delay(100) or delay(75); it blinks just like that.

Am i missing something here? i mean isn't delay(1000) = 1second or is there any alternate to delay?

Here is my code to read returning data from obd board.

char rxData[20];
char rxIndex=0;

void setup() 
{
Serial.begin(9600);
Serial.println("ATZ");//reset board
getResponse();
getResponse();
Serial.println(rxData);
delay(1000);
Serial.println("0100");//init OBD communication
getResponse();
getResponse();
Serial.println(rxData);
delay(1000);

Serial.flush();
}

void loop() 
{
Serial.println("010C");
getResponse();
getResponse();
Serial.println(rxData);
delay(1000);
Serial.flush();
}

void getResponse(void)
{
  char inChar=0;
  //Keep reading characters until we get a carriage return
  while(inChar != '\r'){
    //If a character comes in on the serial port, we need to act on it.
    if(Serial.available() > 0){
      //Start by checking if we've received the end of message character ('\r').
      if(Serial.peek() == '\r'){
        //Clear the Serial buffer
        inChar=Serial.read();
        //Put the end of string character on our data string
        rxData[rxIndex]='\0';
        //Reset the buffer index so that the next character goes back at the beginning of the string.
        rxIndex=0;
      }
      //If we didn't get the end of message character, just add the new character to the string.
      else{
        //Get the new character from the Serial port.
        inChar = Serial.read();
        //Add the new character to the string, and increment the index variable.
        rxData[rxIndex++]=inChar;
      }
    }
  }
}

ELMduino.h might be a library that is compatible with your OBDII interface board. It was originally designed for interfacing with ELM327 chips, but it looks like your board uses the exact same API.

Give it a shot - I'd be interested whether or not it fixes things for you

Power_Broker:
ELMduino.h might be a library that is compatible with your OBDII interface board. It was originally designed for interfacing with ELM327 chips, but it looks like your board uses the exact same API.

Give it a shot - I’d be interested whether or not it fixes things for you

it seems great library and yes sparkfun obdII board uses exact same api, so as far as i understand from exaples this library designed for mostly bluetooth/wireless obd diagnostic devices, so i did a quick test with below code;

#include "ELMduino.h"
ELM327 myELM327;
uint32_t rpm = 0;
void setup() 
{
Serial.begin(9600);
Serial.println("ATZ");
}

void loop() 
{
float tempRPM = myELM327.rpm();
rpm = (uint32_t)tempRPM;
Serial.print("RPM: "); Serial.println(rpm);
delay(500);
printError();
}

void printError()
{
  Serial.print("Received: ");
  for (byte i = 0; i < myELM327.recBytes; i++)
    Serial.write(myELM327.payload[i]);
  Serial.println();
  if (myELM327.status == ELM_SUCCESS)
    Serial.println(F("\tELM_SUCCESS"));
  else if (myELM327.status == ELM_NO_RESPONSE)
    Serial.println(F("\tERROR: ELM_NO_RESPONSE"));
  else if (myELM327.status == ELM_BUFFER_OVERFLOW)
    Serial.println(F("\tERROR: ELM_BUFFER_OVERFLOW"));
  else if (myELM327.status == ELM_UNABLE_TO_CONNECT)
    Serial.println(F("\tERROR: ELM_UNABLE_TO_CONNECT"));
  else if (myELM327.status == ELM_NO_DATA)
    Serial.println(F("\tERROR: ELM_NO_DATA"));
  else if (myELM327.status == ELM_STOPPED)
    Serial.println(F("\tERROR: ELM_STOPPED"));
  else if (myELM327.status == ELM_TIMEOUT)
    Serial.println(F("\tERROR: ELM_TIMEOUT"));
  else if (myELM327.status == ELM_TIMEOUT)
    Serial.println(F("\tERROR: ELM_GENERAL_ERROR"));
  delay(100);
}

and most probably did something wrong :slight_smile: because output like :

08:44:24.613 -> ATZ
08:44:24.613 -> RPM: 4294967295
08:44:25.067 -> Received: 
08:44:25.168 -> RPM: 4294967295
08:44:25.669 -> Received: 
08:44:25.769 -> RPM: 4294967295
08:44:26.270 -> Received: 
08:44:26.370 -> RPM: 4294967295
08:44:26.872 -> Received: 
08:44:26.972 -> RPM: 4294967295
08:44:27.473 -> Received: 
08:44:27.573 -> RPM: 4294967295
08:44:28.074 -> Received: 
08:44:28.175 -> RPM: 4294967295
08:44:28.676 -> Received: 
08:44:28.776 -> RPM: 4294967295
08:44:29.277 -> Received: 
08:44:29.378 -> RPM: 4294967295

As a father of newborn i need to wake myself up with bold black coffee before i test something :slight_smile: , but if you can give me a hand i’ll be appreciated.

after 1 week of try i finally solved it :slight_smile:

As you guys know UNO has 1 i/o serial port, and Sparkfun's OBDII board doesn't work on same i/o serial port (at least i couldn't be able to), with uno when you send a command through serial to obd board you need to wait minimum 3 seconds to send another command or car's can-bus thinks that you canceled the first command returns STOPPED error, but with MEGA it works perfectly because mega has 3 i/o serial ports. You simply define Serial(TX)-Serial1(RX) and it works perfectly with 75ms delay.

Here is the working code.

//Set up ring buffer
char rxData[20];
char rxIndex = 0;
int rpmstored = 0;

    void setup()
    {
      Serial.begin(9600); // prints to serial monitor
      Serial1.begin(9600); //Hardware serial connection to the obdii uart
      OBD_init(); //initiates obd link
      delay(3000);
    }
    
    void loop()
{    
rpmstored = getRPM();
//int mph = (int)((getSPEED() * 10000L + 5) / 16090); //convert to mph
//  Serial.print (mph);
Serial.print("S:");
Serial.print (getSPEED());
Serial.print (",");
Serial.print("R:");
Serial.println (getRPM());
//Serial.print (",");
//Serial.print("W:");
//Serial.print (getWATERTEMP());
//Serial.print (",");
//Serial.print("O:");
//Serial.print (getOILTEMP());
//Serial.print (",");
//Serial.print("F:");
//Serial.print (getFUEL());
//Serial.print (",");
//Serial.print("V:");
//Serial.println (getVOLT());
delay(100);
Serial.flush();
    }
    
    void OBD_init(void)
    {
      //Wait for a little while before sending the reset command to the OBD-II-UART
      delay(2000);
      //Reset the OBD-II-UART
      Serial1.print("ATZ\r");
      //Wait for a bit before starting to send commands after the reset.
      delay(2);
      OBD_read();
      Serial1.print("ATE0\r");
      OBD_read();
      //Serial1.flush();
    }
    
    int getRPM(void)
    {
      //Query the OBD-II-UART for the Vehicle rpm
      Serial1.flush();
      Serial1.print("010C\r");
      OBD_read();

      return ((strtol(&rxData[6], 0, 16) * 256) + strtol(&rxData[9], 0, 16)) / 4;
    }

    int getSPEED(void)
    {
      //Query the OBD-II-UART for the vehicle speed
      Serial1.flush();
      Serial1.print("010D\r");
      OBD_read();

      return strtol(&rxData[6], 0, 16);
    }

    int getOILTEMP(void)
    {
      //Query the OBD-II-UART for the vehicle speed
      Serial1.flush();
      Serial1.print("015C\r");
      OBD_read();

      return strtol(&rxData[6], 0, 16);
    }

    int getFUEL(void)
    {
      //Query the OBD-II-UART for the vehicle speed
      Serial1.flush();
      Serial1.print("012F\r");
      OBD_read();

      return strtol(&rxData[6], 0, 16);
    }

    int getVOLT(void)
    {
      //Query the OBD-II-UART for the vehicle speed
      Serial1.flush();
      Serial1.print("0142\r");
      OBD_read();

      return strtol(&rxData[6], 0, 16);
    }

    int getWATERTEMP(void)
    {
      //Query the OBD-II-UART for the Engine Coolant Temp
      Serial1.flush();
      Serial1.print("0105\r");
      OBD_read();

      return strtol(&rxData[6], 0, 16) - 40;
    }
    
    
    void OBD_read(void)
    {
      char c;
      do {
        if (Serial1.available() > 0)
        {
          c = Serial1.read();
          if ((c != '>') && (c != '\r') && (c != '\n')) //Keep these out of our buffer
          {
            rxData[rxIndex++] = c; //Add whatever we receive to the buffer
          }
        }
      } while (c != '>'); //The ELM327 ends its response with this char so when we get it we exit out.
      rxData[rxIndex++] = '\0';//Converts the array into a string
      rxIndex = 0; //Set this to 0 so next time we call the read we get a "clean buffer"
    
    }

@power_broker your library is a masterpiece for me, but i couldn't be able to work with this board(due to my lack of knowledge i'm sure), but i tested with two different bluetooth ELM327 adapter on Arduino Uno+HC05 bluetooth, just worked perfectly & fast.

Thanks to all guys for ideas and help.

sheshman:
it seems great library and yes sparkfun obdII board uses exact same api, so as far as i understand from exaples this library designed for mostly bluetooth/wireless obd diagnostic devices, so i did a quick test with below code;

#include "ELMduino.h"

ELM327 myELM327;
uint32_t rpm = 0;
void setup()
{
Serial.begin(9600);
Serial.println(“ATZ”);
}

void loop()
{
float tempRPM = myELM327.rpm();
rpm = (uint32_t)tempRPM;
Serial.print("RPM: "); Serial.println(rpm);
delay(500);
printError();
}

void printError()
{
  Serial.print(“Received: “);
  for (byte i = 0; i < myELM327.recBytes; i++)
    Serial.write(myELM327.payload[i]);
  Serial.println();
  if (myELM327.status == ELM_SUCCESS)
    Serial.println(F(”\tELM_SUCCESS”));
  else if (myELM327.status == ELM_NO_RESPONSE)
    Serial.println(F("\tERROR: ELM_NO_RESPONSE"));
  else if (myELM327.status == ELM_BUFFER_OVERFLOW)
    Serial.println(F("\tERROR: ELM_BUFFER_OVERFLOW"));
  else if (myELM327.status == ELM_UNABLE_TO_CONNECT)
    Serial.println(F("\tERROR: ELM_UNABLE_TO_CONNECT"));
  else if (myELM327.status == ELM_NO_DATA)
    Serial.println(F("\tERROR: ELM_NO_DATA"));
  else if (myELM327.status == ELM_STOPPED)
    Serial.println(F("\tERROR: ELM_STOPPED"));
  else if (myELM327.status == ELM_TIMEOUT)
    Serial.println(F("\tERROR: ELM_TIMEOUT"));
  else if (myELM327.status == ELM_TIMEOUT)
    Serial.println(F("\tERROR: ELM_GENERAL_ERROR"));
  delay(100);
}




and most probably did something wrong :) because output like :


08:44:24.613 → ATZ
08:44:24.613 → RPM: 4294967295
08:44:25.067 → Received:
08:44:25.168 → RPM: 4294967295
08:44:25.669 → Received:
08:44:25.769 → RPM: 4294967295
08:44:26.270 → Received:
08:44:26.370 → RPM: 4294967295
08:44:26.872 → Received:
08:44:26.972 → RPM: 4294967295
08:44:27.473 → Received:
08:44:27.573 → RPM: 4294967295
08:44:28.074 → Received:
08:44:28.175 → RPM: 4294967295
08:44:28.676 → Received:
08:44:28.776 → RPM: 4294967295
08:44:29.277 → Received:
08:44:29.378 → RPM: 4294967295




As a father of newborn i need to wake myself up with bold black coffee before i test something :) , but if you can give me a hand i'll be appreciated.

This wouldn’t work, because you never call “myELM327.begin()”. Try it with that call and see what happens

Power_Broker:
This wouldn’t work, because you never call “myELM327.begin()”. Try it with that call and see what happens

oh my you are right, i can be really silly :slight_smile: tomorrow i’ll test and let you know.

sheshman:
oh my you are right, i can be really silly :slight_smile: tomorrow i'll test and let you know.

Me too, honestly :slight_smile:

Power_Broker:
Me too, honestly :slight_smile:

good to hear i’m not the only one haha :slight_smile: Tested again with below code;

#include "ELMduino.h"
ELM327 myELM327;
uint32_t rpm = 0;
#define ELM_PORT Serial
void setup() 
{
Serial.begin(9600);
//Serial.println("ATZ");
myELM327.begin(ELM_PORT);
}

void loop() 
{
  float tempRPM = myELM327.rpm();
  if (myELM327.status == ELM_SUCCESS)
  {
    rpm = (uint32_t)tempRPM;
    Serial.print("RPM: "); Serial.println(rpm);
  }
  else
  {
    printError();
  }
}

void printError()
{
  Serial.print("Received: ");
  for (byte i = 0; i < myELM327.recBytes; i++)
    Serial.write(myELM327.payload[i]);
  Serial.println();
  if (myELM327.status == ELM_SUCCESS)
    Serial.println(F("\tELM_SUCCESS"));
  else if (myELM327.status == ELM_NO_RESPONSE)
    Serial.println(F("\tERROR: ELM_NO_RESPONSE"));
  else if (myELM327.status == ELM_BUFFER_OVERFLOW)
    Serial.println(F("\tERROR: ELM_BUFFER_OVERFLOW"));
  else if (myELM327.status == ELM_UNABLE_TO_CONNECT)
    Serial.println(F("\tERROR: ELM_UNABLE_TO_CONNECT"));
  else if (myELM327.status == ELM_NO_DATA)
    Serial.println(F("\tERROR: ELM_NO_DATA"));
  else if (myELM327.status == ELM_STOPPED)
    Serial.println(F("\tERROR: ELM_STOPPED"));
  else if (myELM327.status == ELM_TIMEOUT)
    Serial.println(F("\tERROR: ELM_TIMEOUT"));
  else if (myELM327.status == ELM_TIMEOUT)
    Serial.println(F("\tERROR: ELM_GENERAL_ERROR"));
  delay(100);
}

the output was

12:06:16.660 -> AT Z
AT E0
AT S0
AT AL
AT TP A0
010C
Received: 
12:06:19.003 -> 	ERROR: ELM_TIMEOUT
12:06:19.097 -> Received: 
12:06:19.097 -> 	ERROR: ELM_TIMEOUT
12:06:19.191 -> Received: 
12:06:19.191 -> 	ERROR: ELM_TIMEOUT
12:06:19.285 -> Received: 
12:06:19.285 -> 	ERROR: ELM_TIMEOUT
12:06:19.379 -> Received: 
12:06:19.379 -> 	ERROR: ELM_TIMEOUT
12:06:19.519 -> Received:

tried both on mega & uno, strangely bluetooth samples in the library works perfectly with my bluetooth obdII dongle. This board uses the exact same api but it returns TIMEOUT (RX-TX lights on board flashing tho)

Hmm, interesting - I bet the OBDII board doesn't like some of the config settings. I'm glad it works for your bluetooth dongle, though

Power_Broker:
Hmm, interesting - I bet the OBDII board doesn't like some of the config settings. I'm glad it works for your bluetooth dongle, though

I'm sure your library will work with this board but i need to dig in , but let me tell you this was the first and the last time i ever buy or use any sparkfun product, my car's model is 2004, car companies started to use fast can-bus technology (CAN-L & CAN-H) since 2008 that's why i stuck with OBDII and this trash product.

With sparkfun OBDII board ;

1-when you program & upload your code to arduino you need to disconnect RX from obd board, otherwise board goes brick even if you don't power up the board while you uploading.

2-There is no sleep mode when you turn off the ignition key, it keeps on and drain your battery (it takes 0.8Amp and it's enough to drain your car's battery in 2 weeks)

3-Their support is based on "we don't know your car, your car's protocols, we can not do anything, you are on your own", even if you ask a simple question like is this board can work on 115.200 instead of 9.600 baudrate.

4-You literally need to beg for help on their official forum, there are thousands of questions without answer.

First i bought seedstudio's can-bus shield but as i mentioned before it didn't work on my car because of the my car doesn't have that kind of can-bus.

Once again this was the last time i bought and use a sparkfun component, i'll not use never ever again.

@Power_Broker does your library works with esp32s(Bluetooth)? i've managed to work with HC-05 but it's kinda slow or hc-05 loosing connection most of the time (my hc-05 is broken i'm using for tests), i'm going to buy new one but i want to buy esp32s instead of HC-05

Whew, I'm glad I am using the Freematics, I thought about getting a Sparkfun ODB-thingy but did not.