0

I have a project that logs data from a vechicle's OBD 2 port (using PiCan2 on top of RPi3B) and combines that data with data from sensors connected to an external Arduino. The Arduino communicates with the RPi via USB serial. I have set the code to write the values to a .txt file, seperated by commas. Each line is a separate data frame. The code is set to take a data sample every time the GPS (Neo 6M) is updated. The program works as expected at 1Hz which is the default Neo 6M update rate, BUT after setting the GPS to work at 5Hz for more accuracy on road events, I get periodical losses on data collecting. The first picture is from 1Hz and the second is from 5Hz. Notice the data gaps.1st Image

2nd Image

The python code is a modified version from here. I used the obdii_logger.py and simple_coolant to create this:

#!/usr/bin/env python3
import serial
import RPi.GPIO as GPIO
import time
import os
import can
import string
from threading import Thread

from datetime import datetime
ln=datetime.today().strftime('%d-%m-%Y___%H-%M-%S rduversion')
index=0
start_time=time.time()
led = 22
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(led,GPIO.OUT)
GPIO.output(led,True)
INTAKE_AIR_TEMPERATURE = 0x0F
ENGINE_RPM          = 0x0C
ENGINE_COOLANT_TEMP = 0x05
VEHICLE_SPEED       = 0x0D
PID_REQUEST         = 0x7DF
PID_REPLY           = 0x7E8
file=open("rest9.txt","a")
os.system("sudo /sbin/ip link set can0 up type can bitrate 500000")
time.sleep(0.1)
os.system("sudo ifconfig can0 txqueuelen 1000")
print('Ready')
try:
    bus = can.interface.Bus(channel='can0', bustype='socketcan_native')
except OSError:
    print('Cannot find PiCAN board.')
    GPIO.output(led,False)
    exit()

  
def can_rx_task():
    while True:
        message = bus.recv()
        
        
        if message.arbitration_id == PID_REPLY and message.data[2] == ENGINE_RPM:
            c = '{0:f} {1:x} {2:x} '.format(message.timestamp, message.arbitration_id, message.dlc)
            s=''
            for i in range(message.dlc ):
                s +=  '{0:x} '.format(message.data[i])
            rpm = round(((message.data[3]*256) + message.data[4])/4)
            file.write(str(rpm)+",")
            print(str(rpm))
        
        if message.arbitration_id == PID_REPLY and message.data[2] == VEHICLE_SPEED:
            c = '{0:f} {1:x} {2:x} '.format(message.timestamp, message.arbitration_id, message.dlc)
            s=''
            for i in range(message.dlc ):
                s +=  '{0:x} '.format(message.data[i])
            speed = message.data[3]
            file.write(str(speed)+",")
            print(str(speed))
        
        #if message.arbitration_id == PID_REPLY and message.data[2] == INTAKE_AIR_TEMPERATURE:
            #c = '{0:f} {1:x} {2:x} '.format(message.timestamp, message.arbitration_id, message.dlc)
            #s=''
            #for i in range(message.dlc ):
                #s +=  '{0:x} '.format(message.data[i])
            #airtemperature = message.data[3] - 40
            #file.write(str(airtemperature)+",")
            #print(str(airtemperature))

t = Thread(target = can_rx_task)
t.start()

try:
    if __name__ == '__main__':
        ser = serial.Serial('/dev/ttyACM0', 9600, timeout=1)
        ser.reset_input_buffer()
        


    while True:
        if ser.in_waiting > 0:
            line = ser.readline().decode('utf-8').rstrip()+"\n"
            file.write(datetime.today().strftime('%H-%M-%S,'))
            file.write(line)
            msg = can.Message(arbitration_id=PID_REQUEST,data=[0x02,0x01,VEHICLE_SPEED,0x00,0x00,0x00,0x00,0x00],extended_id=False)
            bus.send(msg)
            time.sleep(0.05)
            msg = can.Message(arbitration_id=PID_REQUEST,data=[0x02,0x01,ENGINE_RPM,0x00,0x00,0x00,0x00,0x00],extended_id=False)
            bus.send(msg)
            time.sleep(0.05)
            
            #msg = can.Message(arbitration_id=PID_REQUEST,data=[0x02,0x01,INTAKE_AIR_TEMPERATURE,0x00,0x00,0x00,0x00,0x00],extended_id=False)
            #bus.send(msg)
            #time.sleep(0.05)
            #file.close()
            print(line)
            print(index)
            
            index+=1

except KeyboardInterrupt:
    #Catch keyboard interrupt
    GPIO.output(led,False)
    end_time=time.time()
    elapsed_time=end_time-start_time
    print('Execution time: '+str(int(elapsed_time)))
    file.close()
    os.system("sudo /sbin/ip link set can0 down")
    print('\n\rKeyboard interrtupt')

Also here is the Arduino Code:

#include <Wire.h>
#include <Adafruit_Sensor.h>
const int x=A1;
const int y=A2;
const int z=A3;
#include <SoftwareSerial.h> 
#include <TinyGPS++.h>
TinyGPSPlus gps; 
SoftwareSerial ss(4,3);

const unsigned char UBLOX_INIT[] PROGMEM={
0xB5,0x62,0x06,0x08,0x06,0x00,0xC8,0x00,0x01,0x00,0x01,0x00,0xDE,0x6A
};


  
  
void setup(void)
{
  ss.begin(9600);
  Serial.begin(9600);
  while (!Serial);


  for(unsigned int i=0;i<sizeof(UBLOX_INIT);i++){
    ss.write(pgm_read_byte(UBLOX_INIT+i));
    }
  
}

void loop(){

  while(ss.available()>0){
    gps.encode(ss.read());
    if(gps.location.isUpdated()){
  /* Get a new sensor event */
 
int sensorRD=analogRead(A0);
if(sensorRD<600){
Serial.print("2");
Serial.print(",");
}
else if(sensorRD>900){
  Serial.print("0");
  Serial.print(",");
  }
else if(sensorRD>600 && sensorRD<900){
Serial.print("1");
Serial.print(",");
}
 
  Serial.print(analogRead(x)); Serial.print(",");
  Serial.print(analogRead(y)); Serial.print(",");
  Serial.print(analogRead(z)); Serial.print(",");
  
      Serial.print(gps.location.lat(), 6);
      Serial.print(","); 
      Serial.println(gps.location.lng(), 6);
    }
  }
  }

The data loss occurs ONLY when I send 3 or more different PID requests to the ECU. The program was working perfectly with 4 PIDs on 1Hz. How can I read more PIDs at 5hz without data loss? Am running out of Ram? buffer space? I have googled everything and cant seem to be able to fix the problem.

2
  • You are probably running out of CPU time; in the Python code, you are sleeping for 3 x 0.05 seconds, which doesn't leave much time for your code to do anything useful, if the data is arriving every 0.2 seconds. You need to re-structure the code to avoid this time-wasting.
    – jayben
    Mar 4 at 13:51
  • This is exactly what happened! I lowered it to 0.01 secs and I was able to read more PIDs Thanksđź‘Ť Mar 5 at 14:38

0

Your Answer

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

Browse other questions tagged or ask your own question.