1

I have a problem in performance (scanning speed) with my Pi and the MPU6050. The task of the code is to log the data from the MPU as fast as possible and in an accurate interval.

To reach a high scanning speed I just record the raw register values and convert everything later. Moreover, I change the I2C baud rate from the Raspberry to 400kHz.

At the moment the code provide a raw data record frequency with max 135Hz.

Can you help me to get higher sampling rate and a better accurate interval. Wherein the exact interval the more important point is.

#!/usr/bin/python

import smbus
from datetime import datetime, timedelta
import time

bus = smbus.SMBus(1) # Bus for Revision 2 boards
address = 0x68       # Sensor i2c address
# Power management registers
power_mgmt_1 = 0x6b
power_mgmt_2 = 0x6c

# Accelerometer
# Data register
ACCEL_XOUT0 = 0x3B
ACCEL_XOUT1 = 0x3C
ACCEL_YOUT0 = 0x3D
ACCEL_YOUT1 = 0x3E
ACCEL_ZOUT0 = 0x3F
ACCEL_ZOUT1 = 0x40
# Range
ACCEL_CONFIG_REGISTER = 0x1C
ACCEL_2G = 0x00
ACCEL_4G = 0x08
ACCEL_8G = 0x10
ACCEL_16G = 0x18
# Scale Modifiers
ACCEL_SCALE_MODIFIER_2G = 16384.0
ACCEL_SCALE_MODIFIER_4G = 8192.0
ACCEL_SCALE_MODIFIER_8G = 4096.0
ACCEL_SCALE_MODIFIER_16G = 2048.0

# Gyroscope
# Data register
GYRO_XOUT0 = 0x43
GYRO_XOUT1 = 0x44
GYRO_YOUT0 = 0x45
GYRO_YOUT1 = 0x46
GYRO_ZOUT0 = 0x47
GYRO_ZOUT1 = 0x48
# Range
GYRO_CONFIG_REGISTER = 0x1B
GYRO_250DEG = 0x00
GYRO_500DEG = 0x08
GYRO_1000DEG = 0x10
GYRO_2000DEG = 0x18
# Scale Modifiers
GYRO_SCALE_MODIFIER_250DEG = 131.0
GYRO_SCALE_MODIFIER_500DEG = 65.5
GYRO_SCALE_MODIFIER_1000DEG = 32.8
GYRO_SCALE_MODIFIER_2000DEG = 16.4

# Temperature
# Data register
TEMP_OUT0 = 0x41
TEMP_OUT1 = 0x42

# -- Functions --
def read_register(adr):
    return [bus.read_byte_data(address, adr),bus.read_byte_data(address, adr+1)]

def convert_register(raw_val):
    convert_val = (raw_val[0] << 8) + raw_val[1]
    if (convert_val >= 0x8000):
        return -((65535 - convert_val) + 1)
    else:
        return convert_val

def convert_temp(raw_val):
    raw_temp = convert_register(raw_val)
    temp = (raw_temp / 340) + 36.53
    return temp

def set_range_get_scale(register, range):
    bus.write_byte_data(address, register, range) # set new range
    time.sleep(0.5)
    current_range = bus.read_byte_data(address, register) # read current set range
    if register == ACCEL_CONFIG_REGISTER:
        if current_range == ACCEL_2G:
            return ACCEL_SCALE_MODIFIER_2G
        elif current_range == ACCEL_4G:
            return ACCEL_SCALE_MODIFIER_4G
        elif current_range == ACCEL_8G:
            return ACCEL_SCALE_MODIFIER_8G
        else: #current_range == ACCEL_16G
            return ACCEL_SCALE_MODIFIER_16G
    if register == GYRO_CONFIG_REGISTER:
        if current_range == GYRO_250DEG:
            return GYRO_SCALE_MODIFIER_250DEG
        elif current_range == GYRO_500DEG:
            return GYRO_SCALE_MODIFIER_500DEG
        elif current_range == GYRO_1000DEG:
            return GYRO_SCALE_MODIFIER_1000DEG
        else: #current_range == GYRO_2000DEG:
            return GYRO_SCALE_MODIFIER_2000DEG  

# -- INIT -- 
print('| Loading...')
bus.write_byte_data(address, power_mgmt_1, 0)
acc_scale = set_range_get_scale(ACCEL_CONFIG_REGISTER,ACCEL_2G)
gyro_scale = set_range_get_scale(GYRO_CONFIG_REGISTER,GYRO_250DEG)

# -- MAIN --
# query of parameters
freqInput = raw_input("Measuring frequency[Hz]: ")
durationInput=[0,0]
tmp = raw_input("Measuring duration[m]: ")
durationInput[0] = int(tmp)
tmp = raw_input("Measuring duration[s]: ")
durationInput[1] = int(tmp)

# Calculation of frequency
milsec = float(1000.0/float(freqInput))
if milsec==1000:
   freq=timedelta(0,1)
elif milsec%1==0:
   freq=timedelta(0,0,0,int(milsec))
else:
   freq=timedelta(0,0,(milsec-int(milsec))*1000,int(milsec))

# Set measurement duration
duration=timedelta(0,durationInput[1],0,0,durationInput[0]) # days, seconds, microseconds, milliseconds, minutes

# List for data record
time=[]
temp=[]
acc=[]
gyro=[]

# Loop
print('| Start Logging')
tend = datetime.now()+duration
t = datetime.now()
while datetime.now().time() < tend.time(): # interrupts if the total measuring time is passed
    t = datetime.now()
    time.append(datetime.now())
    temp.append(read_register(0x41))
    acc.append([read_register(0x3B),read_register(0x3D),read_register(0x3F)])
    gyro.append([read_register(0x43),read_register(0x45),read_register(0x47)])
    while datetime.now() < t+freq:  # interrupts if it time for the next record
        pass
tend = datetime.now()
print('| Finish Logging')

# Test Records
print('| Start Test Record')
if len(time) == len(temp) and len(time) == len(acc) and len(time) == len(gyro):
    print('| Finish Record Test; Result = OK')
else:
    print('| Finish Record Test; Result = FALSE')
    SystemExit(0)

# Convert Raw Data
print('| Start Raw Data Converting')
for i in range(len(time)):
    temp[i] = convert_temp(temp[i])
    for j in range(0,3):
        acc[i][j] = convert_register(acc[i][j]) / acc_scale
        gyro[i][j] = convert_register(gyro[i][j]) / gyro_scale
print('| Finish Raw Data Converting')

# write file
print ("| Start file writing")
name = datetime.now()
file = name.strftime('%Y%m%d_%H%M%S')
datei_out = open(file+".csv","w")
for i in range(len(time)):
    datei_out.write(str(i+1)+";") # number of measurment
    datei_out.write(str(time[i].time())+";") # time stamp of measurment
    datei_out.write(str(time[i]-time[0])+";") # time delta since measurement start
    datei_out.write(str(acc[i][0])+";") # Accelerometer X
    datei_out.write(str(acc[i][1])+";") # Accelerometer X
    datei_out.write(str(acc[i][2])+";") # Accelerometer X
    datei_out.write(str(gyro[i][0])+";") # Gyroscope X
    datei_out.write(str(gyro[i][1])+";") # Gyroscope X
    datei_out.write(str(gyro[i][2])+"\n") # Gyroscope X
datei_out.close()
print ("| Finish file writing")

# end
print ("| Completely Finish")
Torxed
  • 22,866
  • 14
  • 82
  • 131
japi90
  • 11
  • 1
  • 2
  • Maybe try to use profiler (https://docs.python.org/2/library/profile.html) to check which part of the code is slowest. – Pax0r Apr 11 '16 at 10:55
  • 1
    It's hard for the general programmer to help you since you havn't narrowed down you own problem, most of us won't have a rasberry pi readily available and thus consider doing what @Pax0r sad or just add `x = time()` between blocks of code and see where things are slow. Calling `datetime.now()` for instance all over the place will be tedious as well as any loops. Remember it's actually a rather slow CPU, you won't believe the random bottle necks that will appear especially if you are using for instance raspbian (with a system in the background doing things) – Torxed Apr 11 '16 at 11:05
  • @ Pax0r: Thanks for the profiler hint. I will try it. – japi90 Apr 15 '16 at 09:20
  • @ Torxed: I think also that the `datetime.now()` is one reason for a slower performance. But I need it to stop after a defined time and the `timer` is not so accuracy. – japi90 Apr 15 '16 at 09:22

0 Answers0