APC Australia

Get real-time vehicle data with Python

Python is a computer language versatile enough to even read real-time data from your car’s engine control unit. Darren Yates explains how.

-

I’ve got a bit of a ‘car’ thing going on with my masterclas­ses this month, so it seemed fitting that we look at how you can code Python to read the On-Board Diagnostic (OBD-II) data from your car’s engine control unit (ECU) using a low-cost Bluetooth OBD-II dongle. We won’t go in-depth on OBD-II — you can read more details in my Android masterclas­s back on page 100. But we will assume you have a Windows PC or laptop with Bluetooth on-board, plus an ELM327-based Bluetooth OBD-II device.

PYTHON-OBD

Just briefly, OBD-II allows external scanners to read real-time data and ‘diagnostic trouble codes’ (DTCs) from a vehicle’s ECU and covers a huge range of parameters from vehicle speed to engine revs to fuel flow-rates. Mechanics use profession­al OBD-II diagnostic tools to check for correct brake operation during rego-checks.

What has this got to do with Python? Well, what makes Python so popular is not just how easy the language is to pick up, but the vast array of libraries available that make it easy to code up apps to do almost anything. One of those many libraries is ‘Python-OBD’ and it’s designed specifical­ly to allow you to read the data coming through your vehicle’s OBD-II port via low-cost ELM327-style Bluetooth-enabled dongles.

ELM327 COMMAND SET

Looking at these low-cost devices from a programmin­g perspectiv­e, there’s plenty going on. First, the microcontr­oller chip inside the dongle takes in data from the user through its Bluetooth wireless connection, which converts the data into the microcontr­oller chip’s required RS232 serial format. This format is very similar to old-style AT modem commands. The chip then converts those commands into OBD-II data commands and sends them to the ECU over the vehicle’s OBD-II data link. Return data coming back from the ECU is then re-converted from OBD-II back to RS232 format and transmitte­d to the user over the Bluetooth wireless connection.

So that we don’t have to code those AT modem-style commands directly, the Python-OBD library features applicatio­n programmin­g interfaces (APIs) to generate those commands and transmits them over your PC’s Bluetooth connection to the dongle.

We won’t go into the specific ELM327 AT command set here as it’s not really necessary. However, if you’re interested, you can read the table online ( tinyurl.com/y97apvfu).

PAIRING UP YOUR DEVICE

Now before we get into the coding proper, you’ll need to ensure that you pair up the OBD-II Bluetooth device with your PC’s Bluetooth adapter. In Windows 10, check the Task Tray for the Bluetooth icon, right-click on it, select ‘Show Bluetooth Devices’ from the context menu, choose the OBD-II device via the ‘Pair’ button and enter the password (usually ‘0000’ or ‘1234’). Next, jump into Device Manager, look under ‘Ports (COM & LPT)’ and find the COM port number being used by the OBD-II device (chances are it’ll be the highest number listed and not COM1 — that’s your mouse).

INSTALLING PYTHON-OBD

To give you an idea of our test setup, we used a 2012-era HP Pavilion dm4 notebook PC upgraded to Windows 10, with Python 3.6.1 installed and a lowcost ELM327-branded Bluetooth OBD-II dongle we purchased from eBay for about $5.

If you don’t have Python 3 yet, you can grab it free from www.python.org/ downloads. Python-OBD doesn’t come with the stock Python install, but you

can install it relatively easily using Python’s PIP3 utility.

Open up a command/DOS prompt in the folder \users\<username>\AppData\ Local\Programs\Python\Python36-32\ Scripts. You should find the ‘pip3’ script here. You can launch the command prompt in Windows Explorer — first, open up that folder, then while holding down the left Shift key, right-click on the folder space and choose ‘Open command window here’ from the context menu. Next, type in the command:

pip3 install obd

Pip3 is the ‘preferred installer program’ for Python version 3 — it automatica­lly knows where to find the various public-catalogued Python libraries, greatly simplifyin­g the process. When the installati­on is complete, you can shut down the command prompt window. To check the library has installed correctly, fire up Python and in the Python Shell, just type:

import obd

...and press the Enter key. If you don’t get an error message, excellent — you’re good to go. If you do, try repeating the process and check if you have conflictin­g versions of Python installed.

USING PYTHON-OBD

Now we’re ready to write some code. The first thing we need to do is import the library again using the ‘import obd’ statement. After that, we have to establish a connection with the Bluetooth OBD-II dongle plugged into the data link connector on your vehicle. You can try to create a connection object with the command:

connection = obd.OBD()

However, this didn’t work for us — we couldn’t get a link. To make it work with the ELM327-branded Bluetooth OBD-II dongle, we had to add in a few more parameters and expand this command to:

connection = obd.OBD (portstr=”COM8”,baudrate= 19200,fast= False)

We did have multiple Bluetooth devices paired (but not connected), which probably didn’t help, as we think the Python-OBD library probably got stuck on a COM port not in use. But by setting the COM port manually, setting the baud-rate and telling the OBD function to not implement its ‘fast’ option to speed up access, we were able to connect to the device. Remember, this is in addition to having previously paired the device with your PC’s Bluetooth adapter. If you haven’t done that, the rest of this won’t work.

Now once we have a connection, we’re ready to begin sending commands to the vehicle’s ECU. To do that, you send an OBDCommand using the ‘obd’ object we just created, the return data or ‘response’ comes back as an OBDRespons­e object.

It sounds more complicate­d than it is, so here’s an example command:

response = connection. query(obd.commands.SPEED)

What we’re doing is using the query function of the ‘connection’ object to send the command ‘obd.commands. SPEED’ and we’re expecting the return data to be deposited in the ‘response’ object. Another way you could do this is to put the command into an OBDCommand object and include that in the query, like this:

command = obd.commands.SPEED response = connection. query(command)

This is the way to do it if you want to programmat­ically select commands to send to the ECU. To print or obtain the data value in the response object, you can either assign the value or print it like this:

newSpeed = response.value. magnitude

print(response.value. magnitude)

For the most part, Python-OBD is a really simple library to use and shouldn’t take you long to get the hang of it.

But from a programmin­g perspectiv­e, the key thing is to be aware of how certain commands affect your program code flow. For example, execute the standard query function (like the one shown left) and your code will stop until a response comes back from your vehicle’s ECU — either the data you’re expecting, or nothing. Why nothing? As we mention in the Android Masterclas­s earlier in this issue, there’s no guarantee that every vehicle will support every OBD command.

For top-down command prompt/ terminal-style apps, code-blocking isn’t necessaril­y a deal-breaker, but for GUI apps, it’s a shocker because your GUI won’t respond to any mouse commands while it’s waiting.

So Python-OBD also comes with an alternativ­e query method called ‘asynchrono­us querying’ and what this does is to set up a new code stream or ‘thread’ separate from the standard GUI thread to allow you to send off commands separately, yet still have your GUI app operation continue as normal.

LIST OF PYTHON-OBD COMMANDS

If you’ve read the Android Masterclas­s this month where I talk about the Mode and PID numbers and having to send those across to the ECU, you don’t have to worry about that here — the PythonOBD library does all that leg-work for you. All you have to do is know the name of the command you want to send and for that, head to the Python-OBD doc ( python-obd.readthedoc­s.io).

FINDING COMMAND SUPPORT

But how do you identify which OBD commands a vehicle supports from those that it doesn’t? The answer is another Python-OBD function called ‘has_command()’. This function looks into the internal look-up tables of the Bluetooth device to see whether a particular command is supported, returning the result as a Boolean value, that is, it’ll return ‘true’ if it is supported and ‘false’ if it isn’t. For example:

print( obd.command.has_ command(obd.commands.SPEED) )

...looks up the OBD-II dongle to see if the ‘SPEED’ command is supported. The Boolean value returned is then displayed to the screen using the standard print() function.

OBD DATA RECORDER APP

Now that we’ve got the basic nuts and bolts worked out, we’re ready enough to build a small but useful data recorder app. The fact you can use these low-cost ELM327-style dongles to extract real-time data from the ECU

“What makes Python so popular is not just how easy the language is to pick up but the vast array of libraries available.”

means we can continuous­ly grab data and store it on file. For example, if we create a crude but simple .CSV (commasepar­ated-variable) file, we can capture data, import it into Excel or similar spreadshee­t app and graph the data. You can find our ODB-II Data Logger app source code on the website at apcmag.com/magstuff.

However, it’s about now just as you’re getting practical that problems usually crop up — and the issue here is that data transfer from the ECU to the OBD-II dongle isn’t instant. In fact, the data rates are, in some cases, as slow as old dial-up modems — in the kilobitspe­r-second range. So to keep things simple, we’re not going to try to force our app to capture a particular number of samples per minute. Instead, we’ll capture the time along with the sample data and store both in our CSV file. That way, we still have an option for accurately detailing when the data samples occurred, even if we don’t have full control to decide when they occur. But to prevent overloadin­g the ECU, we’ll also use the time.sleep() function to limit the sample rate to no more than two samples per second.

FILE I/O

We looked at how to use file operations back in the January 2017 issue of APC and the method we’re using here doesn’t have to be complicate­d. All we need is to open up a file for writing with a filename chosen by the user, write the data and close it when we’re done.

But a quick word of warning here — if the user chooses a file that already exists, the contents of that file will be wiped.

When then user presses the Enter key, the file is opened and we continue by opening up a connection to the OBD-II dongle. After confirmati­on of a connection, we begin sending commands to the dongle to hit the vehicle ECU for data using a loop. As the return data comes back, we format it, print it to the screen as well as add it to the CSV file.

However, in starting a loop, we also need some way to get out of it. We could choose a for-loop with a fixed number of samples, but a nicer way is to allow the user to press any keyboard key to exit the loop when they’re ready.

To do that, we tap into the low-level functions of Microsoft’s MSVCRT C++ runtime engine. The key function is mscvrt.kbhit(), which is a simple Boolean function that fires out ‘True’ if a key is pressed; ‘False’ if not. Making this the condition of a whileloop means we can take samples until the user decides they’ve had enough and presses a key. At that point, we close the CSV file and we’re done.

Note, too, that by using this Windows runtime engine, our code won’t run on Mac OS X or Linux systems.

IMPORT INTO EXCEL

Since we’ve created a basic CSV spreadshee­t file, importing it into your favourite spreadshee­t app is easy. From there, you can do whatever analysis you like, or you can just turn the data into pretty pictures like the one we’ve included here.

One important point — if we don’t use the ‘value.magnitude’ fields in writing data to the CSV file, we’ll end up with cells that also include the units, for example, ’45 kmh’, which aren’t typically helpful, so remember to use ‘magnitude’ field to get the value only.

BUYER BEWARE

We mentioned it earlier, but we’ll mention it again. We purchased two Bluetooth-enabled OBD-II dongles from eBay and, despite featuring different versions of ‘EM327’ firmware, they both worked and we were able to successful­ly run our Python code on an HP Pavilion dm4 notebook PC with Windows 10 and capture data.

However, we can’t guarantee these devices won’t ever cause issues with your vehicle. We tested our purchased units on a 2005 Mazda 3 sedan with no obvious ill effects and while these devices are designed to be ‘read only’, you take the risk — just remember ‘ buyer beware’.

 ??  ?? Make sure you have a Windows PC or laptop with Bluetooth adapter ready.
Make sure you have a Windows PC or laptop with Bluetooth adapter ready.
 ??  ?? The ELM327bran­ded Bluetooth dongle we purchased for $5 from eBay.
The ELM327bran­ded Bluetooth dongle we purchased for $5 from eBay.
 ??  ?? Our simple but practical OBD-II data logger for speed, RPM and engine-load.
Our simple but practical OBD-II data logger for speed, RPM and engine-load.
 ??  ?? You must have the ODB-II device plugged in and paired to your PC.
You must have the ODB-II device plugged in and paired to your PC.
 ??  ?? Run ‘pip3 install obd’ in the Scripts subfolder of your Python installati­on.
Run ‘pip3 install obd’ in the Scripts subfolder of your Python installati­on.
 ??  ?? If you can run ‘import obd’ in the Python Shell with no errors, you’re good.
If you can run ‘import obd’ in the Python Shell with no errors, you’re good.
 ??  ?? The Bluetooth password for most low-cost OBD-II devices is just ‘ 1234’.
The Bluetooth password for most low-cost OBD-II devices is just ‘ 1234’.
 ??  ?? Actual driving data captured by our data logger app and imported into Excel.
Actual driving data captured by our data logger app and imported into Excel.
 ??  ?? Don’t forget to pair the OBD-II device with your Windows PC via Bluetooth.
Don’t forget to pair the OBD-II device with your Windows PC via Bluetooth.
 ??  ?? Data logger output showing RPM, speed and engine-load.
Data logger output showing RPM, speed and engine-load.

Newspapers in English

Newspapers from Australia