Python-加速度计以1 kHz的速率读写CSV文件

时间:2018-11-20 19:57:57

标签: python csv raspberry-pi accelerometer i2c

我正在尝试使用MPU-6000加速度计和Raspberry Pi Zero W记录挡风玻璃中的振动数据。我是Python的新手,请耐心等待。

我编写了一个python2脚本,该脚本将MPU-6000配置为通过I2C进行通信,并将时钟配置为400 kHz。 当加速度计寄存器中有可用的新数据时,MPU-6000会发出中断,该数据将被读取,转换为2的补码,然后与时间戳一起写入CSV文件。加速度计的输出速率配置为1 kHz。

我遇到的问题是,在对所有三个传感器轴进行采样时,脚本无法将所有数据点都写入CSV文件。代替pr轴pr秒的1000个数据点,我得到pr轴pr秒的大约650个数据点。 我尝试只写一个轴,事实证明每秒成功完成1000个数据点。我知道MPU-6000具有可用的FIFO寄存器,我可能可以对其进行突发读取以得到1000个样本/秒而没有任何问题。问题将是为每个样本获取一个时间戳,所以我还没有尝试实现从FIFO寄存器的读取。

我很可能会在Matlab中进行大多数后期处理,因此python脚本应该做的最重要的事情是以确定的速率和时间戳将任何形式的传感器数据写入CSV文件。

有什么方法可以进一步改善我的Python脚本,因此我可以对所有三个轴进行采样并以1 kHz的速率写入CSV文件?

我的脚本的各个部分如下所示:

#!/usr/bin/python
import smbus
import math
import csv
import time
import sys
import datetime

# Register addresses
power_mgmt_1 = 0x6b
power_mgmt_2 = 0x6c
samlerate_divider = 0x19
accel_config = 0x1C
INT_Enable = 0x38



def read_byte(reg):
    return bus.read_byte_data(address, reg)

def read_word(reg):
    h = bus.read_byte_data(address, reg)
    l = bus.read_byte_data(address, reg+1)
    value = (h <<8)+l
    return value

def read_word_2c(reg):
    val = read_word(reg)

    if (val >= 0x8000):
        return -((65535 - val) + 1)
    else:
        return val



csvwriter = None

def csv_open():
    csvfile = open('accel-data.csv', 'a')

    csvwriter = csv.writer(csvfile)




def csv_write(timedelta, accelerometerx, accelerometery, accelerometerz):

    global csvwriter

    csvwriter.writerow([timedelta,  accelerometerx, accelerometery, 
    accelerometerz])



# I2C configs
bus = smbus.SMBus(1) 
address = 0x69       

#Power management configurations
bus.write_byte_data(address, power_mgmt_1, 0)
bus.write_byte_data(address, power_mgmt_2, 0x00)


#Configure sample-rate divider
bus.write_byte_data(address, 0x19, 0x07)


#Configure data ready interrupt:
bus.write_byte_data(address,INT_Enable, 0x01) 



#Opening csv file and getting ready for writing
csv_open()

csv_write('Time', 'X_Axis', 'Y_Axis', 'Z_Axis') 

print
print "Accelerometer"
print "---------------------"

print "Printing acccelerometer data: "

#starttime = datetime.datetime.now()

while True:


    data_interrupt_read =  bus.read_byte_data(address, 0x3A)

    if data_interrupt_read == 1:


        meas_time = datetime.datetime.now()
#       delta_time = meas_time - starttime


        accelerometer_xout = read_word_2c(0x3b)
        accelerometer_yout = read_word_2c(0x3d)
        accelerometer_zout = read_word_2c(0x3f)

#       accelerometer_xout = read_word(0x3b)
#       accelerometer_yout = read_word(0x3d)
#       accelerometer_zout = read_word(0x3f)

#       accelerometer_xout_scaled = accelerometer_xout / 16384.0
#       accelerometer_yout_scaled = accelerometer_yout / 16384.0
#       accelerometer_zout_scaled = accelerometer_zout / 16384.0



#       csv_write(meas_time, accelerometer_xout_scaled, 
        accelerometer_yout_scaled, accelerometer_zout_scaled)

        csv_write(meas_time, accelerometer_xout, accelerometer_yout, 
        accelerometer_zout) 


    continue

1 个答案:

答案 0 :(得分:1)

如果您要写入的数据是连续的,那么最好的方法是最大程度地减少写入数据所需的处理量,并最大程度地减少写入的数据量。为此,一种好的方法是将原始数据写入二进制格式的文件。这样,每个数据字仅需要写入2个字节。可以将datetime对象转换为需要4个字节的时间戳。因此,您将使用以下格式:

[4 byte timestamp][2 byte x][2 byte y][2 byte z]

Python的struct库可用于将多个变量转换为可以写入文件的单个二进制字符串。数据似乎已签名,在这种情况下,您可以尝试按原样编写单词,然后使用对签名值支持的内置库在以后读回。

例如,以下代码可用于将原始数据写入二进制文件:

#!/usr/bin/python
import smbus
import math
import csv
import time
import sys
import datetime
import struct

# Register addresses
power_mgmt_1 = 0x6b
power_mgmt_2 = 0x6c
samlerate_divider = 0x19
accel_config = 0x1C
INT_Enable = 0x38


def read_byte(reg):
    return bus.read_byte_data(address, reg)


def read_word(reg):
    h = bus.read_byte_data(address, reg)
    l = bus.read_byte_data(address, reg+1)
    value = (h <<8)+l
    return value


# I2C configs
bus = smbus.SMBus(1) 
address = 0x69       

#Power management configurations
bus.write_byte_data(address, power_mgmt_1, 0)
bus.write_byte_data(address, power_mgmt_2, 0x00)

#Configure sample-rate divider
bus.write_byte_data(address, 0x19, 0x07)

#Configure data ready interrupt:
bus.write_byte_data(address, INT_Enable, 0x01) 


print
print "Accelerometer"
print "---------------------"

print "Printing accelerometer data: "

#starttime = datetime.datetime.now()
bin_format = 'L3H'

with open('accel-data.bin', 'ab') as f_output:
    while True:
        #data_interrupt_read =  bus.read_byte_data(address, 0x3A)
        data_interrupt_read = 1

        if data_interrupt_read == 1:
            meas_time = datetime.datetime.now()
            timestamp = time.mktime(meas_time.timetuple())

            accelerometer_xout = read_word(0x3b)
            accelerometer_yout = read_word(0x3d)
            accelerometer_zout = read_word(0x3f)

            f_output.write(struct.pack(bin_format, timestamp, accelerometer_xout, accelerometer_yout, accelerometer_zout))

然后,您可以使用以下命令将二进制文件转换为CSV文件:

from datetime import datetime
import csv
import struct

bin_format = 'L3h'  # Read data as signed words
entry_size = struct.calcsize(bin_format)

with open('accel-data.bin', 'rb') as f_input, open('accel-data.csv', 'wb') as f_output:
    csv_output = csv.writer(f_output)
    csv_output.writerow(['Time', 'X_Axis', 'Y_Axis', 'Z_Axis'])

    while True:
        bin_entry = f_input.read(entry_size)

        if len(bin_entry) < entry_size:
            break

        entry = list(struct.unpack(bin_format, bin_entry))
        entry[0] = datetime.fromtimestamp(entry[0]).strftime('%Y-%m-%d  %H:%M:%S')
        csv_output.writerow(entry)

如果数据收集不连续,则可以使用线程。一个线程会将您的数据读入一个特殊的队列。另一个线程可以将项目从队列中读取到磁盘上。

如果连续,如果数据写入的速度慢于数据读取的速度,则此方法将失败。

看看特殊的Format characters,该{{3}}告诉struct如何打包和解压缩二进制数据。