Tuesday, 9 July 2013

Raspberry Pi Reading Car Diagnostics (OBD-II) Data

I read about a guy called salgar on pistonheads.com who had used a raspberry pi to read data from his motorbike via an OBD-II USB reader and I thought, I've got to have a go at that.


OBD or On Board Diagnostics and OBD-II is a standard for communicating and reading data from a car, its standard across most modern cars and the likelihood is you have a connector in your car which you can read all sorts of data about the car such as RPM, Speed, Temperature and a million other things you wouldn't guess a car was monitoring.

Update - I've taken this prototype to the next stage and used the OBD data to overlay mph, rpm, temperature and throttle position over video taken with the camera board.


I got hold of a USB to OBD2 interface cable for about £10.  Pick one up from amazon.com or amazon.co.uk.


I then took a fork of salgar's software from his github repository, https://github.com/roflson/pyobd, as the basis for my program.  salgar's software is a fork from a project called pyobd, https://github.com/peterh/pyobd, which is a GUI based application for reading OBD-II data.

I used this as the basis for a program which would connect through OBD-II interface, 'ask' the car which sensors it supported and then read the data sensors in a loop every 0.5 second and write them to the screen.

I see this as step one in a project to log data about a car for other uses.

Download and run

You can download the code direct from githubhttps://github.com/martinohanlon/pyobd, so open a terminal and follow the instructions:

sudo apt-get install python-serial
sudo apt-get install git-core
cd ~
git clone https://github.com/martinohanlon/pyobd
cd pyobd
python obd_capture.py

68 comments:

  1. :O That is so cool! Maybe you can control the car with Raspberry Pi!

    ReplyDelete
    Replies
    1. That'll take a lot more work! I'll put it on the list tho.

      Delete
    2. Imagine what people could do with Raspberry Pi-powered cars... Heck, why not houses?? Snap of your fingers, you house lights up. xD

      Delete
    3. There are loads of raspberry pi home automation projects, just google it.

      Delete
  2. It works for volkswagen's car too?

    Look interesant!!

    ReplyDelete
    Replies
    1. I'm also intrested, because vag group use a can bus obd... I have a seat ibiza...

      Delete
    2. The reader I got says it supports any OBD-II standard including CAN. Exactly the same setup works on a BMW 3 Series.

      Delete
  3. I've managed to communicate with JLR cars with a raspberry Pi and SPI connected can analysis board. No GUI on it as such but has the ability to listen and broadcast CAN packets.

    ReplyDelete
  4. there is a similar project on going at http://awards.xee.com; main difference being the iPhone notification!

    ReplyDelete
  5. I have a Bluetooth adapter that I currently connect with my Nexus 4 and the "Torque" app- If I was to add a Bluetooth adapter to my Pi would it be able to see and connect in the same way?

    With one of these: http://learn.adafruit.com/adafruit-ultimate-gps-on-the-raspberry-pi it looks like I'd be able to get the same functionatlity as the torque/Android combination I currently use right?

    ReplyDelete
    Replies
    1. I dont know much about Torque, but if the bluetooth adapter appears as a serial device, then I dont see a reason why it wouldnt work.

      Delete
    2. Hi Edge

      Did you manage to get this working? I have been doing some testing today and I can pair my pi with a bluetooth dongle to my phone but torque is unable to find the obd2 through the pi. There are obd2 adaptors with bluetooth built in on ebay but I would like to do some messing around with the data on the pi as well as through torque which would be more for quick diagnostics.

      Delete
  6. Another question,can you show us an example of the output?

    I want to modify the script for redirecting the output also to a file, and it would be great if it will be in some kind of csv format...

    ReplyDelete
    Replies
    1. If you download the repository from github and look at salgar's original program obd_recorder.py, that is exactly what this does - writes the out of a limited number of sensors to a csv file. I've got other plans, getting data out was just my first step.

      Delete
    2. Hey Martin, great program man! (and to be fair, thanks to those who did work before you) I tried this python script previously on my mac, before realizing that it would be impossible (at least for me) to get it running because of sandboxing. Now I have a pi and a small screen installed in my car, and I can monitor rpm continuously. My next step will be to build a nice gui to give me a sweet revcounter, as my care doesn't have one, and then I'll be soo happy :D

      Delete
  7. could i do this with a arduino uno? or beaglebone black ?

    ReplyDelete
  8. Hi, i'm getting this error:

    File "/home/pi/pyobd/obd_io.py", line 25, in
    import serial
    ImportError: No module named serial

    There are some other module to install?

    ReplyDelete
    Replies
    1. Yes, you need to install pyserial. Google it.

      Ill update the post in a while with some instructions.

      Delete
    2. Solved with sudo apt-get install python-serial

      However is not working, it only read 2 data from the car, and i don't know what they are.

      i'm not sure if it's the software or the car (Seat Ibiza), i will try with a windows pc.

      Delete
    3. When you say 2 data, do you mean it only picks up 2 sensors? Could you paste the log, so I could have a look?

      Delete
  9. WOW amazing project! i was looking to do this someway! i was wondering can you use this to extract error codes from the car or does this only show RPM, temperature etc?

    ReplyDelete
  10. Yes, its just a question of sending different commands through the obd interface to the car. Check out the obd2 page on Wikipedia there's a good summary of the commands.

    ReplyDelete
  11. Hey Martin I just had a go at this using my pi and obd2 and testing via putty from in the house whilst the car ran outside. The script was running fine picking up sensors but then hit this error. I assume there is some invalid code coming out?

    supported sensor index = 21 o212
    supported sensor index = 28 obd_standard
    supported sensor index = 31 engine_time
    supported sensor index = 32 engine_mil_time
    boguscode?7F 12
    Traceback (most recent call last):
    File "obd_capture.py", line 86, in
    o.capture_data()
    File "obd_capture.py", line 68, in capture_data
    (name, value, unit) = self.port.sensor(sensorIndex)
    File "/home/pi/pyobd/obd_io.py", line 226, in sensor
    r = self.get_sensor_value(sensor)
    File "/home/pi/pyobd/obd_io.py", line 215, in get_sensor_value
    data = sensor.value(data)
    File "/home/pi/pyobd/obd_sensors.py", line 58, in sec_to_min
    code = hex_to_int(code)
    File "/home/pi/pyobd/obd_sensors.py", line 26, in hex_to_int
    i = eval("0x" + str, {}, {})
    File "", line 1
    0x
    ^
    SyntaxError: invalid token

    ReplyDelete
    Replies
    1. or a code which the pyobd program is not setup to understanding. Time for some debugging maybe!

      Delete
  12. Awesome! Do you know of any hardware to interface directly with a car/bike? Like read rpm from the reverse coil? Or is that what the obd 2 is? I'm thinking of older cars without an onboard computer.

    ReplyDelete
    Replies
    1. OBD 2 can do this, but for older cars / bikes which dont support it you are going to need something different. I've never had the need to look for one, but Im sure such a sensor exists.

      Delete
  13. Martin, excellent write-up. Have tried this but get the error detailed below, would you know why..? Thanks.

    Error:
    Opening interface (serial port)
    Interface successfully /dev/ttyUSB0 opened
    Connecting to ECU...
    atz response:ELM327 v1.5
    ate0 response:ate0OK
    0100 response:CAN ERROR
    Connected to /dev/ttyUSB0
    Traceback (most recent call last):
    File "obd_capture.py", line 86, in
    o.capture_data()
    File "obd_capture.py", line 39, in capture_data
    self.supp = self.port.sensor(0)[1]
    File "/home/pi/pyobd/obd_io.py", line 226, in sensor
    r = self.get_sensor_value(sensor)
    File "/home/pi/pyobd/obd_io.py", line 215, in get_sensor_value
    data = sensor.value(data)
    File "/home/pi/pyobd/obd_sensors.py", line 109, in hex_to_bitstring
    v = eval("0x%s" % i)
    File "", line 1
    0xR
    ^
    SyntaxError: invalid token

    ReplyDelete
    Replies
    1. You seem to be getting a response from the request to ask OBD what sensors are being supported that cant be converted from hex to a bitstring (e.g. 0x1A to 0010101010101).

      If you want to and see if you can move forward, modify the code to remove the stuff which finds the supported and unsupported sensors and hard code the supported sensor list. e.g. supportedSensorList = ["rpm", "speed", "temp"].

      Delete
    2. Hi, I got the same error

      ate0 response:ate0OK
      0100 response:CAN ERROR

      File "", line 1
      0xRROR
      ^
      SyntaxError: invalid token

      I tried change supportedSensorList but still not working. Any help? Thanks.

      Delete
    3. I keep getting the same error. It breaks because of the result "CAN ERROR". I can't seem to find what this error means.

      I have added a simple

      if data == "CAN ERROR":
      return "CANERROR"

      to get_sensor_value() in obd_io.py which stops the script from breaking. After that it just shows the time but no sensor values. Any idea what the problem could be?

      Delete
    4. Sorry guys. I can only guess that car manufacturers implementation of the OBD2 standard isn't always 'standard'!

      Delete
  14. This was really simple to follow, great stuff. However I've got a similar problem to the one above I'm afraid. Do I need to manually configure the supportedSensorList as well or might this be something else.

    ['/dev/ttyUSB0']
    Opening interface (serial port)
    Interface successfully /dev/ttyUSB0 opened
    Connecting to ECU...
    atz response:atzELM327 v1.5
    ate0 response:ate0OK
    0100 response:41 00 98 18 80 01 41 00 98 3B 80 19
    Connected to /dev/ttyUSB0
    Traceback (most recent call last):
    File "obd_capture.py", line 86, in
    o.capture_data()
    File "obd_capture.py", line 49, in capture_data
    self.unsupportedSensorList.append([i+1, obd_sensors.SENSORS[i+1]])
    IndexError: list index out of range

    ReplyDelete
    Replies
    1. Its difficult to be sure, but I think you are getting an error due to OBD reporting more sensors than the exist in the pyobd SENSORS list. You could also hardcode the sensors to monitor and do away with this bit of code, or change it to handle the error.

      Delete
    2. I was having this same issue! The first thing I did was print out the size of the entire sensorlist and a counter to see where it was stopping using:

      print(len(self.supp))

      This showed me that it was stopping at index 33 of self.supp. yet for some reason its length would print out as 80. I just changed the loop to run from 0 till 32(length of the sensor[] in obd_sensors.py and everything is perfect.

      'for i in range(0, 32):' instead of 'for i in range(0, len(self.supp)):'

      If anyone can explain this I would love to know! Good Luck!

      Delete
    3. I see, I suspect what is happening is that your car is returning the string of zero's and one's representing the supported sensors but it is padding it with whitespaces up to the maximum, which presumably is 80.

      Delete
  15. an you read the error codes too if so how?

    ReplyDelete
    Replies
    1. I dont read the error codes in this example, but I think you can, the obd_io class in obd_io.py has a method called get_dtc() which looks like it should return the Diagnostic Trouble Codes (DTC). Have a go let me know how you get on. There is also a class called pcodes in obd2_codes.py which provides a dictionary of codes and descriptions.

      Delete
  16. GM has it's own special unicorn blood codes that the guys at Autozone can never read with their code readers any chance someone with this setup has a GM?

    '05 Saturn Vue here...

    ReplyDelete
  17. I am curious to know if I can add sensors to be supported. Since the list of sensors is written out in obd_sensors.py like this: ' Sensor("rpm" , " Engine RPM", "010C1", rpm ,"" )'
    How would I find this information for other sensors? For example if my car had a sensor for bumper temperature, would I be able to add it? How?

    ReplyDelete
  18. Have a read of http://en.wikipedia.org/wiki/OBD-II_PIDs it describes all the sensors (parameter ids) which are in the standard, although they may not all be supported by a car.

    There are also non standard pids which tend to be proprietary to each manufacturer and there is usually very limited information about them, however i beleive that even they are readable by the same hardware its just whether you can find out how and how to interpret the result

    ReplyDelete
  19. DId you get any 'NameError: name 'DATAERROR' is not defined' problems when you were testing this out?

    ReplyDelete
    Replies
    1. No sorry i didnt see that error, have you got any more info? When does the error occur, could you cut and paste the whole error message?

      Delete
    2. I'm afraid I don't have the full error handy (though sometimes DATAERROR would be followed by some numbers, like DATAERROR410303 for instance). The error seemed to originate from def get_sensor_value on line 215, I suppose the script can't handle whatever my car (2001 Mustang GT) is returning, what do you think?

      Delete
  20. Hi Martin,
    I'm excited to use this code. I never wanted a UI anyway I just want to log to a file and mine it later. I'm getting an SSL error when I try to clone the git repo:

    error: SSL: certificate subject name (*.opendns.com) does not match target host name 'github.con' while accessing https://github.con/martinohanlon/pyobd/info/refs
    fatal: HTTP request failed

    ideas? Thanks,
    --Mike

    ReplyDelete
    Replies
    1. github.coN rather than github.coM looks kind of suspicious, is this just a typo or have you copied the url incorrectly?

      Delete
  21. I have the same OBD II reader except its the bluetooth version, I am having no luck connecting it. I have paired it and set it as a serial device. When I run the program all I am getting is "Not connected". Any tips ...?

    ReplyDelete
    Replies
    1. Other than checking the simple stuff like making sure you have got the right serial device, no not really, i have tried to do this with a bluebooth device.

      Delete
  22. I have made quite a few modifications to the project you made available such as support and interpretation of more sensors, this was a very fun project. But there is one thing that I cannot seem to get; How do I tell the make/model of the vehicle via OBDII?

    So far I have not been able to find any documentation regarding this feature. It must be possible. Any suggestions?

    ReplyDelete
    Replies
    1. This would be greatly helpful so that I could create a database of vehicles and their drivers based on make/model/VIN.

      Delete
    2. According to wikipedia, you should be able to get VIN using Mode $09:

      http://en.wikipedia.org/wiki/On-board_diagnostics#OBD-II

      Mode $09 is used to retrieve vehicle information. Among others, the following information is available:
      - VIN (Vehicle Identification Number): Vehicle ID

      Would you mind sharing your code?

      Delete
    3. Thank you! I will share my code as soon as my project is wrapped up.

      Delete
  23. Hi Martin,

    I'm getting this error, do you know how it can be fixer ? :

    pi@raspberrypi ~/pyobd $ python obd_capture.py
    Traceback (most recent call last):
    File "obd_capture.py", line 81, in
    o.connect()
    File "obd_capture.py", line 18, in connect
    portnames = scanSerial()
    File "/home/pi/pyobd/obd_utils.py", line 9, in scanSerial
    s = serial.Serial(i)
    File "/usr/local/lib/python2.7/dist-packages/serial/serialutil.py", line 282, in __init__
    self.open()
    File "/usr/local/lib/python2.7/dist-packages/serial/serialposix.py", line 289, in open
    self.fd = os.open(self.portstr, os.O_RDWR|os.O_NOCTTY|os.O_NONBLOCK)
    OSError: [Errno 2] No such file or directory: '/dev/ttyS0'


    Thanks a lot

    ReplyDelete
    Replies
    1. Your getting the error because the serial port ttyS0 isnt setup properly.. Why is a totally different question!

      Delete
    2. Hey I'm having the same issue and struggling to fix it, any ideas?

      Delete
    3. If you're having problems with the Serial port setup I would recommend following this link on Debian's forums. It really helps to explain the process and utilization of the correct commands for setting up and linking the USB to any Serial port you would like to use. http://forums.debian.net/viewtopic.php?f=16&t=61943

      Delete
  24. Hi, love your OBDII project. I have really only just stumbled across the PI . such a wonderful creation, man if only we had this back when I was at college, instead of messing about with duff circuits & stuff that would take 90% of time to get functioning and 10% of the lesson to do some simple task.

    I wondered with your Pi OBDII reader , given that it has a Lan port, - would it be possible to have it connected via a smartphone to the web and then write the obd readings at intervals while you are driving the car on the track into a SQL table on the web. which then could be viewed by someone logged on to the SQL table (and wizzy interface) (on their laptop or phone at the side of the track) That would be interesting.

    ReplyDelete
  25. Awesome btw I am planing to have a sound activation in the system .. am not sure where to start , unlock the car .. do u think it is plausible?

    ReplyDelete
    Replies
    1. It certainly sounds plausible to unlock the car, providing you can hook into the unlock mechanism. I suspect on older cars, this will be much easier than modern. So in summary, it probably depends on the car.

      Delete
  26. Hi Martin, can you please help me with my connection. When I try to record the data i get the following error. Can you please help me.

    Opening interface (serial port)
    Interface successfully /dev/ttyUSB0 opened
    Connecting to ECU...
    Got nothing

    Got nothing

    Got nothing

    Got nothing

    Got nothing

    atz response:atz

    Got nothing

    Got nothing

    Got nothing

    Got nothing

    Got nothing

    ate0 response:ate0

    Got nothing

    Got nothing

    Got nothing

    Got nothing

    Got nothing

    0100 response:0100

    Traceback (most recent call last):
    File "obd_capture.py", line 81, in
    o.connect()
    File "obd_capture.py", line 29, in connect
    print "Connected to "+self.port.port.name
    AttributeError: 'Serial' object has no attribute 'name'

    Regards from Munich...

    ReplyDelete
    Replies
    1. Its not an error I have seen before... Have you got the latest version of software, particularly pySerial? You could just comment out that line and see if it continues, its only a debug line to show which serial port you are connected too.

      Delete
  27. Hi Martin,
    This project is awesome! I have just set it up in my car and the OBDII USB is all talking, but all I get is a running datestamp without the data. Looking at your write-up on the video overlay I can see your example csv file matches mine minus the data! Is it possible my car isn't talking or that I don't have the right pid codes? I'd expect to see something more that just datestamps, jibberish even?
    Help much appreciated! Your work is awesome!

    ReplyDelete
    Replies
    1. I wonder if the program is running but the OBD-II interface isnt returning any sensors on the supported sensors PID.

      If you look at the obd_capture.py program, there is a line which says:

      print "supported sensor index = " + str(supportedSensor[0]) + " " + str(supportedSensor[1].shortname)

      Does this print anything?

      Delete
    2. Cheers for the reply Martin, no that doesn't appear. The output is this:

      ['/dev/ttyUSB0']
      Opening interface (serial port)
      Interface successfully /dev/ttyUSB0 opened
      Connecting to ECU...
      atz response:atzELM327 v1.5
      ate0 response:ate00K
      0100 response:NO DATA
      Connected to /dev/ttyUSB0
      11:25:9.14550
      [date stamps continue thereafter]

      I'm guessing the atz and ate response are showing the ECU is talking in a basic sense, but the 0100 response is what's throwing things off?

      Any help very welcome!

      Delete