4

I am using this device for my Arduino that connects to the OBD-II port of my car to get various information such as speed, rpm, etc. I am using this for a digital Nixie tube speedometer using the smart Nixie tube from a Kickstarter project.

I pass the information to the Nixie tubes through serial and get information from the OBD-II through serial as well. I am getting speed updates about every 20 seconds and that is incredibly slow when the device can supposedly update up to 100 times per second.

I originally was using an Arduino Uno and using software serial for the tubes, but I figured the slowdown was due to interupts interfering with the hardware serial, so I switched to the Arduino Mega 2560 to use a second hardware serial pin to hopefully fix the problem, yet the same issue is occurring.

Here is my code... There must be something I'm doing wrong. Serial2 is for the Nixie tubes.

#import <Arduino.h>

#include <OBD.h>

int ones = 0;
int tens = 0;

int kphValue = 0;
int mphValue = 0;

int rpmValue = 0;

String onesString;
String tensString;
String payloadString;
String rpmString;
COBD obd;

void setup(){
    Serial2.begin(9600);
    obd.begin();

    //Initiate OBD-II connection until success
    while (!obd.init()){
        Serial2.print("$0,Y,Y,255,255,000,000$0,Y,Y,255,255,000,000!");
        delay(1000);
        Serial2.print("$0,Y,Y,000,000,000,000$0,Y,Y,000,000,000,000!");
        delay(1000);
    }
}

void loop(){
    onesString = String(ones);
    tensString = String(tens);
    payloadString;
    rpmString;

    if(obd.read(PID_RPM, rpmValue)){
        if (rpmValue < 3000){
            rpmString =",N,N,255,000,255,000";
        }
        else if (rpmValue >= 5000){
            rpmString = ",N,N,255,255,000,000";
        }
        else if (rpmValue >= 3000){
            rpmString = ",N,N,255,255,030,000";
        }
    }

    if (obd.read(PID_SPEED, kphValue)){
        kphToMPH();
        payloadString = "$" + onesString + rpmString + "$" + tensString + "rpmString" + "!";
        Serial2.print(payloadString);
    }
}

void splitDigits(int input_number)
{
    ones = (input_number%10);
    tens = ((input_number/10)%10);
}

void kphToMPH()
{
    mphValue = kphValue * 0.621371;
    splitDigits(mphValue);
}

EDIT: I am using the following library: https://github.com/stanleyhuangyc/ArduinoOBD

migrated from electronics.stackexchange.com Apr 24 '14 at 4:34

This question came from our site for electronics and electrical engineering professionals, students, and enthusiasts.

  • 1
    The call to Serial2.available() looks suspicious, what happens if you remove it? That calls checks for incoming data, not that it's OK to send data. – PeterJ Apr 23 '14 at 4:37
  • I will edit that out. I added that to see if it would help because without it I'm still getting slow responses. – evan.stoddard Apr 23 '14 at 4:38
  • Seem to be missing the source for obd.read() there. – John U Apr 23 '14 at 8:14
  • 1
    Can you add some sort of indication, like blink an LED, to show what's delaying? Is it that the code waits between reads, that the reads happen really slowly (low baud rate? faulty comms routine? long negotiation period?) or that the car waits a long time to respond? etc. etc. – John U Apr 23 '14 at 8:41
  • The read is a relatively high baud rate. – evan.stoddard Apr 23 '14 at 12:19
6

I think the problem is not so much in the update speed, but in the fact that you loose accuracy in your calculation. The following lines are the culprit:

int kphValue = 0;  // [-32768:32767]
int mphValue = 0;
mphValue = kphValue * 0.621371;

Make sure the calculation will be entirely in integers to prevent calculation errors:

uint16_t kphValue = 0;  // [0:65535]
uint16_t mphValue = 0;
mphValue = ( kphValue * 621 ) / 1000;

This limits kphValue to just over 100, if you want to go higher than that there are two option:

  • multiply by 62 and divide by 100;
  • use longer integers int32_t [-2147483648:2147483647], which comes with enough room for multiplying by 621371 and dividing by 1000000, but will perform slower and with a larger memory footprint. Do you really need that accuracy?
  • Yes and what about the computation delay added by the usage of floating point numbers with a MCU that has no floating point support. – Blup1980 Apr 23 '14 at 6:55
  • Not sure if the first part is correct, while I normally wouldn't write it that way I'd expect kphValue would be converted to a double for the calculation phase. Just gave it a quick try on a PC C++ compiler and result was 621 for an input of 1000. – PeterJ Apr 23 '14 at 7:12
  • @Blup1980 - It will be slower but even a very slow micro should be able to do those calculations in a jiffy. If you were doing the conversion 1000 times per second then you might notice a delay. – John U Apr 23 '14 at 8:16
  • @Blup1980 where do you see floating point numbers in my answer? – jippie Apr 23 '14 at 17:57
  • 1
    @jippie You said that your implementation using integers is better because of the better accuracy. But I wanted to add that it's also better in term of speed because there is no floating point. But it would even be better if you multiply by 636 and divide by 1024 where the divide can be computed as logical shifts instead of a multi cycle divide operation. – Blup1980 Apr 23 '14 at 19:25
3

try this:

#import <Arduino.h>
#include <OBD.h>

int kphValue = 0;
int rpmValue = 0;

COBD obd;

//array of character arrays, see http://arduino.cc/en/Reference/string
const char* rpmStrings[] = {    ",N,N,255,000,255,000", 
                                ",N,N,255,255,030,000", 
                                ",N,N,255,255,000,000" }; 

void setup(){
    Serial2.begin(9600);
    obd.begin();

    //Initiate OBD-II connection until success
    while ( !obd.init() ) {
        Serial2.print("$0,Y,Y,255,255,000,000$0,Y,Y,255,255,000,000!");
        delay(1000);
        Serial2.print("$0,Y,Y,000,000,000,000$0,Y,Y,000,000,000,000!");
        delay(1000);
    }
}

void loop() {
    if ( obd.read(PID_RPM, rpmValue) && obd.read(PID_SPEED, kphValue) )
    {
        int rpmStringIndex = determineRpmIndex(rpmValue);
        int mphValue = kphToMPH(kphValue);

        //payloadString = "$" + onesString + rpmString + "$" + tensString + "rpmString" + "!";
        //using Arduino String objects is generally not a good idea due to memory constraints
        //it's probably ok, but I'd rather use character arrays and/or print a bit at a time rather than trying to assemble a giant string 
        Serial2.print("$");
        Serial2.print(mphValue % 10); //ones
        Serial2.print(rpmStrings[rpmStringIndex]);
        Serial2.print("$");
        Serial2.print(mphValue / 10); //tens - integer division, don't need modulo

        //do you really want to append the string "rpmString!" or did you want the contents of the variabe rmpString+"!" ?
        //I'm pretty sure you meant the latter
        Serial2.print(rpmStrings[rpmStringIndex]);
        Serial2.print("!");
    }
    else 
    {
        //obd read error
        //add debugging output here to see if obd failed to respond correctly/on time
    }
}

int kphToMph( int kphValue ) {
    //return a value rather than updating a global variable
    return ( int ) ( kphValue * 0.621371 );
}

int determineRpmIndex( int rpmValue ) {
    if ( rpmValue >= 5000 )
        return 2;

    if ( rpmValue >= 3000 )
        return 1;

    return 0;
}
  • Looks good and learned a lot... I will upload when I get a chance and let you know! – evan.stoddard May 2 '14 at 0:42
1

I was found solution with

Serial.setTimeout(100);

Like this (https://www.arduino.cc/en/Serial/SetTimeout) setTimeout was 1000ms default.

the check serial port per 1000ms.

I referenced this https://stackoverflow.com/a/28892086/929740

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.