Python - чтение и запись акселерометра в файл CSV с частотой 1 кГц - PullRequest
0 голосов
/ 20 ноября 2018

Я пытаюсь использовать акселерометр MPU-6000 и Raspberry Pi Zero W для регистрации данных вибрации на лобовом стекле.Я довольно новичок в Python, поэтому, пожалуйста, потерпите меня.

Я написал скрипт python2, который настраивает MPU-6000 для связи по I2C с тактовой частотой 400 кГц.MPU-6000 выдает прерывание, когда в регистрах акселерометра появляются новые данные, которые считываются, преобразуются в дополнение к 2, а затем записываются в файл CSV вместе с отметкой времени.Выходная частота акселерометра настроена на 1 кГц.

Я чувствую, что при выборке всех трех осей датчика сценарий не может записать все точки данных в файл CSV.Вместо 1000 точек данных pr оси pr секунд я получаю приблизительно 650 точек данных pr оси pr секунд.Я попытался написать только одну ось, которая оказалась успешной с 1000 точек данных на секунду.Я знаю, что MPU-6000 имеет доступный регистр FIFO, который я, вероятно, могу прочитать в пачке, чтобы получить 1000 выборок / с без проблем.Проблема будет заключаться в получении метки времени для каждого образца, поэтому я еще не пытался реализовать чтение из регистра FIFO.

Скорее всего, я сделаю большую часть постобработки в Matlab, поэтому самое важное, что должен сделать скрипт Python, - это записать данные датчика в любой форме в файл CSV с определенной скоростью, с отметкой времени.

Есть ли способ еще улучшить мой скрипт на Python, чтобы я мог сэмплировать все три оси и записать в файл CSV с частотой 1 кГц?

Части моего сценария изображены ниже:

#!/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 голосов
/ 21 ноября 2018

Если данные, которые вы пытаетесь записать, являются непрерывными, то лучший способ - минимизировать объем обработки, необходимый для их записи, а также минимизировать объем записываемых данных.Для этого хорошим подходом было бы записать необработанные данные в двоичный форматированный файл.Каждое слово данных тогда потребовало бы только 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)

ЕслиВаш сбор данных не является непрерывным, вы можете использовать потоки.Один поток будет читать ваши данные в специальной очереди.Другой поток может считывать элементы из очереди на диск.

Если он будет непрерывным, этот подход потерпит неудачу, если запись данных будет медленнее, чем чтение.

Взгляните на специальные символы формата , используемые для указания struct, как упаковать и распаковать двоичные данные.

...