For automotive enthusiasts and DIY tinkerers, the fusion of Arduino, OBD2, and Android opens up a world of possibilities for custom car diagnostics and data monitoring. Imagine tapping directly into your vehicle’s onboard systems, pulling real-time sensor data, and visualizing it all on your Android device. This is precisely what can be achieved with an Arduino-based OBD2 interface and an Android application like Torque Pro.
This guide delves into how you can leverage Arduino as a versatile OBD2 adapter to send custom sensor data to your Android phone. We’ll explore the fundamental code that bridges this gap, allowing you to monitor parameters beyond the standard OBD2 readings, all displayed conveniently on your Android dashboard.
Understanding OBD2 and Arduino’s Role
OBD2 (On-Board Diagnostics II) is a standardized system in modern vehicles that provides access to various engine and vehicle parameters. Typically, you’d use a dedicated OBD2 scanner tool to read this data. However, Arduino, with its flexibility and vast ecosystem, can act as a custom interface, especially when you want to incorporate sensors and data points beyond the standard OBD2 protocol.
Why choose Arduino for OBD2 projects?
- Custom Sensor Integration: Arduino excels at reading data from a wide array of sensors – temperature, pressure, accelerometers, and more. You can feed this data into your OBD2 stream, enriching the information available.
- Flexibility and Control: Unlike fixed OBD2 scanners, Arduino allows you to program custom logic, manipulate data, and tailor the system to your specific needs.
- Cost-Effectiveness: Arduino boards and basic components are relatively inexpensive, making DIY car diagnostics accessible to hobbyists.
- Open Source and Community Support: The Arduino ecosystem boasts a massive community and abundant open-source resources, simplifying development and troubleshooting.
Arduino Code: Bridging OBD2 and Android with Torque
The provided Arduino code serves as a foundational example of how to establish communication between an Arduino board and an Android OBD2 application, specifically Torque Pro. Let’s break down the key sections of this code:
1. Includes and Constants:
#include <SoftwareSerial.h>
#include <string.h>
/**
* Torque for Android Arduino sample program by Ian Hawkins http://torque-bhp.com/
* ... (rest of the header comments) ...
*/
// Various constants.
const String ATE = "ATE"; // Echo off/on
const String ATI = "ATI"; // Version id
const String ATZ = "ATZ"; // Reset
const String ATS = "ATS"; // Set protocol X
const String ATH = "ATH"; // Headers off / on
const String ATL = "ATL"; // Linefeeds off/on
const String ATM = "ATM"; // Memory off/on
const String GETDEFINITIONS = "GETDEFINITIONS"; // Get sensor definitions
const String GETCONFIGURATION = "GETCONFIGURATION"; // Get config of app (hide car sensors, devices sensors, etc)
const String GETSENSORS = "G"; // Get sensor values, one shot.
const String SETSENSOR = "S"; // Set a sensor value
const String PROMPT = ">";
const String CANBUS = "6"; // canbus 500k 11 bit protocol id for elm.
const String ATDPN = "ATDPN";
const String ATDESC = "AT@1";
const String ATAT = "ATAT";
const String LF = "n";
const String VERSION = "Torque Protocol Interface v0.0.1"; // Don't change this - it's used by Torque
const String VERSION_DESC = "Torque For Android Protocol Interface";
const String OK = "OK";
const String ANALOG = "a";
const String DIGITAL = "d";
const String IS_INPUT = "i";
const String IS_OUTPUT = "o";
String fromTorque = "";
#include <SoftwareSerial.h>
: This line includes the SoftwareSerial library, essential for creating a serial communication port on Arduino pins other than the default serial pins (0 and 1). This is crucial because we’ll be using pins 2 and 3 for Bluetooth communication, freeing up the hardware serial port for debugging if needed.#include <string.h>
: Includes the string manipulation library, useful for handling string data.- Constants: The code defines various constants representing AT commands (common commands for communication with OBD2 adapters and Bluetooth modules) and protocol-specific strings used for interaction with the Torque app. These constants streamline the code and make it more readable.
GETDEFINITIONS
,GETSENSORS
, andSETSENSOR
are particularly important as they define how Torque requests sensor information and sends commands back to the Arduino.
2. Sensor Definitions:
/**
* Array of sensors we will advertise to Torque so it can automatically import them. Using strings
* Stucture is:
*
* Arduino Pin, Arduino pin type, Input/Ouput, Default value(if output), ShortName, Long name, units, minimum value, maximum value
*
* Caveats: Don't use a '>' in any of the names,
* Update 'sensorsSize' with the number of elements.
* Analog outputs are PWM on digital pins.
*/
const int SENSORSSIZE = 9 * 3; // each line is 9 attributes, and we have 3 lines.
const String sensors[SENSORSSIZE] = {
"0", ANALOG, IS_INPUT, "-", "Boost", "Boost", "PSI", "0", "5",
"1", ANALOG, IS_INPUT, "-", "EGT", "Temp", "F", "0", "5",
"4", DIGITAL,IS_OUTPUT, "0", "Dout1", "Digital Out 1", "bit", "0", "1"
};
-
sensors
array: This is the heart of the custom sensor definition. It’s a string array that tells Torque about the sensors Arduino is providing. Each sensor is defined by 9 attributes:- Arduino Pin: The pin number on the Arduino board connected to the sensor.
- Arduino Pin Type:
ANALOG
orDIGITAL
, indicating the type of pin. - Input/Output:
IS_INPUT
orIS_OUTPUT
, specifying if the sensor is providing input to Arduino or receiving output from it (for control purposes). - Default Value (if output): The initial value for output pins.
- Short Name: A concise name for the sensor (e.g., “Boost”).
- Long Name: A more descriptive name (e.g., “Boost Pressure”).
- Units: The unit of measurement (e.g., “PSI”, “F”).
- Minimum Value: The minimum expected sensor reading.
- Maximum Value: The maximum expected sensor reading.
Important: To add more sensors, you need to append new sets of these 9 attributes to the
sensors
array and update theSENSORSSIZE
constant accordingly.
3. Configuration Directives:
/**
* Configuration directives for the app to hide various things. Comma separated. Remove to enable visibility in Torque
* - handy if your project isn't car related or you want to make sensor selections relatively easy.
*
* Supported types:
* NO_CAR_SENSORS - hide any car related sensors
* NO_DEVICE_SENSORS - hide any device (phone) sensors
* */
const String CONFIGURATION = "NO_CAR_SENSORS,NO_DEVICE_SENSORS";
CONFIGURATION
constant: This string allows you to control which sensor categories are displayed in the Torque app.NO_CAR_SENSORS
andNO_DEVICE_SENSORS
hide the default car and phone sensors in Torque, respectively, making it cleaner to focus on your custom Arduino sensors. You can remove these directives to show all sensor categories if desired.
4. SoftwareSerial Setup:
// Setup bluetooth module on pins 2 and 3 (you can't use these digial pins in the sensor list or it'll break comms)
SoftwareSerial mySerial(2,3); // Most other boards can use pins 2 and 3
//SoftwareSerial mySerial(8,9); // Use pins 8,9 on Arduino Micro
SoftwareSerial mySerial(2,3);
: This line initializes a SoftwareSerial object namedmySerial
using digital pins 2 and 3 for serial communication. Pin 2 is defined as the RX (receiver) pin, and pin 3 as the TX (transmitter) pin for the Arduino in relation to the Bluetooth module. This setup is crucial for communicating with a Bluetooth module that will wirelessly transmit data to your Android device.
5. setup()
Function:
void setup() {
// Init the pins
initSensors();
Serial.begin(9600); // the GPRS baud rate - comment likely incorrect, should be serial monitor baud rate
delay(600);
mySerial.begin(9600);
}
initSensors();
: This function (defined later in the code) initializes the Arduino pins defined in thesensors
array, setting them as inputs or outputs and setting default output values.Serial.begin(9600);
: Initializes the hardware serial communication for debugging via the serial monitor at a baud rate of 9600. Note: The comment “the GPRS baud rate” is likely inaccurate and should refer to the serial monitor connection.delay(600);
: A short delay to allow the serial connection to initialize.mySerial.begin(9600);
: Initializes the software serial communication (mySerial
) for Bluetooth communication, also at 9600 baud rate. Make sure your Bluetooth module is configured to the same baud rate.
6. loop()
Function:
void loop() {
/**
* Grab data from the bluetooth module, parse it.
*/
if (mySerial.available()) {
char c = mySerial.read();
if ((c == 'n' || c == 'r') && fromTorque.length() > 0) {
fromTorque.toUpperCase();
processCommand(fromTorque);
fromTorque = "";
} else if (c != ' ' && c != 'n' && c !='r') {
// Ignore spaces.
fromTorque += c;
}
}
}
mySerial.available()
: Checks if there is data available to read from the Bluetooth serial port.mySerial.read()
: Reads a character from the Bluetooth serial port.- Command Parsing: The code accumulates characters into the
fromTorque
string until a newline (n
) or carriage return (r
) character is received. This signifies the end of a command sent from the Torque app. fromTorque.toUpperCase();
: Converts the received command to uppercase for case-insensitive command processing.processCommand(fromTorque);
: Calls theprocessCommand
function to handle the received command.fromTorque = "";
: Clears thefromTorque
string to prepare for the next command.
7. processCommand()
Function:
/**
* Parse the commands sent from Torque
*/
void processCommand(String command) {
// Debug - see what torque is sending on your serial monitor
Serial.println(command);
// Simple command processing from the app to the arduino..
if (command.equals(ATZ)) {
initSensors(); // reset the pins
mySerial.print(VERSION);
mySerial.print(LF);
mySerial.print(OK);
} else if (command.startsWith(ATE)) {
mySerial.print(OK);
} // ... (other AT command handling) ...
else if (command.startsWith(GETDEFINITIONS)) {
showSensorDefinitions();
} else if (command.startsWith(GETSENSORS)) {
getSensorValues();
} else if (command.startsWith(GETCONFIGURATION)) {
getConfiguration();
} else if (command.startsWith(SETSENSOR)) {
setSensorValue(command);
}
mySerial.print(LF);
mySerial.print(PROMPT);
}
- Command Dispatch: This function is the command interpreter. It receives commands from Torque (as strings) and executes the corresponding actions.
- AT Command Handling: It handles basic AT commands like
ATZ
(reset),ATE
(echo control),ATI
(identification), and others, responding with “OK” or version information as expected by OBD2 interfaces and Torque. - Torque-Specific Commands: It handles commands crucial for Torque integration:
GETDEFINITIONS
: CallsshowSensorDefinitions()
to send the sensor definitions (from thesensors
array) to Torque.GETSENSORS
: CallsgetSensorValues()
to read sensor values and send them to Torque.GETCONFIGURATION
: CallsgetConfiguration()
to send configuration directives to Torque.SETSENSOR
: CallssetSensorValue()
to handle commands from Torque to set the value of an output sensor on the Arduino.
Serial.println(command);
: This line is for debugging. It prints the received command to the serial monitor, allowing you to see what Torque is sending.- Prompt:
mySerial.print(LF); mySerial.print(PROMPT);
sends a newline and a prompt character (“>”) back to Torque after each command, signaling that Arduino is ready for the next command.
8. showSensorDefinitions()
Function:
/**
* List all the sensors to the app
*/
void showSensorDefinitions() {
int id = 0;
for (int i = 0; i < SENSORSSIZE/9; i++) {
for (int j = 0; j < 9; j++) {
id = (i*9)+j;
mySerial.print(sensors[id]);
if (id+1 < SENSORSSIZE) {
mySerial.print(',');
}
}
mySerial.print(LF);
}
}
- Sensor Definition Transmission: This function iterates through the
sensors
array and sends the sensor definitions to Torque in a comma-separated format, with each sensor’s attributes separated by commas and each sensor definition ending with a newline character. This is how Torque learns about the custom sensors Arduino is providing.
9. getSensorValues()
Function:
/**
* Dump sensor information for input sensors.
*
* Format to Torque is id:type:value
*/
void getSensorValues() {
for (int i = 0; i < SENSORSSIZE/9; i++) {
int group = i * 9;
int id = sensors[group].toInt();
String type = sensors[group+1];
boolean isOutput = sensors[group+2].equals(IS_OUTPUT);
if (!isOutput) {
mySerial.print(id);
mySerial.print(":");
mySerial.print(type);
mySerial.print(":");
if (type.equals(ANALOG)) {
if (i==0) { //Boost sensor - Example conversion
mySerial.print((((analogRead(id)*5.1/1024)/(5.1)-0.04)/0.009)*0.145); //Example boost sensor conversion
}
else if (i==1) { //EGT sensor - Example raw reading
mySerial.print (analogRead(id)); //Example raw analog read
}
}
else if (type.equals(DIGITAL)) {
mySerial.print(digitalRead(id));
}
mySerial.print('n');
}
}
}
- Sensor Value Transmission: This function reads the values from the input sensors defined in the
sensors
array and sends them to Torque. - Sensor Type Handling: It distinguishes between
ANALOG
andDIGITAL
sensors and reads the appropriate values usinganalogRead()
anddigitalRead()
. - Example Conversions: The code includes example conversions for the “Boost” and “EGT” sensors. The boost sensor example shows a specific voltage-to-pressure conversion, highlighting that you’ll need to customize these conversions based on your actual sensors. The EGT sensor example shows a raw analog reading.
- Data Format: Sensor values are sent in the format “id:type:value” followed by a newline character, as expected by Torque.
10. setSensorValue()
Function:
/**
* Sets a sensors value
*/
void setSensorValue(String command) {
int index = command.indexOf(":");
int id = command.substring(1,index).toInt();
int value = command.substring(index+1, command.length()).toInt();
for (int i = 0; i < SENSORSSIZE/9; i++) {
int group = i * 9;
int sid = sensors[group].toInt();
boolean isOutput = sensors[group+2].equals(IS_OUTPUT);
if (isOutput) {
if (sid == id) {
String type = sensors[group+1];
if (type.equals(ANALOG)) {
analogWrite(sid, constrain(value,0,255));
} else if (type.equals(DIGITAL)) {
digitalWrite(sid, value > 0 ? HIGH: LOW);
}
break;
}
}
}
}
- Output Sensor Control: This function handles commands from Torque to set the values of output sensors (like “Dout1” in the example).
- Command Parsing: It parses the
SETSENSOR
command to extract the sensor ID and the desired value. - Output Writing: It iterates through the
sensors
array, finds the matching output sensor ID, and usesanalogWrite()
ordigitalWrite()
to set the output pin to the received value, constrained to valid ranges (0-255 for analog, HIGH/LOW for digital).
11. initSensors()
Function:
/**
* Init the sensor definitions (input/output, default output states, etc)
*/
void initSensors() {
for (int i = 0; i < SENSORSSIZE/9; i++) {
int group = i * 9;
int id = sensors[group].toInt();
String type = sensors[group+1];
boolean isOutput = sensors[group+2].equals(IS_OUTPUT);
int defaultValue = sensors[group+3].toInt();
if (isOutput) {
if (type.equals(ANALOG)) {
pinMode(id, OUTPUT);
analogWrite(id, constrain(defaultValue, 0, 255));
} else if (type.equals(DIGITAL)) {
pinMode(id, OUTPUT);
digitalWrite(id, defaultValue > 0 ? HIGH : LOW);
}
}
}
}
- Sensor Initialization: This function initializes the pins defined in the
sensors
array. For output pins, it sets the pin mode toOUTPUT
and sets the initial output value usinganalogWrite()
ordigitalWrite()
based on the default value specified in thesensors
array.
12. getConfiguration()
Function:
void getConfiguration() {
mySerial.print(CONFIGURATION);
}
- Configuration Transmission: This function simply sends the
CONFIGURATION
string to Torque, allowing Torque to apply the specified configuration directives (like hiding car or device sensors).
Setting Up Your Arduino OBD2 Android System
To get this system working, you’ll need the following:
- Arduino Board: An Arduino UNO or similar board.
- Bluetooth Module: An HC-05 or HC-06 Bluetooth module for wireless communication.
- OBD2 Adapter Cable (Optional but Recommended): To connect to your car’s OBD2 port without modifying your car’s wiring directly. You may need to adapt the wiring of the OBD2 cable to connect to your Arduino and Bluetooth module.
- Android Device with Torque Pro App: Torque Pro is a popular Android OBD2 app that supports custom sensors.
- Sensors (Optional): Depending on the sensors you want to monitor (boost pressure sensor, EGT sensor, etc.).
- Wiring and Breadboard: For connecting the components.
Steps:
- Wire the Bluetooth Module to Arduino: Connect the Bluetooth module’s TX pin to Arduino’s RX pin 2 and Bluetooth module’s RX pin to Arduino’s TX pin 3. Connect power and ground appropriately.
- Upload the Arduino Code: Upload the provided Arduino code to your Arduino board using the Arduino IDE.
- Pair Bluetooth: Pair your Android device with the Bluetooth module.
- Configure Torque Pro:
- In Torque Pro settings, configure the connection type to “Bluetooth OBD2 Adapter.”
- Select your Bluetooth module from the list of paired devices.
- Torque Pro should automatically recognize the Arduino as an OBD2 adapter and import the custom sensors defined in the code.
- Connect to OBD2 Port: Connect your Arduino/Bluetooth setup to your car’s OBD2 port (using an adapter cable if needed).
- Start Torque Pro and Monitor Data: Run Torque Pro on your Android device. You should now see the custom sensors (Boost, EGT, Dout1 in the example) available in Torque Pro, displaying data from your Arduino.
Expanding the Project and Potential Applications
This basic example is just the starting point. You can significantly expand this project:
- Add More Sensors: Integrate various sensors relevant to your needs – wideband O2 sensor, oil pressure, accelerometer for g-force, etc. Define these sensors in the
sensors
array in the code. - Custom Data Processing: Implement more complex data processing and conversions within the Arduino code.
- Control Outputs: Utilize the output sensor functionality to control relays or other actuators based on sensor readings or commands from Torque Pro. This could be used for things like controlling fans, lights, or other vehicle systems.
- Data Logging: Extend the code to log sensor data to an SD card for later analysis.
- Custom Android App Development: For more advanced customization, you could develop your own Android app to communicate with the Arduino and visualize the data in a bespoke interface.
Potential Applications:
- Custom Car Gauges: Create a personalized digital dashboard displaying the parameters you care about most.
- Performance Monitoring: Track engine performance metrics beyond standard OBD2 data.
- DIY Telemetry: Log vehicle data for track days or performance analysis.
- Vehicle Health Monitoring: Implement custom alerts and warnings based on sensor readings.
- Educational Projects: A fantastic platform for learning about automotive electronics, Arduino programming, and OBD2 systems.
Conclusion
By combining the power of Arduino, the OBD2 interface, and the versatility of Android, you can create a powerful and customizable car diagnostics and data monitoring system. The provided code offers a solid foundation to build upon, allowing you to tailor your car data experience to your specific interests and needs. Dive in, experiment, and unlock the potential of your vehicle’s data with Arduino Obd2 Android!