Arduino OBD-II project wiring and components
Arduino OBD-II project wiring and components

Troubleshooting Arduino OBD-II RPM Readings: Understanding OBD-II Commands for Engine Diagnostics

As an auto repair expert at autelfrance.com, I often encounter enthusiasts diving into DIY car diagnostics. Today, we’ll address a common issue faced when using an Arduino with an OBD-II UART module to read real-time engine data like RPM and speed. This project, while focused on data retrieval, touches upon the broader capabilities of OBD-II, including more advanced commands beyond basic sensor readings.

The user in our example is building a project with a Sparkfun OBDII UART module, Arduino Uno, and an LCD screen. They aim to display live RPM, speed, coolant temperature, and oxygen sensor readings. Let’s break down their setup and troubleshoot why they’re seeing static RPM and speed values even after starting the engine.

Their wiring is as follows, which is generally correct for UART communication:

  • OBD TX -> Arduino RX
  • OBD RX -> Arduino TX
  • OBD GND -> Arduino GND

They are using the example code provided by Sparkfun as a base and have adapted it for their DFRobot_RGBLCD. Here’s their code snippet:

#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("Speed: ");
  lcd.setCursor(0,1);
  lcd.print("RPM: ");
  delay(1500);

  Serial.println("ATZ"); // Reset OBD-II adapter
  delay(2000);
  Serial.flush();
}

void loop() {
  Serial.println("010D"); // Request vehicle speed (PID 010D)
  getResponse();
  getResponse(); // Call twice to discard potential extra bytes
  vehicleSpeed = strtol(&rxData[6],0,16);
  lcd.setCursor(7,0);
  lcd.print(vehicleSpeed);
  lcd.print(" km/h");
  delay(100);
  Serial.flush();

  Serial.println("010C"); // Request engine RPM (PID 010C)
  getResponse();
  getResponse(); // Call twice to discard potential extra bytes
  vehicleRPM = ((strtol(&rxData[6],0,16)*256)+strtol(&rxData[9],0,16))/4;
  lcd.setCursor(5,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]='';
        rxIndex=0;
      }
      else{
        inChar = Serial.read();
        rxData[rxIndex++]=inChar;
      }
    }
  }
}

The core issue is that the Arduino seems to be reading and displaying RPM and speed values only once, likely upon initial connection when the ignition is in “battery mode” (accessory mode), but these values do not update after the engine is started. They observe RPM as 832 and speed as 13 km/h initially, which remain static.

To troubleshoot, the user wisely used a USB FTDI (TTL) adapter and a terminal program (Tera Term) to directly communicate with the OBD-II module, bypassing the Arduino. This is a crucial step in isolating the problem. They connected:

  • OBD TX -> TTL RX
  • OBD RX -> TTL TX
  • OBD GND -> TTL GND

And used these commands in Tera Term, as suggested by the OBD-II UART module manual:

ATZ -- Reset the OBD-II adapter
ATRV -- Read battery voltage
ATSP0 -- Auto-detect OBD-II protocol
010C -- Request RPM (PID 010C)
010D -- Request Speed (PID 010D)

The results from Tera Term were successful. They received voltage readings and live RPM and speed data, confirming that the OBD-II module itself is functioning correctly and communicating with the car’s ECU. This is a significant finding, indicating the problem likely lies within the Arduino setup or code.

Possible Causes and Solutions

  1. Serial Communication Issues: While the wiring seems correct, double-check the baud rate. The Arduino code uses Serial.begin(9600). Ensure the OBD-II UART module is also set to 9600 baud or configured for auto-baud detection if it supports it. Mismatched baud rates are a common cause of communication problems.

  2. Code Logic in loop(): The code sends “010D” and “010C” commands and calls getResponse() twice after each. While calling getResponse() twice might be intended to clear extra bytes, it might be consuming the correct response as well. Try calling getResponse() only once after each command to see if this resolves the issue.

  3. Serial Buffer Overflow/Data Handling: The rxData buffer is 20 bytes, which should be sufficient for typical OBD-II responses. However, if there are issues in the getResponse() function or if the responses are longer than expected, it could lead to data corruption or incorrect parsing. Review the getResponse() function carefully. It waits for a carriage return (r) to terminate the response. This is standard OBD-II behavior.

  4. Serial.flush() Usage: Serial.flush() in Arduino waits for the transmission of outgoing serial data to complete. In this code, it’s used after sending commands and after displaying values. While not directly harmful, it might be adding unnecessary delays. Try removing Serial.flush() calls within the loop() to see if it makes a difference. Serial.flush() in the setup() is generally good practice after sending the ATZ command to ensure the reset command is fully transmitted.

  5. Power Supply: Although less likely since the initial readings are obtained, ensure the Arduino and OBD-II module are receiving stable and sufficient power, especially when the engine is running and electrical loads in the car change.

OBD-II Commands and Beyond: Engine Start Considerations

While this project focuses on reading data, it’s worth briefly mentioning the command capabilities of OBD-II. OBD-II standards primarily focus on diagnostic data and emissions-related information. Standard OBD-II commands (PIDs like 010C and 010D) are designed for reading sensor data, not for controlling vehicle functions like starting the engine.

The idea of an “Obdii Start Engine Command” is more related to advanced or manufacturer-specific commands, often outside the scope of standard OBD-II. While some advanced diagnostic tools or aftermarket devices might utilize proprietary commands to control certain vehicle functions, including remote start or engine manipulation, these are not part of the standard OBD-II protocol and are highly vehicle-specific and potentially risky to implement without deep understanding.

For typical DIY projects with Arduino and basic OBD-II UART modules, focusing on reading and displaying diagnostic data is the primary and safest application. Attempting to send commands to control critical engine functions like starting is generally not recommended and could lead to unintended consequences or even damage to the vehicle if not implemented correctly and with proper safety measures.

Next Steps for Troubleshooting

  1. Simplify the Code: For testing, simplify the Arduino code to only request RPM (010C) and display it. Remove the speed request and LCD code temporarily to isolate the RPM reading.

  2. Debug Serial Output: Add Serial.println(rxData); inside the loop() after calling getResponse(). This will print the raw response received from the OBD-II module to the Arduino serial monitor. Examine this output to see exactly what data is being received and if it’s changing after the engine starts.

  3. Check Protocol Detection: The code uses ATSP0 for auto protocol detection. While usually reliable, in some cases, manually setting the protocol using ATSP followed by a specific protocol number (e.g., ATSP6 for ISO 15765-4 CAN) might be necessary. Consult the OBD-II UART module documentation and your vehicle’s specifications to determine the correct protocol if auto-detection is suspected to be an issue.

  4. Verify Wiring Again: Double, even triple-check the wiring connections between the Arduino, OBD-II UART module, and the OBD-II port in your car. A loose or incorrect connection can cause intermittent or no communication.

By systematically checking these points and simplifying the setup for initial debugging, you should be able to pinpoint why the RPM and speed values are not updating after engine start. Remember to focus on reading and understanding the serial data being transmitted to ensure correct parsing and display of the OBD-II information.

[

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *