PowerBroker2 / ELMduino

Arduino OBD-II Bluetooth Scanner Interface Library for Car Hacking Projects
MIT License
662 stars 125 forks source link

Wonky fuel rate readings on ESP32-Pico V4 #152

Closed Cynicroute closed 10 months ago

Cynicroute commented 1 year ago

Hi everyone. First of all, kudos @PowerBroker2 for this brilliant library. It's simplified even getting started with OBD-2 for a complete novice like me.

I've been working on grabbing readings from a generic ELM327 on a Pico V4 (battery, fuel level, fuel rate). While I can connect reliably, getting readings is inconsistent. Aside from the inconsistency, the one reading that comes back wonky every time is the fuel rate. I suspect there's a divisor that i'm missing. Thoughts?

#include <BluetoothSerial.h>
#include <ELMduino.h>

BluetoothSerial     SerialBT;
#define ELM_PORT    SerialBT
#define DEBUG_PORT  Serial
//#define REMOVE_BONDED_DEVICES 1   // Set 0 to disable

ELM327 myELM327;

uint32_t rpm = 0;
uint32_t volts = 0;
uint32_t litres = 0;
uint32_t lph = 0;

// For future 'if last' statement
//float lastVolts;
//float lastLitres;
//float lastLPH;

void setup()  {

  DEBUG_PORT.begin(115200);
  ELM_PORT.begin("OBDII", true);  //true enables debug mode
  delay(500);
  SerialBT.setPin("1234");

  DEBUG_PORT.println("Initializing...");

  if (!ELM_PORT.connect("OBDII"))
    {
      DEBUG_PORT.println("Stage 1 failed. Could not connect to ELM Device.");
      while(1);
    }

  if (!myELM327.begin(ELM_PORT, true, 2000))
    {
      Serial.println("Stage 2 failed. Could not connect to OBD-II.");
      while (1);
    }

  Serial.println("Connected to ELM327. Reading Data...");

}

void loop() {

  //--- RPM
  float getRPM = myELM327.rpm();
  if (myELM327.nb_rx_state == ELM_SUCCESS)
    {
      rpm = (uint32_t)getRPM;
      Serial.print("Revs: "); 
      Serial.print(rpm);
      Serial.print(" RPM");
    }
  else if (myELM327.nb_rx_state != ELM_GETTING_MSG)
    myELM327.printError();
  delay(100);

  //--- BATTERY VOLTAGE
  float getVolts = myELM327.batteryVoltage();
  if (myELM327.nb_rx_state == ELM_SUCCESS)
    {
      volts = (uint32_t)getVolts;  
      Serial.print("Battery: "); 
      Serial.print(volts);
      Serial.print(" v");
    }
  else if (myELM327.nb_rx_state != ELM_GETTING_MSG)
    myELM327.printError();
  delay(100);

  //--- FUEL LEVEL  
  float getLevel = myELM327.fuelLevel();
  if (myELM327.nb_rx_state == ELM_SUCCESS)
    {
      litres = (uint32_t)getLevel;
      Serial.print("Fuel Tank: "); 
      Serial.print(litres);
      Serial.print(" %");
    }
  else if (myELM327.nb_rx_state != ELM_GETTING_MSG)
    myELM327.printError();
  delay(100);

  //--- FUEL RATE
  float getRate = myELM327.fuelRate();
  if (myELM327.nb_rx_state == ELM_SUCCESS)
    {
      lph = (uint32_t)getRate;
      Serial.print("Fuel Consumption: "); 
      Serial.print(lph);
      Serial.print(" L/h");
    }
  else if (myELM327.nb_rx_state != ELM_GETTING_MSG)
    myELM327.printError();

  delay(1000);
}

And here's what's being spit out. Something tells me 200+ L/h is excessive for fuel consumption:

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 188777542, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1184
load:0x40078000,len:13132
load:0x40080400,len:3036
entry 0x400805e4
Initializing...
Clearing input serial buffer
Sending the following command/query: AT D
    Received char: ⸮
    Received char: O
    Received char: K
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: OK
Clearing input serial buffer
Sending the following command/query: AT Z
    Received char: A
    Received char: T
    Received char: _
    Received char: Z
    Received char: \r
    Received char: ⸮
    Received char: \r
    Received char: \r
    Received char: E
    Received char: L
    Received char: M
    Received char: 3
    Received char: 2
    Received char: 7
    Received char: _
    Received char: v
    Received char: 1
    Received char: .
    Received char: 5
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: ATZELM327v1.5
Clearing input serial buffer
Sending the following command/query: AT E0
    Received char: A
    Received char: T
    Received char: _
    Received char: E
    Received char: 0
    Received char: \r
    Received char: O
    Received char: K
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: ATE0OK
Clearing input serial buffer
Sending the following command/query: AT S0
    Received char: O
    Received char: K
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: OK
Clearing input serial buffer
Sending the following command/query: AT AL
    Received char: O
    Received char: K
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: OK
Clearing input serial buffer
Sending the following command/query: AT ST 00
    Received char: O
    Received char: K
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: OK
Clearing input serial buffer
Sending the following command/query: AT TP A0
    Received char: O
    Received char: K
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: OK
Connected to ELM327. Reading Data...
Service: 1
PID: 12
Normal length query detected
Query string: 010C1
Clearing input serial buffer
Sending the following command/query: 010C1
    Received char: S
    Received char: E
    Received char: A
    Received char: R
    Received char: C
    Received char: H
    Received char: I
    Received char: N
    Received char: G
    Received char: .
    Received char: .
    Received char: .
    Received char: \r
    Received char: 4
    Received char: 1
    Received char: 0
    Received char: C
    Received char: 1
    Received char: 3
    Received char: 5
    Received char: 6
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: SEARCHING...410C1356
Expected response header: 410C
Single response detected
64-bit response: 
    responseByte_0: 86
    responseByte_1: 19
    responseByte_2: 0
    responseByte_3: 0
    responseByte_4: 0
    responseByte_5: 0
    responseByte_6: 0
    responseByte_7: 0
Revs: 1237 RPM
Clearing input serial buffer
Sending the following command/query: AT RV
    Received char: 1
    Received char: 4
    Received char: .
    Received char: 4
    Received char: V
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: 14.4V
Battery: 14 v
Service: 1
PID: 47
Normal length query detected
Query string: 012F1
Clearing input serial buffer
Sending the following command/query: 012F1
    Received char: 4
    Received char: 1
    Received char: 2
    Received char: F
    Received char: 2
    Received char: 6
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: 412F26
Expected response header: 412F
Single response detected
64-bit response: 
    responseByte_0: 38
    responseByte_1: 0
    responseByte_2: 0
    responseByte_3: 0
    responseByte_4: 0
    responseByte_5: 0
    responseByte_6: 0
    responseByte_7: 0
Fuel Consumption: 0 L/h
Service: 1
PID: 12
Normal length query detected
Query string: 010C1
Clearing input serial buffer
Sending the following command/query: 010C1
    Received char: 4
    Received char: 1
    Received char: 0
    Received char: C
    Received char: 1
    Received char: 2
    Received char: F
    Received char: 2
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: 410C12F2
Expected response header: 410C
Single response detected
64-bit response: 
    responseByte_0: 242
    responseByte_1: 18
    responseByte_2: 0
    responseByte_3: 0
    responseByte_4: 0
    responseByte_5: 0
    responseByte_6: 0
    responseByte_7: 0
Fuel Consumption: 242 L/h
Service: 1
PID: 12
Normal length query detected
Query string: 010C1
Clearing input serial buffer
Sending the following command/query: 010C1
    Received char: 4
    Received char: 1
    Received char: 0
    Received char: C
    Received char: 1
    Received char: 4
    Received char: 1
    Received char: E
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: 410C141E
Expected response header: 410C
Single response detected
64-bit response: 
    responseByte_0: 30
    responseByte_1: 20
    responseByte_2: 0
    responseByte_3: 0
    responseByte_4: 0
    responseByte_5: 0
    responseByte_6: 0
    responseByte_7: 0
Fuel Consumption: 257 L/hService: 1
PID: 12
Normal length query detected
Query string: 010C1
Clearing input serial buffer
Sending the following command/query: 010C1
    Received char: 4
    Received char: 1
    Received char: 0
    Received char: C
    Received char: 1
    Received char: 7
    Received char: 3
    Received char: E
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: 410C173E
Expected response header: 410C
Single response detected
64-bit response: 
    responseByte_0: 62
    responseByte_1: 23
    responseByte_2: 0
    responseByte_3: 0
    responseByte_4: 0
    responseByte_5: 0
    responseByte_6: 0
    responseByte_7: 0
Fuel Consumption: 297 L/hService: 1
PID: 12
Normal length query detected
Query string: 010C1
Clearing input serial buffer
Sending the following command/query: 010C1
    Received char: 4
    Received char: 1
    Received char: 0
    Received char: C
    Received char: 1
    Received char: 7
    Received char: 7
    Received char: 0
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: 410C1770
Expected response header: 410C
Single response detected
PowerBroker2 commented 1 year ago

Glad you found the library useful! From a quick look I see you're calling multiple queries one right after the other before guaranteeing you fully parsed the responses of the initial query. Since this lib is asynchronous/non-blocking, if you don't do this check, it'll be like asking someone several questions in a conversation without giving them a chance to respond. This probably confuses which pid gets parsed to what variable (although I can't guarantee that's the only issue).

Take a look at this example that shows how to query multiple PIDs in a single sketch using a switch statement

Cynicroute commented 1 year ago

Makes sense. I'll give it a whirl and see what comes out.

Thank you!

Cynicroute commented 1 year ago

Well, I updated the sketch and it sort of works. It's pulling RPM, Volts, and Litres, but not L/h. I even threw in a small delay to slow things down a bit.

#include <BluetoothSerial.h>
#include <ELMduino.h>

BluetoothSerial     SerialBT;
#define ELM_PORT    SerialBT
#define DEBUG_PORT  Serial
//#define REMOVE_BONDED_DEVICES 1   // Set 0 to disable

ELM327 myELM327;

typedef enum { ENG_RPM, BATT_V, FUEL_L, FUEL_R }
    obd_pid_states;
    obd_pid_states obd_state = ENG_RPM;

uint32_t rpm = 0;
uint32_t volts = 0;
uint32_t litres = 0;
uint32_t lph = 0;

// For future 'if last' statement
//float lastVolts;
//float lastLitres;
//float lastLPH;

void setup()  {

  DEBUG_PORT.begin(115200);
  ELM_PORT.begin("OBDII", true);  //true enables debug mode
  delay(500);
  SerialBT.setPin("1234");

  DEBUG_PORT.println("Initializing...");

  if (!ELM_PORT.connect("OBDII"))
    {
      DEBUG_PORT.println("Stage 1 failed. Could not connect to ELM Device.");
      while(1);
    }

  if (!myELM327.begin(ELM_PORT, true, 2000))
    {
      Serial.println("Stage 2 failed. Could not connect to OBD-II.");
      while (1);
    }

  Serial.println("Connected to ELM327. Reading Data...");

}

void loop() {

switch (obd_state)
{
    case ENG_RPM:
    {  //--- RPM
    float getRPM = myELM327.rpm();
    if (myELM327.nb_rx_state == ELM_SUCCESS)
        {
        rpm = (uint32_t)getRPM;
        Serial.print("Revs: "); 
        Serial.print(rpm);
        Serial.print(" RPM");
        obd_state = BATT_V;
        }
    else if (myELM327.nb_rx_state != ELM_GETTING_MSG)
        {
        myELM327.printError();
        obd_state = BATT_V;
        delay(100);
        }
    break;
    }

    case BATT_V:
    {  //--- BATTERY VOLTAGE
    float getVolts = myELM327.batteryVoltage();
    if (myELM327.nb_rx_state == ELM_SUCCESS)
        {
        volts = (uint32_t)getVolts;  
        Serial.print("Battery: "); 
        Serial.print(volts);
        Serial.print(" v");
        obd_state = FUEL_L;
        }
    else if (myELM327.nb_rx_state != ELM_GETTING_MSG)
        {
        myELM327.printError();
        obd_state = FUEL_L;
        delay(100);
        }
    break;    
    }

    case FUEL_L:
    {  //--- FUEL LEVEL  
    float getLevel = myELM327.fuelLevel();
    if (myELM327.nb_rx_state == ELM_SUCCESS)
        {
        litres = (uint32_t)getLevel;
        Serial.print("Fuel Tank: "); 
        Serial.print(litres);
        Serial.print(" %");
        obd_state = FUEL_R;
        }
    else if (myELM327.nb_rx_state != ELM_GETTING_MSG)
        {
        myELM327.printError();
        obd_state = FUEL_R;
        delay(100);
        }
    break;
    }

    case FUEL_R:
    {  //--- FUEL RATE
    float getRate = myELM327.fuelRate();
    if (myELM327.nb_rx_state == ELM_SUCCESS)
        {
        lph = (uint32_t)getRate;
        Serial.print("Fuel Consumption: "); 
        Serial.print(lph);
        Serial.print(" L/h");
        obd_state = ENG_RPM;
        }
    else if (myELM327.nb_rx_state != ELM_GETTING_MSG)
        {
        myELM327.printError();
        obd_state = ENG_RPM;
        delay(100);
        }
    break;
    }
}

}

But still not quite right...

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 188777542, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:1184
load:0x40078000,len:13132
load:0x40080400,len:3036
entry 0x400805e4
Initializing...
Clearing input serial buffer
Sending the following command/query: AT D
    Received char: ⸮
    Received char: O
    Received char: K
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: OK
Clearing input serial buffer
Sending the following command/query: AT Z
    Received char: A
    Received char: T
    Received char: _
    Received char: Z
    Received char: \r
    Received char: ⸮
    Received char: \r
    Received char: \r
    Received char: E
    Received char: L
    Received char: M
    Received char: 3
    Received char: 2
    Received char: 7
    Received char: _
    Received char: v
    Received char: 1
    Received char: .
    Received char: 5
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: ATZELM327v1.5
Clearing input serial buffer
Sending the following command/query: AT E0
    Received char: A
    Received char: T
    Received char: _
    Received char: E
    Received char: 0
    Received char: \r
    Received char: O
    Received char: K
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: ATE0OK
Clearing input serial buffer
Sending the following command/query: AT S0
    Received char: O
    Received char: K
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: OK
Clearing input serial buffer
Sending the following command/query: AT AL
    Received char: O
    Received char: K
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: OK
Clearing input serial buffer
Sending the following command/query: AT ST 00
    Received char: O
    Received char: K
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: OK
Clearing input serial buffer
Sending the following command/query: AT TP A0
    Received char: O
    Received char: K
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: OK
Connected to ELM327. Reading Data...
Service: 1
PID: 12
Normal length query detected
Query string: 010C1
Clearing input serial buffer
Sending the following command/query: 010C1
    Received char: S
    Received char: E
    Received char: A
    Received char: R
    Received char: C
    Received char: H
    Received char: I
    Received char: N
    Received char: G
    Received char: .
    Received char: .
    Received char: .
    Received char: \r
    Received char: 4
    Received char: 1
    Received char: 0
    Received char: C
    Received char: 0
    Received char: E
    Received char: A
    Received char: 6
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: SEARCHING...410C0EA6
Expected response header: 410C
Single response detected
64-bit response: 
    responseByte_0: 166
    responseByte_1: 14
    responseByte_2: 0
    responseByte_3: 0
    responseByte_4: 0
    responseByte_5: 0
    responseByte_6: 0
    responseByte_7: 0
Revs: 937 RPMClearing input serial buffer
Sending the following command/query: AT RV
    Received char: 1
    Received char: 4
    Received char: .
    Received char: 1
    Received char: V
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: 14.1V
Battery: 14 vService: 1
PID: 47
Normal length query detected
Query string: 012F1
Clearing input serial buffer
Sending the following command/query: 012F1
    Received char: 4
    Received char: 1
    Received char: 2
    Received char: F
    Received char: 2
    Received char: 6
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: 412F26
Expected response header: 412F
Single response detected
64-bit response: 
    responseByte_0: 38
    responseByte_1: 0
    responseByte_2: 0
    responseByte_3: 0
    responseByte_4: 0
    responseByte_5: 0
    responseByte_6: 0
    responseByte_7: 0
Fuel Tank: 14 %Service: 1
PID: 94
Normal length query detected
Query string: 015E1
Clearing input serial buffer
Sending the following command/query: 015E1
    Received char: N
    Received char: O
    Received char: _
    Received char: D
    Received char: A
    Received char: T
    Received char: A
    Received char: \r
    Received char: \r
    Received char: >
Delimiter found.
All chars received: NODATA
ELM responded with errror "NO DATA"
Received: NODATA
ERROR: ELM_NO_DATA
Service: 1
PowerBroker2 commented 1 year ago

If the ELM327 responds with NO DATA it means for some reason your car's diagnostics computer does not support that PID

Cynicroute commented 1 year ago

Strange. I must be calling on the wrong PID. According to the ELM app on my phone, it's capturing 'calculated instant fuel rate' in L/h. (2.4 at idle... seems reasonable). I have some digging to do.