Getting Vehicle data from my car's OBDII port

Hello Blynk experts,

In this project, I am using Arduino YUn with CAN Bus Shield v1.2 in order to get the vehicle data and display few of them in the iOS app. Also I would like to record the signals while I am driving the car on SuperChart widget and then I can export them to computer.

I have few issues currently with getting the CAN data and sending it to Blynk app. It seems that I have to optimize my code or Blynk cannot handle so many Virtual pins.

When I am connected to CAN bus, I can send 1-2 signals to virtual pins but it is so unstable that sometimes Arduino YUN board goes to Offline and then Online again. (If I want to send more signals to virtual pins, it stays mostly offline)

So I am not sure, where the root cause of the problem.

Please check my code below:

    /************************************************************************************************* 
      OBD-II_PIDs TEST CODE
      Query
      send id: 0x7df
          dta: 0x02, 0x01, PID_CODE, 0, 0, 0, 0, 0
      Response
      From id: 0x7E9 or 0x7EA or 0x7EB
          dta: len, 0x41, PID_CODE, byte0, byte1(option), byte2(option), byte3(option), byte4(option)     
   [https://en.wikipedia.org/wiki/OBD-II_PIDs](https://en.wikipedia.org/wiki/OBD-II_PIDs)
      Input a PID, then you will get reponse from vehicle, the input should be end with '\n'
      Blynk.virtualWrite(V1, val);
    ***************************************************************************************************/
    #include "mcp_can.h"
    #include <Bridge.h>
    #include <BlynkSimpleYun.h>

    char auth[] = "*********************";
    WidgetTerminal terminal(V1);

    // the cs pin of the version after v1.1 is default to D9
    // v0.9b and v1.0 is default D10
    const int SPI_CS_PIN = 9;

    MCP_CAN CAN(SPI_CS_PIN);                                    // Set CS pin
    #define BLYNK_PRINT Serial

    #define CAN_ID_PID          0x7DF

    unsigned char PID_INPUT;
    unsigned char getPid    = 0;
    float test= 3.0;
    float nEng=100.0;
    float T_W_O=6.0;

    void set_mask_filt()
    {
        /*
         * set mask, set both the mask to 0x3ff
         */
        CAN.init_Mask(0, 0, 0x7FC);
        CAN.init_Mask(1, 0, 0x7FC);

        /*
         * set filter, we can receive id from 0x04 ~ 0x09
         */
        CAN.init_Filt(0, 0, 0x7E8);                 
        CAN.init_Filt(1, 0, 0x7E8);
        CAN.init_Filt(2, 0, 0x7E8);
        CAN.init_Filt(3, 0, 0x7E8);
        CAN.init_Filt(4, 0, 0x7E8); 
        CAN.init_Filt(5, 0, 0x7E8);
    }

    void sendPid(unsigned char __pid)
    {
        unsigned char tmp[8] = {0x02, 0x01, __pid, 0, 0, 0, 0, 0};
        Serial.print("SEND PID: 0x");
        terminal.print("SEND PID: 0x");
        Serial.println(__pid, HEX);
        terminal.print(__pid, HEX);
        terminal.print("\n");
        terminal.print(test);
        terminal.print("\n");
        terminal.flush();
        CAN.sendMsgBuf(CAN_ID_PID, 0, 8, tmp);
       
        
    }


    void sendPidPeriodic()
    {
       
        unsigned char tmp1[8] = {0x02, 0x01, 0x0C, 0, 0, 0, 0, 0};  // 0x0C is for engine speed
        unsigned char tmp2[8] = {0x02, 0x01, 0x05, 0, 0, 0, 0, 0}; // 0x05 is for coolant temp

        //CAN.sendMsgBuf(CAN_ID_PID, 0, 8, tmp2);
        //delay(500);
        //CAN.sendMsgBuf(CAN_ID_PID, 0, 8, tmp1);
        //delay(500);
    }


    BLYNK_WRITE(V1)
    {
        terminal.print("\n");
        terminal.print("Send PID from terminal: 0x");
        terminal.write(param.getBuffer(), param.getLength());
        terminal.println();
        terminal.flush();
        //char c =param.getBuffer();
        //sendPid(param.getBuffer);

      }
    void setup()
    {
        Serial.begin(115200);
        Blynk.begin(auth);
      terminal.println(F("Blynk v" BLYNK_VERSION ": Device started"));
      terminal.println(F("-------------"));
      terminal.flush();
        while (CAN_OK != CAN.begin(CAN_500KBPS))    // init can bus : baudrate = 500k
        {
            Serial.println("CAN BUS Shield init fail");
            terminal.print("CAN BUS Shield init fail");
            Serial.println(" Init CAN BUS Shield again");
            terminal.print("Init CAN BUS Shield again");
            delay(100);
        }
        Serial.println("CAN BUS Shield init ok!");
        terminal.print("CAN BUS Shield init ok!");
        terminal.print("\n");
        terminal.flush();
        set_mask_filt();
    }


    void loop()
    {
        Blynk.run();
        taskCanRecv();
        taskDbg();
        sendPidPeriodic();



      
        if(getPid)          // GET A PID
        {
            getPid = 0;
            sendPid(PID_INPUT);
            PID_INPUT = 0;
        }

    }

    void taskCanRecv()
    {
        unsigned char len = 0;
        unsigned char buf[8];

        if(CAN_MSGAVAIL == CAN.checkReceive())                   // check if get data
        {
            CAN.readMsgBuf(&len, buf);    // read data,  len: data length, buf: data buf
      
            Serial.println("\r\n-----");
            Serial.print("Get Data From id: ");
            Serial.println(CAN.getCanId(), HEX);
         
            //Serial.print("data len = ");
            //Serial.println(len);
            
            for(int i = 0; i<len; i++)    // print the data
            {
                //Serial.print("0x");
                Serial.print(buf[i], HEX);
                Serial.print("\t");
                
               if(buf[2]==0x0C&&buf[1]==0x41){
            nEng = ((buf[3]*256) + buf[4])/4;
            //Serial.println(nEng);
            Blynk.virtualWrite(V3, nEng); // Send Engine Speed
            }
                else if (buf[2]==0x5&&buf[1]==0x41){
            T_W_O= (buf[3])-40;
            Blynk.virtualWrite(V4, T_W_O); // Send coolant temp
                }
                else if (buf[1]==0x41){
                
            test= (buf[3]);
            Blynk.virtualWrite(V5, test);

          
                }
               
            }
            //Serial.println();
        }
    }

    void taskDbg()
    {
        while(Serial.available())
        {
            char c = Serial.read();
            
            if(c>='0' && c<='9')
            {
                PID_INPUT *= 0x10;
                PID_INPUT += c-'0';
                
            }
            else if(c>='A' && c<='F')
            {
                PID_INPUT *= 0x10;
                PID_INPUT += 10+c-'A';
            }
            else if(c>='a' && c<='f')
            {
                PID_INPUT *= 0x10;
                PID_INPUT += 10+c-'a';
            }
            else if(c == '\n')      // END
            {
                getPid = 1;
            }
        }
    }
    // END FILE

Probably I am not requesting the OBD PIDs in the best way. But my aim is to receive the data as fast as possible without crashing anything.

Can you please support me how to make the request periodically and how to send them to Blynk app in a more optimized way ?

Thanks…

wow, interesting and cool project. i’m not an expert in this and on phone right now, but you should try:

  • to enable blynk debug prints, to see what causes the disconnect

  • to use blynk timer (or simple timer) to schedule the tasks you need

  • to measure how long it takes to communicate with the obd, using serial print millis before and after the communication functions. (maybe the duration is too long, or too often, and this causes the crash)

however, please keep me updated how it goes, it seems an interesting idea!

Don’t know anything about CAN, but according to the Blynk documentation, avoid delay() and loops into main code (setup() , loop())
I would suggest

  1. remove the while loop from setup. make it one-pass function and call it periodicaly with BlynkTimer until it succeeds
  2. check the point of crash. is it during or after setup()

B.R
Kostas

I had a bit of a dabble with an ElecFreaks Canbus V1.2 shield and an Auduino of some sort (Uno or Mega, I can’t remember which). I didn’t manage to get any sensible data out of the OBDI on my Renault car, but I must admit I didn’t stick at it for very long.
I was trying to get a data out the Canbus regarding lights, indicators, horn, wipers etc. My aim was to see if it would be practical to control these items via the Canbus, with a view to eventually building an interface that would allow me to control these for a disabled driver. I’ve since released that these items are probably on a different bus (vehicle ECU) from the one I was reading, so if i revisit the project I’d need to figure-out how to access the correct bus - maybe a different pin on the OBDI connector.

My advice would be to get some sensible data out without using Blynk, then when that’s working reliably add the Blynk functionality.

Pete.

this is valid only for the loop, in setup delays does not affect blynk functionality at all.

as for the replace while loop in setup with timer, it is not valid, because the blynk timer will not work in setup (it is only initialised thete). it is activated only in the main loop. thus, if he replaces the while loop with a timer, it will never be executed in setup.

i think @PeteKnight is right, probably would be better to build a solid non blynk version first, and see how it goes.