Can an OBDII Scanner Read Speed? – Decoding Vehicle Speed with OBDII

As a content creator for autelfrance.com and an expert in auto repair, I often encounter questions from enthusiasts and professionals alike about vehicle diagnostics and data retrieval. A common question, especially among those new to automotive DIY and diagnostics, is: “Can an OBDII scanner read speed?”

The short answer is a resounding yes! OBDII (On-Board Diagnostics II) scanners are not just for reading trouble codes; they are powerful tools capable of accessing a wealth of real-time data from your vehicle’s computer system, including vehicle speed.

This article will delve into how OBDII scanners read speed, why this is incredibly useful, and how you can access this data yourself for various projects, whether you’re building a collision alert system, monitoring your car’s performance, or simply curious about the technology under the hood.

Understanding OBD-II and Vehicle Speed Data

The OBD-II system is standardized across most modern vehicles. Its primary purpose is to monitor vehicle emissions and engine health. However, to achieve this, the Engine Control Unit (ECU) or Powertrain Control Module (PCM) collects data from numerous sensors throughout the car. One of these crucial sensors is the vehicle speed sensor (VSS).

The VSS, typically located in the transmission or wheel hubs, sends signals to the ECU indicating the vehicle’s speed. The ECU processes this information for various functions, including speedometer display, cruise control, and transmission shifting. Crucially, this speed data is also made available through the OBD-II port.

OBD-II scanners communicate with your car’s ECU using standardized protocols. When you plug in an OBDII scanner and request vehicle speed, it sends a specific request to the ECU. The ECU, in turn, responds with the current speed data it’s receiving from the VSS.

This standardized access to vehicle speed via OBD-II opens up a world of possibilities beyond just professional diagnostics. For hobbyists and DIY enthusiasts, it means you can tap into your car’s speed data for custom projects using readily available and affordable tools like Arduino microcontrollers and CAN bus shields.

Using Arduino and CAN Bus to Read OBD-II Speed

The original poster in our source article is on the right track, aiming to use an Arduino Uno and a Seeed Studio CAN shield to read vehicle speed data. This is a popular and effective approach for DIY automotive projects. Let’s break down the key components and the provided code to understand how this works and address potential issues.

Hardware Components:

  • Arduino Uno R3: A microcontroller board that acts as the brain of the operation, processing data and running your custom code.
  • Seeed Studio CAN Shield: This shield allows the Arduino to communicate over the CAN (Controller Area Network) bus, which is the communication network used in modern vehicles, including for OBD-II diagnostics.
  • OBDII Connector: A cable to physically connect the CAN shield to your car’s OBD-II port, usually located under the dashboard.

Software and Code Explanation:

The provided Arduino code snippet is a good starting point for reading OBD-II data, specifically vehicle speed. Let’s analyze the code section by section:

#include <seeedgrayoled.h>
#include <wire.h>
#include "Arduino.h"
#include <mcp_can.h>
#include <mcp_can_dfs.h>
#include <spi.h>
#include "mcp_can.h"

const int SPI_CS_PIN = 9;
MCP_CAN CAN(SPI_CS_PIN);

#define PID_ENGIN_PRM    0x0C
#define PID_VEHICLE_SPEED 0x0D
#define PID_COOLANT_TEMP  0x05
#define CAN_ID_PID        0x7DF

unsigned char PID_INPUT;
unsigned char getPid    = 0;
int vSpeed;

void set_mask_filt() {
    CAN.init_Mask(0, 0, 0x7FC);
    CAN.init_Mask(1, 0, 0x7FC);
    CAN.init_Filt(0, 0, 0x7E8);
    CAN.init_Filt(1, 0, 0x7E8);
    CAN.init_Filt(2, 0, 0x7E8);
    CAN.init_Filt(3, 0, 0x7E8);
    CAN.init_Filt(4, 0, 0x7E8);
    CAN.init_Filt(5, 0, 0x7E8);
}

void sendPid(unsigned char __pid) {
    unsigned char tmp[8] = {0x02, 0x01, __pid, 0, 0, 0, 0, 0};
    SeeedGrayOled.setTextXY(0,0);
    SeeedGrayOled.putString("SEND PID: 0x");
    Serial.println(__pid, HEX);
    SeeedGrayOled.putNumber(__pid);
    CAN.sendMsgBuf(CAN_ID_PID, 0, 8, tmp);
}

void setup() {
    Serial.begin(115200);
    Wire.begin();
    SeeedGrayOled.init(SH1107G);
    SeeedGrayOled.setContrastLevel(100);
    SeeedGrayOled.clearDisplay();
    SeeedGrayOled.setNormalDisplay();
    SeeedGrayOled.setVerticalMode();
    SeeedGrayOled.setTextXY(0,0);
    while (CAN_OK != CAN.begin(CAN_500KBPS)) {
        SeeedGrayOled.putString("CAN BUS Shield init fail");
        SeeedGrayOled.putString(" Init CAN BUS Shield again");
        delay(100);
    }
    SeeedGrayOled.putString("CAN BUS Shield init ok!");
    delay(3000);
    SeeedGrayOled.clearDisplay();
}

void loop() {
    taskCanRecv();
    taskDbg();
    if (getPid) {
        getPid = 0;
        sendPid(PID_VEHICLE_SPEED);
        PID_INPUT = 0;
    }
}

void taskCanRecv() {
    unsigned char len = 0;
    unsigned char buf[8];
    if (CAN_MSGAVAIL == CAN.checkReceive()) {
        CAN.readMsgBuf(&len, buf);
        SeeedGrayOled.clearDisplay();
        SeeedGrayOled.putString("rn------------------------------------------------------------------");
        SeeedGrayOled.putString("Get Data From id: 0x");
        Serial.println(CAN.getCanId(), HEX);
        for (int i = 0; i < len; i++) {
            SeeedGrayOled.print(" ");
            SeeedGrayOled.print(buf[i], HEX);
        }
        Serial.println("");
        if (buf[2] == PID_VEHICLE_SPEED + 0x40) {
            vSpeed = buf[3];
            SeeedGrayOled.setTextXY(2, 0);
            SeeedGrayOled.putString("Vehicle Speed(km/h):");
            SeeedGrayOled.setTextXY(3, 0);
            SeeedGrayOled.putNumber(vSpeed);
            Serial.print("Vehicle Speed(km/h):");
            Serial.println(vSpeed);
        }
    }
}

void taskDbg() {
    getPid = 1;
    delay(1000);
}

Code Breakdown:

  • Includes: The code includes necessary libraries for the OLED display, Wire (I2C communication), Arduino core, and the MCP2515 CAN controller library (mcp_can.h).
  • CAN Initialization: MCP_CAN CAN(SPI_CS_PIN); initializes the CAN object, specifying the SPI chip select pin.
  • PID Definitions: #define statements define Parameter IDs (PIDs) for Engine RPM, Vehicle Speed, and Coolant Temperature. PID_VEHICLE_SPEED is set to 0x0D, which is the standard PID for vehicle speed. CAN_ID_PID (0x7DF) is the standard OBD-II request ID.
  • set_mask_filt(): This function sets CAN masks and filters. In this case, it’s configured to receive messages from IDs 0x7E8 to 0x7EF, which are typical response IDs from the ECU after sending a request to 0x7DF.
  • sendPid(unsigned char __pid): This function is crucial. It sends a CAN message to request a specific PID.
    • unsigned char tmp[8] = {0x02, 0x01, __pid, 0, 0, 0, 0, 0}; creates the data frame for the CAN message.
      • 0x02: Specifies the number of data bytes following.
      • 0x01: Service ID for “Show current data”.
      • __pid: The PID to request (e.g., PID_VEHICLE_SPEED – 0x0D).
    • CAN.sendMsgBuf(CAN_ID_PID, 0, 8, tmp); sends the CAN message with the request. CAN_ID_PID (0x7DF) is the target ID, 0 indicates no extended ID, 8 is the data length, and tmp is the data buffer.
  • setup(): Initializes serial communication, the OLED display, and crucially, the CAN bus with CAN.begin(CAN_500KBPS). OBD-II CAN typically operates at 500 kbps.
  • loop(): The main loop calls taskCanRecv() to check for and process incoming CAN messages and taskDbg() to periodically trigger sending the PID request.
  • taskCanRecv(): This function handles receiving CAN messages.
    • CAN.checkReceive() checks if a message is available.
    • CAN.readMsgBuf(&len, buf) reads the received message into buf.
    • The code then checks if the third byte of the received data (buf[2]) is equal to PID_VEHICLE_SPEED + 0x40. This is because a successful OBD-II response typically echoes the requested PID with the 0x40 bit set (to differentiate response from request).
    • If it’s a vehicle speed response, vSpeed = buf[3]; extracts the speed data, which is usually a single byte representing speed in km/h.
  • taskDbg(): Simply sets getPid = 1 every second, which triggers sending the PID_VEHICLE_SPEED request in the loop().

Potential Issues and Troubleshooting:

The original poster mentioned “not returning any data.” Here are some common reasons why this might happen and how to troubleshoot:

  1. CAN Bus Initialization Failure: The while (CAN_OK != CAN.begin(CAN_500KBPS)) loop in setup() should catch basic initialization problems. If “CAN BUS Shield init fail” persists, check:

    • Wiring: Ensure the CAN shield is correctly connected to the Arduino, especially the SPI pins and the CS pin (D9 in this code).
    • Shield Compatibility: Verify that the Seeed Studio CAN shield is compatible with the Arduino Uno R3 and that the mcp_can.h library is correctly installed and compatible with the shield version.
    • CAN Bus Speed: Double-check that 500 kbps is the correct CAN bus speed for your vehicle’s OBD-II. While 500 kbps is common, some vehicles might use different speeds.
  2. OBD-II Connection Issues:

    • Connector: Ensure the OBD-II connector is properly plugged into your car’s OBD-II port.
    • Vehicle Compatibility: While OBD-II is standardized, very old or some very specific vehicles might have compatibility issues. However, for most modern cars, this shouldn’t be a problem for basic PIDs like speed.
    • Ignition ON: OBD-II systems typically only become active when the vehicle’s ignition is turned to the “ON” position (engine doesn’t necessarily need to be running, but key needs to be in the “ON” or “Accessory” position in some cars).
  3. PID Request/Response Problems:

    • Incorrect PID: While 0x0D is the standard PID for vehicle speed, in rare cases, a specific vehicle might use a different PID or not support it. Consulting vehicle-specific OBD-II documentation (if available) or using a generic OBD-II scanner to verify speed PID support can be helpful.
    • Filtering Issues: While the set_mask_filt() function should be configured correctly for typical OBD-II responses, incorrect mask/filter settings could prevent receiving the ECU’s response. For basic PID requests, the provided filter settings should generally work.
    • ECU Response Time: In some cases, the ECU might take a short time to respond to a PID request. Adding a small delay after sendPid() and before checking for a response in taskCanRecv() might help, although the current code already has a 1-second delay in taskDbg() which should be sufficient.
  4. Code Logic Errors:

    • getPid Logic: The taskDbg() function sets getPid = 1 every second, which should trigger a speed request every second. Double-check that taskDbg() is being called correctly in loop().
    • Response Parsing: The code checks buf[2] == PID_VEHICLE_SPEED + 0x40. This is generally correct for standard OBD-II responses. However, if there are still issues, carefully examine the raw CAN data being received (using serial print of the entire buf array in taskCanRecv()) to understand the ECU’s response format for vehicle speed.

Debugging Tips:

  • Serial Monitor is Your Friend: The code already uses Serial.println() to print debug information. Make sure your Arduino Serial Monitor is open and set to the correct baud rate (115200). Pay close attention to the output, especially “CAN BUS Shield init ok!” and any error messages or received data.
  • Print Raw CAN Data: In taskCanRecv(), before checking buf[2], add code to print the entire buf array in hexadecimal to see the raw CAN message data being received. This can help diagnose if you are receiving any data and what the format is.
  • Simplify and Isolate: Start with the most basic code to just initialize the CAN bus and send a single speed request. Gradually add complexity as you get it working.
  • Use a Known Good OBD-II Scanner: If you have a handheld OBD-II scanner, use it to connect to your car and verify that it can read vehicle speed. This confirms that your car’s OBD-II system is working correctly and that vehicle speed data is available.

Conclusion

Yes, an OBDII scanner absolutely can read speed! It’s a fundamental piece of data accessible through the standardized OBD-II protocol. By using tools like Arduino, CAN bus shields, and the right code, enthusiasts can easily tap into this data for a wide range of exciting and practical automotive projects.

While the initial setup might require some troubleshooting, understanding the basics of OBD-II, CAN bus communication, and the code structure will empower you to successfully read vehicle speed and other valuable data from your car, opening up a world of automotive innovation and customization. Remember to start simple, debug systematically, and leverage the wealth of online resources and communities dedicated to OBD-II and Arduino projects.

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 *