Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
zhaoshentech
Published © CC BY

IoT4Car

MKR WiFi 1000 talks to a car through OBD-II interface, and uploads the data to IoT cloud for real-time monitoring and post-processing.

IntermediateFull instructions provided8 hours52,948
IoT4Car

Things used in this project

Hardware components

Arduino MKR1000
Arduino MKR1000
×1
SparkFun Logic Level Converter - Bi-Directional
SparkFun Logic Level Converter - Bi-Directional
×1
SparkFun OBD-II UART
×1
SparkFun OBD-II to DB9 Cable
×1

Software apps and online services

Arduino IDE
Arduino IDE
freeboard
dweet

Story

Read more

Schematics

IoT4Car

Connect Arduino MKR WiFi 1000, SparkFun OBD-II UART board, SparkFun Logic Level Shifter, and LCD 1602

Code

IoT4Car_code

C/C++
This program will talk to vehicle using the OBDII-UART board, and display the results on the LCD, and upload to freeboard IoT platform
/*
* OBDII-UART-Serial version 9
* This program will talk to vehicle using the OBDII-UART board, 
* and display the results on the LCD, and upload to freeboard IoT platform
* 
* Author: zhaoshentech
* Updated: 2018-08-27
* 
* updates:
*   v3: modified the getResponse() function so that the buffer receives the correct response.
*       add the getRPM() to get the engine RPM from the vehicle.
*   v4: add the getSpeed() function to get the speed of the vehicle
*   v5: add the LCD module and display the speed and RPM on the LCD
*   v6: is the wifi version
*   v7: is the non-wifi, non-serial version. Remove serial initialization,
*       so that the board can work without a computer.
*   v8: is the non-wifi, non-serial version. Add fuel level and coolant temperature.
*       rearrange the display location.
*   v9: is the wifi, non-serial version. Upolad speed, RPM, fuel level and coolant temperture
* 
* LCD circuit connection:
* LCD RS pin to digitial pin 12
* LCD Enable pin to digital pin 11
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3 
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10 K potentialmeter:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
*/

////////////////////////////////////////////////////////
//
// WiFi related 
//
///////////////////////////////////////////////////////
#include<SPI.h>
#include<WiFi101.h>
char ssid[] = "YOUR WIFI SSID";  // wifi ID
char pass[] = "YOUR WIFI PSWD";   // wifi password
char server[] = "www.dweet.io";  // freeboard and dweet Settings
unsigned long lastConnectionTime = 0; // track the last connection time
const unsigned long postingInterval = 10L * 1000L; // post data every 10 seconds
WiFiClient client; //Initialize the wifi client
int status = WL_IDLE_STATUS; // the WiFi radio status


// include the LDC libaray
#include <LiquidCrystal.h>
const int rs = 12, en = 11, d4 =5, d5 =4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

// This is a character buffer that will store the data from the serial port:
char rxData[20];
char rxIndex = 0;
char inChar = 0;
String message;

// Variables to hold the speed and the RPM data:
int vSpeed = 0;
int vRPM = 0;
int vFuel = 0;
int vTemp = 0;

void setup() {
  // Set up the LCD's number of columns and rows:
  lcd.begin(16,2);
  lcd.clear();

  // check the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    lcd.println("WiFi not ready");
    while(true);  
  }
  // attempt to connect to WiFi network:
  while (status != WL_CONNECTED) {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.println("Connecting WiFi...");
    status = WiFi.begin(ssid, pass);
    // wait for 5 second for the connection:
    delay(5000);
  }
  lcd.setCursor(0, 1);
  lcd.println("Connected!");
  
  // Serial1 is the acutal port to talk to vehicle
  Serial1.begin(9600);
  resetBuffer();
}

void loop() {
  while ( status != WL_CONNECTED) {
    lcd.clear();
    lcd.setCursor(0,0);
    // Connect to WPA/WPA2 Wi-Fi network
    Serial.println("Connecting to Wifi");
    lcd.println("Connect WiFi...");
    status = WiFi.begin(ssid, pass);
    // wait 10 seconds for connection
    delay(5000);
  }
  getSpeed();
  getRPM();
  getFuel();
  getCoolTemp();
  if (millis() - lastConnectionTime > postingInterval) {
      httpRequest();
      lastConnectionTime = millis();
   }
}

// getRPM data sends the "010C" command to the Serial1 port
// and call the getResponse() to collect the data. Then it prints
// the RPM data on the Serial Monitor.

void getRPM(void){
  message = "010C";
  Serial1.println(message);
  delay(200);
  //clear the current line
  for (int i = 8; i < 16; ++i)
  {
    lcd.setCursor(i, 0);  // 0 row, i column
    lcd.write(' ');
  }
  lcd.setCursor(8,0); // first row second half in the LCD screen
  //wait reponse
  getResponse();
  // The RPM response divided by 4 gives the correct value.
  vRPM = ((strtol(&rxData[6],0,16)*256) + strtol(&rxData[9],0,16))/4;
  lcd.print(vRPM);
  lcd.print(" rpm");
}


void getSpeed(void){
  message = "010D";
  Serial1.println(message);
  delay(200);
  //clear the current line:
  for (int i = 0; i < 8; ++i)
  {
    lcd.setCursor(i, 0); // 0 row, i column
    lcd.write(' ');
  }
  lcd.setCursor(0,0);// first row first half in the LCD screen
  //wait for the response from the car
  getResponse();
  vSpeed = strtol(&rxData[6], 0, 16); // in the unit of km/h
  vSpeed = vSpeed * 0.621371; // in the unit of mph
  lcd.print(vSpeed);
  lcd.print(" mph");
}

void getFuel(void){
  message = "012F";
  Serial1.println(message);
  delay(200);
  // clear the current line:
  for (int i = 0; i < 8; i++){
    lcd.setCursor(i, 1); // 1st row, i column
    lcd.write(' ');  
  }
  lcd.setCursor(0, 1); // second row first half in the LCD screen  
  //wait for the response from the car
  getResponse();
  vFuel = strtol(&rxData[6], 0, 16); // in the scale of 255
  //vFuel = 244; // debug usage
  vFuel = 1.0* vFuel / 255 *100; // in the scale of 100
  lcd.print(vFuel);
  lcd.print(" %");
  //Serial.println(vFuel); // debug usage
}

void getCoolTemp(void){
  message = "0105";
  Serial1.println(message);
  delay(200);
  // clear the current line:
  for (int i = 8; i < 16; i++){
    lcd.setCursor(i, 1); // 1st row, i column
    lcd.write(' ');  
  }
  lcd.setCursor(8, 1); // second row second half in the LCD screen  
  //wait for the response from the car
  getResponse();
  vTemp = strtol(&rxData[6], 0, 16); // in the unit of C but offset by 40 degrees
  vTemp = vTemp - 40; // offset by 0
  lcd.print(vTemp);
  // print the degree C
  lcd.write(0xDF);
  lcd.print("C");
}

// The getResponse function collects incoming data from the UART into the rxData buffer
// and exits when the response is transferred. Once the carriage return string
// is detected, the rxData buffer is null terminated (so that we can treat it as a string)
// and the rxData index is reset to 0 so that the next string can be copied.


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;
      }  
  }
}

void resetBuffer(void){
  for (int i = 0; i < 20; i++){
    rxData[i] = 0;  
  }
}

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");  
  }
}

Credits

zhaoshentech

zhaoshentech

6 projects • 81 followers
An enthusiastic for startups!

Comments