PowerBroker2 / ELMduino

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

ESP32 connects via BT, can send AT commands only, no query TIMEOUT-STOPPED error #60

Closed Knight2021 closed 3 years ago

Knight2021 commented 3 years ago

Hi, I have this problem and I tried almost everithing, My Esp32 connects correctly to vlink bluetooth 4 adapter and I can send at commands successfully. Example:

atz

atzELM327 v2.2

at dp

at dp AUTO, ISO 9141-2

0105

010541 05 2E

I can send and read succesfully AT commands with this sketch:

void loop()
{
   myELM327.sendCommand(READ_VOLTAGE);

  if (myELM327.status == ELM_SUCCESS)

  {

  Serial.print("Data "); Serial.println(myELM327.payload);

  }

  else
      printError();
}

But if I want to read coolant temperature with the following command is not working:

ELM327.queryPID(01, 05);

or this

myELM327.sendCommand("0105");

or this

 void loop()
{

float ct = myELM327.engineCoolantTemp();

  if (myELM327.status == ELM_SUCCESS)
  {
      Serial.print("Coolant C. "); Serial.println(ct);

  }

  else
      printError();
}

I have always the same errors 6-7 elm stopped and timeout but connection is stable, there is any problem with esp32 240mhz? Timing of some sort to adjust in library for query command? Thank You for Your help.

PowerBroker2 commented 3 years ago

Are you sure your library is up to date? When doing manual AT commands, what happens when you type the following commands?:

AT Z
AT E0
AT S0
AT AL
AT TP A0
0105

Also, printError() should print the payload received by the ELM327 even after an error. What payload printouts happen when you run your sketch?

Knight2021 commented 3 years ago

Library is up to date 2.4.1

If I send the AT commands from serial monitor I obtain this:

at

I can succesfully send AT command from sketch too

e.g.:

myELM327.sendCommand(READ_VOLTAGE); Serial.print("Battery "); Serial.println(myELM327.payload);

result is: bat

But... using this command myELM327.sendCommand("0105"); or myELM327.queryPID(01, 05); or float ct = myELM327.engineCoolantTemp(); + Serial.print("Coolant C. "); Serial.println(ct);

I always have the same result, printError() shows errors but not received payload

err

I'm sticking to coolant temp because it's just what I need but the rpm sketch isn't working too.

Thank You for your help, I have no clue. I tried to lower th clock to 80 Mhz but was not useful.

Edit: I quick setup an arduino uno with hc-05 bt module and the behaviour is the same, connects correctly but same error so is not an ESP32 issue, maybe the query routine is not compatible with iso9141 protocol? at dp AUTO, ISO 9141-2. In serial monitor I can still read the temperature typing 0105 and if I connect with smartphone all works without problems.

PowerBroker2 commented 3 years ago

You mention something about battery voltage, temperature, and engine coolant temperature (the same thing maybe?). You also show you got something to work, but say several things that may or may not do the same don't work.

All in all I'm quite confused...What exactly are you trying to do, what is working, and what isn't?

I don't think anything is wrong with the iso protocol, so don't mess with that for now.

PowerBroker2 commented 3 years ago

Also, I don't have your car or electronics, so if you could do some digging in the code on your side to figure out what's going on, I'd appreciate it. I'm happy to fix bugs, but I need those bugs explained in detail by users who encounter them because I don't have access to similar equipment.

Knight2021 commented 3 years ago

I just want to read coolant temperature, but I cant' so trying to figuring out where is the problem I tried to send AT commands and I discovered the following:

Hardware side: I think my OBD adapter (Vlink Icar pro) is working flawlessly because with smartphone all is working. Is not a ESP related issue like I thought because with arduino+hc05 is exactly the same Esp or arduino connects without problem to Vlink Icar pro dongle, connection is stable

Software side: I don't need that but just to test connection I discovered that I can send AT commands and get answer from serial monitor or automatically from sketch. I can write in seral monitor 0105 ( or any other supported PID) and get result in serial monitor ONLY (not sketch)

About coolant temperature: If I write 0105 in serial monitor I can read the coolant temperature but that's all I can't read temperature with engineCoolantTemp(); If I try to use engineCoolantTemp(); this causes always stopped-timeout errors Again, using the sketch provided with library that shows rpm ( I'm not interested in RPM but just for testing purpose) is not working too (timeout, stopped) so is not just temperature related, every query is rejected, I can get coolant temperature value just typing manually in serial monitor but not from sketch. All is working manually, nothing is working from the sketch but AT commands.

I tried with sendCommand("0105"); but again it throws the same errors.

Thank You for Help

PowerBroker2 commented 3 years ago

Ok, thank you. That makes a lot more sense - although I'm still not sure what is causing the underlying issue. If the AT commands return the correct values, the lib should parse the messages perfectly fine. However, it seems like whenever you try to print the payload buffer, nothing is printing - as if the ELM327 isn't responding.

In order to debug, I'll need you to add Serial.print("recChar: "); Serial.println(recChar); after this line in the lib's CPP file: https://github.com/PowerBroker2/ELMduino/blob/f76302d0ea0d45d8be180b32c47aa2a656e2ec27/src/ELMduino.cpp#L2344

That will tell you in real-time what the ELM327 is responding with. Once we verify the Arduino is receiving bytes through the lib, then we can start to look at the parsing algorithm...

Knight2021 commented 3 years ago

Ok, I've added the line and now the output is: str

Edit: I added a delay (2000); after this line in the lib's CPP file: 2330 elm_port->print('\r'); and it works just very slow because of the delay. Any value under 2000ms is too short. Instead of add a delay it will be nice to modify the timeout value in library but I didn't find how, can You help with this or do You have another solution? Thank You

PowerBroker2 commented 3 years ago

This is a rather odd test result. Are you testing with the car on and running?

I'm going to do some updates to the lib really soon that will include the ability to set a custom timeout value and add a debug mode. Let me do the update before you test test again.

PowerBroker2 commented 3 years ago

Ok, I updated the library (I haven't tagged a new version yet, though) to add a debug mode and allow you to specify your own timeout value.

Do the following for your next test:

  1. Enable timestamps on your serial monitor
  2. Update your sketch's begin() function to look like this: begin(ELM_PORT, true, 2000)
  3. Test again and let me know what happens

Note that you'll have to manually install the latest version of the lib through GitHub since I haven't tagged out a new version. I'd like to let you test it first so I can work out any kinks before letting it go live. If you don't know how to manually install libs from GitHub, there are several youtubes and tutorials on the subject.

Knight2021 commented 3 years ago

Ok I have done what You requested but I could connect only one time and I forget to turn on timestamps, then I tried to connect again and again with no success. This is the only serial output I have, without timestamps .

ts

Then I switched back to the old (2.4.1) lib and I changed this line in the lib's .h uint16_t timeout_ms = 1000; to uint16_t timeout_ms = 2000; and deleted from .cpp the previous delay (2000); and all is working fast, I mean refresh rate is like from smartphone so the timeout problem is solved for me. I want just to add that i have noticed that in lib's .cpp SHORT_TERM_FUEL_TRIM_BANK_1 you are using the wrong formula. The correct formula is findResponse() / 1.28) - 100.0 and not findResponse() / 2.55) - 100.0); according to Wikipedia. This is valid for all four fuel trim (long/short bank1/2).

PowerBroker2 commented 3 years ago

But 2.4.1 is the lib version you originally had the problem with, right? I didn't change anything between that version and the current master branch except print codes and the ability to change timeout_ms through the begin() method, so switching between those versions shouldn't make a difference. I'm starting to think your ELM327 is the real culprit.

Can you please post your code using the master branch (not 2.4.1)?

I'll take a look at the SHORT_TERM_FUEL_TRIM_BANK_1 thing, too

Knight2021 commented 3 years ago

Yes but I fixed the problem that I had with 2.4.1 changing the timeout_ms It worked all day and have no problem it connects in few seconds. I know that with the new library I can change the timeout directly from inside the sketch but to me is not working, can't complete connection. For sure this trick works with the new library too. I think the problem is the car's ecu that has a slower response than others. It's a Yaris MY 2003. This is the code I used with the new library.

#include "BluetoothSerial.h"
#include "ELMduino.h"

BluetoothSerial SerialBT;
#define ELM_PORT   SerialBT
#define DEBUG_PORT Serial

ELM327 myELM327;

void setup()
{

  DEBUG_PORT.begin(115200);
  SerialBT.setPin("1234");
  ELM_PORT.begin("ESP", true);

  if (!ELM_PORT.connect("Android-Vlink"))
  {
    DEBUG_PORT.println("Couldn't connect to OBD scanner - Phase 1");
    while(1);
  }

    if (!myELM327.begin(ELM_PORT), true, 2000)

   {
    Serial.println("Couldn't connect to OBD scanner - Phase 2");
    while (1);
  }

    Serial.println("Connected to ELM327");

}

void loop()
{

  float ld = myELM327.engineLoad();
  float ct = myELM327.engineCoolantTemp();

  if (myELM327.status == ELM_SUCCESS)

  {

      Serial.print("load "); Serial.println(ld);
      Serial.print("coolant "); Serial.println(ct);

  }

  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);
}
PowerBroker2 commented 3 years ago

Try this with version 2.5.0 instead:

#include "BluetoothSerial.h"
#include "ELMduino.h"

BluetoothSerial SerialBT;
#define ELM_PORT   SerialBT
#define DEBUG_PORT Serial

ELM327 myELM327;

void setup()
{
  DEBUG_PORT.begin(115200);
  SerialBT.setPin("1234");
  ELM_PORT.begin("ESP", true);

  if (!ELM_PORT.connect("Android-Vlink"))
  {
    DEBUG_PORT.println("Couldn't connect to OBD scanner - Phase 1");
    while (1);
  }

  if (!myELM327.begin(ELM_PORT, true, 2000))
  {
    Serial.println("Couldn't connect to OBD scanner - Phase 2");
    while (1);
  }

  Serial.println("Connected to ELM327");
}

void loop()
{
  float ld = myELM327.engineLoad();

  if (myELM327.status == ELM_SUCCESS)
  {
    Serial.print("load "); Serial.println(ld);
  }
  else
    myELM327.printError();

  float ct = myELM327.engineCoolantTemp();

  if (myELM327.status == ELM_SUCCESS)
  {
    Serial.print("coolant "); Serial.println(ct);
  }
  else
    myELM327.printError();
}
Knight2021 commented 3 years ago

I tried, with 2.5.0 and the code above can't pass the phase 2 connection, serial monitor output is blank. if I try to connect with the old .begin(ELM_PORT)) passes phase 2 but obviously I get the same timeout errors. Editing the value inside the lib is the only solution for now. zzz

PowerBroker2 commented 3 years ago

I don't think you tried version 2.5.0 considering it had a bug that prevented it from compiling for the ESP32 (see issue #63). Try with 2.5.1 and see what happens.

Two more things:

Knight2021 commented 3 years ago

Why would I have to lie? I'm interested in solving this problem. The board selected is esp32 dev hardware boards version installed on arduino ide is 1.05 . Arduino IDE v 1.8.13 In issue #63 he's using 1.04 cores I'm using 1.05 You have my code, try and compile. Again, You have my code, do You see something like I'm sending a query before the previous query is finished? I can query just once and the result is the same. Is simple as that, the car is not responding in 1000ms just in 2000ms, simply I solved this issue editing the library .h timeout_ms The car has no can bus just k line and iso 9141 protocol, adapter is fully compatible, working with smartphones like a charm. and now my esp is working too thanks to 2000ms timeout and 2.41 lib See attached Pdf file for 2.50 compiling output no errors with 2.50 but it won't connect. 2.41 connects and works without problems with 2000ms timeout, I will see what happens with 2.51. I know you can't guarantee the lib before 2008 but it works! output.pdf

PowerBroker2 commented 3 years ago

I didn't mean to say you lied - I've had times where I thought I uploaded a sketch and didn't realize I had a compile error. Left me wondering why my code wasn't working lol.

I've kind of run out of ideas other than maybe specifying ISO_9141_5_BAUD_INIT (you can do that in the begin() function).

Needing 2 seconds between queries sounds like a lot, but if it works it works!