Записать данные IMU в CSV-файл, используя буфер и буфер переполнения? - PullRequest
0 голосов
/ 22 марта 2019

Я пытался реализовать дополнительный фильтр C ++ для IMU LSM9DS1, подключенного через I2C к плате mbed, но из-за проблем с синхронизацией я не получил правильную интеграцию угловой скорости. Это потому, что в моем коде я предполагаю, что моя частота дискретизации составляет 100 Гц, хотя это не совсем частота, с которой данные отбираются из-за операторов printf (), которые я использую для отображения значений в реальном времени. Это приводит к тому, что мои углы вывода фильтра смещаются / не возвращаются к исходному значению, когда IMU возвращается в исходное положение.

Мне рекомендовали выполнить следующие шаги, чтобы избежать задержек в моем коде, которые могут нарушить работу моего чувствительного ко времени приложения:

  • На каждой итерации программы добавляйте необработанные данные IMU в буфер
  • Когда буфер почти заполнен, используйте прерывание для записи всех данных из буфер в файл .csv
  • Когда / если буфер переполнен, добавьте оставшиеся данные в новый «переполнение» буфер "
  • Очистить первый буфер и заполнить его данными, хранящимися в переполнении буфер и т. д.
  • Обрабатывать фильтрацию вычислений отдельно, обрабатывая данные вручную из файла .csv, как только все это было собрано, чтобы избежать синхронизации проблемы, и посмотрите, если результат соответствует ожиданиям

Весь буфер / переполнение буфера туда-сюда действительно смущает меня, может кто-нибудь помочь мне объяснить, как технически выполнить вышеупомянутые шаги? Заранее спасибо!

Редактировать:

#include "LSM9DS1.h"
#define DT 1/100

void runFilter()
{
    // calculate Euler angles from accelerometer and magnetometer (_roll, 
    // _pitch,_yaw)
    calcAttitude(imu.ax, imu.ay, imu.az, -imu.my, -imu.mx, imu.mz);

    _gyroAngleX += (_rateX*DT);
    _gyroAngleY += (_rateY*DT);
    _gyroAngleZ += (_rateZ*DT);

    _xfilt = 0.98f*(_gyroAngleX) + 0.02f*_roll;
    _yfilt = 0.98f*(_gyroAngleY) + 0.02f*_pitch;
    _zfilt = 0.98f*(_gyroAngleZ) + 0.02f*_yaw;

    printf("%.2f, %.2f, %.2f \n", _xfilt, _yfilt, _zfilt);
}

в main.cpp:

int main()
{
    init(); // Initialise IMU
    while(1) {
        readValues(); // Read data from the IMUs
        runFilter(); 
    }
 }

1 Ответ

1 голос
/ 25 марта 2019

Как Кентаро также упоминал в комментариях, используйте отдельный поток для printf и используйте MQ OS EventQueue, чтобы отложить для него операторы printf.

EventQueue queue;
Thread event_thread(osPriorityLow);

int main() {
    event_thread.start(callback(&queue, &EventQueue::dispatch_forever));

    // after sampling
    queue.call(&printf, "%.2f, %.2f, %.2f \n", _xfilt, _yfilt, _zfilt);

Однако, вы все равно можете столкнуться с проблемами со скоростью. Некоторые общие советы:

  1. Используйте максимальную скорость передачи данных, которую может обработать ваша плата разработки.
  2. Используйте RawSerial объект над printf (который использует Serial), чтобы избежать требования мьютекса.
  3. Не пишите в UART, а пишите в файл (например, смонтируйте FATFileSystem на SD-карту). Это будет намного быстрее.
...