When driving your vehicle, glancing at your dashboard, have you ever thought of collecting the meter readings and do some analysis? These data may contain hidden treasures. For individuals, it can reflect your driving habits, it can tell you your speed, your average mpg, how many traffic lights you have, and your waiting time at each cross. For companies, these data are critical for real-time monitoring in fleet management. Vehicle condition, work load distribution, gasoline efficiency, and even vehicle location can all be fed back to a central control system through cloud. Companies can use machine learning to feed the data into a training model to predict the cost and even analyze the driver's characteristics. As IoT is widely spreading, the above applications won't be far away. With the Arduino MKR boards, targeting at IoT applications, you can build a device that talks to your car and uploads telemetric data into cloud all by yourself. Isn't that cool?
Talking to a vehicleWe need an interface to access into the vehicle system. Where can we hack into the car? The answer is OBD-II interface.
What is OBD-II?
On-Board Diagnostics (OBD) is a vehicle's built-in self-diagnostic system, through which we can communicate with our cars. It was first introduced in United States in 1994, and became a requirement on all 1996 and newer US vehicles. Other countries, including Canada, parts of the European Union, Japan, Australia, and Brazil adopted similar legislation. OBD-II (second generation) has five signaling protocols, and Controller Area Network (CAN bus) is one of them. CAN bus is required to be implemented in all the US cars since 2008. There is a great introduction of OBDII provided by CSS Electronics on Youtube. In this project, we will access data through the 16 pin OBD-II interfaces.
My controller
Arduino is an excellent platform for hobbyists, makers, and professionals. It has a variety of boards targeting at different applications. Here I use the Arduino MKR WiFi 1000 board due to its WiFi capability. Your can also use other boards that you like. I would recommend Arduino MKR GSM 1400, simply because GSM covers much wider areas than WiFi does. But don't worry, even with WiFi we can have internet access along the roads. I will show you the workaround.
The interpret board
Although Arduino itself has plenty of I/Os and numerous libraries, we still need a board that can translate OBD protocols into a language that Arduino can recognize. The board that I use is the SparkFun OBD-II UART Board.
This board allows you to interface with your car’s OBD-II bus. It provides you a serial interface using the ELM327 command set and supports all major OBD-II standards such as CAN. The board contains an STN1110 chip, which is an OBD to UART interpreter that can be used to convert messages between any of the OBD-II protocols currently in use, and UART.
However, it should be pointed that the interpret board has an I/O voltage of 5 V, which may damage the Arduino MKR board I/O, if connecting them directly. Arduino MKR WiFI 1000 runs at a lower voltage and its I/O voltage is 3.3 V. Therefore, a level shifter is needed to convert signal from 5 V to 3.3 V and visa versa. Below is the image of the level shift that I use.
Hook it up
Hooking up the circuit is pretty easy. Simply connecting your Arduino MRK pin 13 Rx and pin 14 Tx, to OBD-II UART board Tx and Rx pins through the level shifter. Of course, you need to connect the ground of the two boards together.
To ease debugging and demonstration, I also connected a LCD 1602 screen to Arduino to display the data in real-time. The LCD to Arduino wiring can be found to this tutorial, and thus will not be elaborated here.
Below is the image of the breadboard connection. The green lines are for the wires connecting the Arduino and the OBD-II UART board, while the yellow lines are for the wires connecting the Arduino and the LCD. The schematic is also available in the attachment.
The real connection is a bit messy due to the limited bread board area, but it follows the above schematic. I included the micro USB and ODB-II to DB9 cable in the picture.
Serial1 not Serial
All right, it is time to program our Arduino MKR board. Since my Arduino MKR board talks with the interpret board through UART, there is no need to install 3rd party libraries. Sending commands to the interpret board is simply like communicating with Serial Monitor. The only thing that I want to emphasize is that the serial port associated with Pin 13 and Pin 14 is Serial 1! Arduino MKR board Serial port refers to its USB port which is used to communicate with your computer. Don't forget to initialize Serial 1 port in the setup() function.
Serial1.begin(9600);
And use Serial 1 to push command to the interpret board.
Serial1.println(message);
Messages
As you see, I use the variable "message" to store the commands. The OBD commands are made up of hexadecimal codes written in ASCII characters. The first two hexadecimal numbers refer to the service mode to be used. There are 10 diagnostic services described in the latest OBD-II standard SAE J1979. Since we are interested in real-time monitoring, we will only use 01 code to show current data in this project.
Any hex number after the service mode represents the Parameter ID (PID) to achieve special functions. Below is the screenshot of the PIDs in 01 service mode. More information can be found in Wikipedia.
In this project, I will demonstrate how to get the car speed, the engine RPM, the fuel level, and the engine coolant temperature. The OBD commands for these four functions are:
- 010D // car speed
- 010C // engine RPM
- 012F // fuel level
- 0105 // coolant temperature.
Decode the data
Once the commands are sent out, Arduino MKR board will listen to Serial 1 port for any response. It is better to put a delay of 200 ms after sending out the commands. I use the following code to receive response.
void getResponse(void){
while(Serial1.available() > 0) {
// Start by checking if we've received the end of message character ('\r').
if(Serial1.peek() == '\r'){
// reach the end of the message, clear the Serial buffer
inChar = Serial1.read();
rxData[rxIndex] = '\0';
// Reset the buffer index so that the next character goes back at the beginning of the string
rxIndex = 0;
}
// If we didnt get the end of the message character, just add the new character to the string
else{
// Get the new character from the Serial port:
inChar = Serial1.read();
// add the new character to the string, and increase the index variable:
rxData[rxIndex++] = inChar;
}
}
}
The response from the interpret board follows the format
">1 Repeated PIDs Data"
For example, in the above screenshot, I send out "010D" to get the car speed. The response is ">1 0D 00". The first 5 characters show that the car receives the command and repeats the PID 0x0D back. The last two digits return the speed data 0x00.
Then I send out "010C" to get the engine RPM, the response ">1 0C" shows the acknowledge of the command, the data 0x098C is 4 times the engine RPM value in hexadecimal. 0x098C / 4 = 611 dec, so the engine RPM is 611 rpm.
After that, I send out command "012F" to get the fuel level, and I get data 0x1D. The fuel level is calculated as 0x1D / 255 * 100 = 11% dec.
The final command is "0105", which gives me the coolant temperature 0x79. The real temperature is 0x79 - 40 = 81 degreeC dec. Then the command sequence repeats itself.
As you can see, the response line has spaces between two hexadecimal digits, and the first 5 digits is simply repeating the commands. Therefore, the real data starts from the 6th character (first one starts from 0 index).
In programming and debugging, a serial monitor is helpful, but when it comes to real application, a LCD screen is more portable and it meets the IoT power requirement. Simply replace the serial monitor with a LCD screen, you can monitor your car data in real time. Below is the photo of using the project in my own car.
The advantage of the Arduino MKR over UNO is its internet accessibility. Targeting at IoT application, Arduino MKR will make industries more intelligent and connective. In the automotive applications, MKR WiFi 1000 may not be the best board since WiFi signal is rare in outdoor environment, but I use my cell phone as a personal hotspot, so it's not a problem.
There are a lot other cloud platforms to store, view, and post process the data. You can choose whatever you like. I will to use dweet.io and freeboard.io as an example. Dweet.io provides API that you can send data to. Freeboard.io has handles to take the dweet.io data and visualize them. There are several tutorials to set up dweet.io and freebboard.io, so I won't elaborate again. If you are interested, here are some examples, example 1, example 2.
The data push code is exhibited below as an illustration how to create dweet commands.
void httpRequest() {
client.stop();
// create data string to send to freeboard
if (client.connect(server, 80)){
Serial.println("Connected");
String data = "POST /dweet/for/mkr1000?RPM=";
data.concat(vRPM); // upload engine RPM
data.concat("&Speed=");
data.concat(vSpeed); // upload car speed
data.concat("&Fuel=");
data.concat(vFuel); // upload fuel level
data.concat("&Temp=");
data.concat(vTemp); // upload coolant temperature
client.println(data);
client.println("Host: https://www.dweet.io");
client.println("Connection: close"); // end of connection
client.println();
}
else {
lcd.clear();
lcd.setCursor(0,0);
lcd.println("Connection failed");
}
}
On freeboard.io, we need to create a new dashboard, and inside this dashboard, create a new datasource. Link this datasource to your dweet.io thing that you defined in the code. In my case, it is mkr1000. The create a new Gauge widget that we will use to display the data. Give it a name, and link it to one of our variables. Below is a screenshot of my dashboard. It shows SPEED, RPM, FUEL LEVEL, and COOLANT TEMPERATURE.
I tried the boards on my own car, and it works well. I am working on designing a PCB that includes all the functions in an integrated circuit. Hopefully, I will write more tutorials in the future. I may include a video demo as well. Sorry this time, I couldn't take video as well as driving my car. And you also want to be careful when debugging your code while driving on the street!
Arduino MKR WiFi board is good enough for this application. If I have more boards, I think I could try MKR GSM 1400 board. Feel free to use other IoT boards with this tutorial and tell me your feedback.
Working on the project is fun and educative. I enjoy the feeling of debugging a problem. It is also my pleasure to share what I know on the web. Thank you for reading. Let me know if you have any questions or comments.
Comments