Стабилизация данных с четырех гироскопов/акселерометра

В настоящее время я работаю над университетским проектом. Моя цель - получить приблизительную оценку положения спины человека. Для этого я построил систему, которая собирает данные с 4 MPU6050 в центральном сервисе. Оттуда он будет визуализирован. Моя первая идея состояла в том, чтобы нарисовать 4 линии и взять углы крена за углы между линиями. Моя проблема в том, что данные MPU6050s сильно дрейфуют. Я уже создал калибровочные данные и использую дополнительный фильтр на NODEMCU, который считывает данные с MPU.

Я использую Adafruit_MPU6050.h lib для подключения к датчикам и получения данных от них. Для расчета крена, тангажа и рыскания я использую следующий код:

  sensors_event_t gyro_1;
  sensors_event_t accel_1;
  mpu_gyro_1->getEvent(&gyro_1);
  mpu_accel_1->getEvent(&accel_1);

  acc_1_angle_x = (atan(accel_1.acceleration.y / sqrt(pow(accel_1.acceleration.x, 2) + pow(accel_1.acceleration.z, 2))) * 180 / PI) - mpu_1_acc_err_x;
  acc_1_angle_y = (atan(-1 * accel_1.acceleration.x / sqrt(pow(accel_1.acceleration.y, 2) + pow(accel_1.acceleration.z, 2))) * 180 / PI) - mpu_1_acc_err_y;

  previousTime = currentTime;                        
  currentTime = millis();                           
  elapsedTime = (currentTime - previousTime) / 1000;

  gyro_1_angle_x = gyro_1_angle_x + (gyro_1.gyro.x - mpu_1_gyro_err_x) * elapsedTime; // deg/s * s = deg
  gyro_1_angle_y = gyro_1_angle_y + (gyro_1.gyro.y - mpu_1_gyro_err_y) * elapsedTime;
  yaw_1 = yaw_1 + (gyro_1.gyro.z - mpu_1_gyro_err_z) * elapsedTime;
  roll_1 = 0.96 * gyro_1_angle_x + 0.04 * acc_1_angle_x;
  pitch_1 = 0.96 * gyro_1_angle_y + 0.04 * acc_1_angle_y;

Как я могу сделать свои данные более стабильными? Я попытался поиграть с 0.96 и 0.04, чтобы изменить объем данных, которые я использую с гироскопа, но стало только хуже.

Если вам интересно, это мой проект github: https://github.com/Trojan13/posture-control

Заранее спасибо за ваш вклад!

, 👍1

Обсуждение

Визуализация данных на ПК здесь не по теме. Что не так с вашей идеей с линиями?, @chrisl

Хорошо, спасибо. Где бы вы посоветовали мне спросить? В настоящее время проблема заключается в том, что линии либо становятся дрожащими, либо дрейфуют к жестким., @Trojan

Вам нужно изолировать проблемы. Когда данные слишком дрожат и дрейфуют, это не имеет ничего общего с визуализацией. Вы можете спросить о том, как сделать ваши данные более стабильными. Затем вы должны показать свой код Arduino и показать на фактических данных, сколько джиттера и дрейфа у вас на самом деле есть., @chrisl

Углы крена, тангажа и рыскания не могут быть измерены непосредственно: MPU измеряет ускорение и гироскоп, а затем он (или вы) интегрирует гироскоп, чтобы оценить углы. Численное интегрирование измеренных данных подвержено дрейфам, поэтому вы должны использовать accel для оценки низкочастотной части крена и тангажа (и вам нужен компас, если вы хотите рыскать). Если у вас слишком большой дрейф, настройте фильтр, чтобы придать больше веса ускорению и меньше интеграции гироскопа., @Edgar Bonet

Извините, ребята. Я скорректировал свой вопрос, чтобы сделать его более точным и подходящим для этой платы. @EdgarBonet Я уже использую фильтр для коррекции значений. Кроме того, я использую фильтр lowpas, предоставленный библиотекой adafruit. "MPU6050_BAND_44_HZ", @Trojan

Если вы добавите неверные поправки к данным гироскопа, это может привести к довольно сильному дрейфу. Проверьте свои запросы на вытягивание., @Edgar Bonet

название вашего поста не соответствует проблеме, которую вы пытаетесь решить ... кто-то, кто является экспертом в получении стабильных показаний, может просто не смотреть на ваш пост, @jsotola

осанка для здоровья позвоночника относительна. лично я отдал бы предпочтение тензометрическим датчикам. скорее всего, ваши фильтры и/или источники данных управляются / фильтруются неправильно. с несколькими mpu6050 на жесткой конструкции вам нужно смешать ускорения от разных устройств с гироскопами от одного устройства, чтобы получить разумный угол для одного устройства. тем не менее, он будет дрейфовать, поэтому вам нужно добавить больше источников или предположений (гравитация - хорошая халява, и с 4 очками m8 будет достаточно)., @Abel


2 ответа


Лучший ответ:

4

Глядя на ваш код, я вижу, что единственное место, где обновляется gyro_1_angle_x, находится здесь:

gyro_1_angle_x = gyro_1_angle_x
    + (gyro_1.gyro.x - mpu_1_gyro_err_x) * elapsedTime;

Это добавляет к gyro_1_angle_x величину, которая не зависит от самого gyro_1_angle_x. Это означает, что при наличии неисправленной систематической ошибки в измерении gyro_1.gyro.x (которая всегда есть, так как вы никогда не сможете достичь идеальной калибровки) ошибки будут накапливаться, приводя к неограниченному дрейфу. Затем вы оцениваете угол крена следующим образом:

roll_1 = 0.96 * gyro_1_angle_x + 0.04 * acc_1_angle_x;

Коэффициент 0.96 незначительно уменьшает величину дрейфа (на 4%), но не меняет качественного поведения: roll_1 также подвержен неограниченному дрейфу.

Предлагаемый подход

Мое предложение будет заключаться в том, чтобы забыть об углах. Использование углов для отслеживания положения вашего устройства-плохая идея: формулы, необходимые для обновления углов, сложны (и поэтому легко ошибиться), дороги в вычислительном отношении и подвержены блокировке кардана. Для отслеживания всего отношения было бы более разумно использовать матрицы вращения или, еще лучше, кватернионы.

Однако в вашем случае вам не нужно отслеживать все отношение. У вас нет средств надежно отслеживать угол рыскания, и вы на самом деле даже не заботитесь об этом угле. Вас интересует только ориентация устройства относительно вертикального направления. Поэтому я предлагаю вам даже не пытаться отслеживать отношение, а вместо этого просто отслеживать вертикальное направление. Это направление задается координатами вектора гравитации в системе отсчета прибора. Тогда у вас есть только один вектор для отслеживания. Никаких углов, никаких матриц, никаких кватернионов - просто простой вектор.

Использование акселерометров

Акселерометры чувствительны к гравитации, поэтому вы можете использовать их показания в качестве оценки вектора гравитации, как в следующем псевдокоде:

at each time step:
    (accel, gyro) = read_MPU();
    gravity = accel;

Это может дать вам противоположность гравитации (направление зенита). Это нормально, если вы знаете, какой вектор вы отслеживаете.

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

Использование гироскопов

Чтобы избавиться от ошибок, вызванных ускорением, вы можете вместо этого использовать показания гироскопа. Предполагая, что вам каким-то образом удастся получить начальную оценку вектора гравитации, вы можете использовать показания гироскопа для итеративного обновления этой оценки:

at each time step:
    (accel, gyro) = read_MPU();
    dt = time_since_previous_time_step;
    rotation = - dt * gyro;
    gravity = apply_rotation(rotation, gravity);

здесь вращение-это вектор вращения, описывающий, насколько сильно гравитация повернулась с предыдущего временного шага. Знак минус в его формуле исходит из того факта, что гироскоп дает вам вращение устройства относительно неподвижной системы отсчета, тогда как вы хотите вращение неподвижного вектора относительно системы отсчета устройства. Функция apply_rotation() применит формулу вращения Родригеса, чтобы повернуть вектор гравитации в его новую ориентацию.

Этот подход не страдает от ошибок, вызванных ускорением. Однако он склонен к дрейфу, так как объединение большого количества небольших вращений приводит к накоплению большого количества мелких ошибок.

Объединение данных гироскопа и акселерометра

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

  • используйте данные гироскопа для поворота текущей оценки вектора гравитации
  • затем осторожно “перемешайте” его в направлении показаний акселерометра.

В псевдокоде это будет выглядеть так:

at each time step:
    (accel, gyro) = read_MPU();
    dt = time_since_previous_time_step;
    rotation = - dt * gyro;
    gravity = apply_rotation(rotation, gravity);
    gravity = gravity + (dt/tau) * (accel - gravity)

Последняя строка имеет эффект незначительного подталкивания оценки гравитации к показаниям акселерометра. Обратите внимание, что эта строка выглядит как реализация фильтра нижних частот первого порядка с постоянной времени тау. Эта постоянная времени определяет границу между “короткими” временными шкалами, где вы доверяете гироскопам больше, чем акселерометрам, и “длинными” временными шкалами, где вы больше доверяете акселерометрам. Значение тау должно быть выбрано экспериментально. Он управляет компромиссом между шумом, исходящим от ускорения, и систематической ошибкой , исходящей от гироскопов.

С помощью этой формулы накопленные ошибки гироскопа всегда будут оставаться связанными, а общая ошибка пропорциональна тау. Поскольку пошаговые вращения , по-видимому, очень малы, и поскольку ошибки вращения не накапливаются неограниченным образом, вы, вероятно, можете избежать использования линеаризации формулы вращения Родригеса (cos θ = 1, sin θ = θ):

gravity = gravity + rotation × gravity

и тогда вам вообще не нужна тригонометрия.

Стоит также отметить, что при таком подходе можно смело инициализировать гравитацию до нуля: она сразу же начнет расти по мере выполнения программы, и ее величина со временем сойдется к соответствующему значению.

Получение подачи и крена

Как только вы знаете вектор гравитации, вы можете легко вычислить тангаж и крен. Я не говорю, что вы должны полностью избегать использования углов: вероятно, вам нужны углы в вашем пользовательском интерфейсе. Я хочу сказать, что вы должны воздерживаться от использования углов для отслеживания ориентации устройства. Вычисление углов в качестве шага постобработки- это прекрасно.

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

,

Я предполагаю, что описанный подход все равно приведет к отклонению от курса, верно?, @Runsva

@Runsva: Этот подход отслеживает только вектор силы тяжести, по которому вы можете вычислить тангаж и крен, но _не_ рыскание. Предполагается, что вас не волнует рыскание, как и в случае с ОП., @Edgar Bonet


2

У вас есть правильная идея объединить данные как с гироскопа, так и с акселерометра. Тем не менее, я бы настоятельно не советовал делать слияние самостоятельно, так как на вашем MPU-6050 есть специальный цифровой процессор движения (DMP), который делает это за вас. Вам просто нужна библиотека, которая захватывает данные из DMP. Насколько я знаю, единственные библиотеки Arduino, которые делают это, основаны на работе Джеффа Роуберга.

Данные, выводимые DMP, находятся в формате кватернионов. Джефф преобразует его в рыскание по тангажу и крену, но его преобразование имеет недостатки (он производит паразитные перевороты и вращения на северном и южном полюсах, называемые карданной блокировкой). Не волнуйся, это можно исправить.

Если вы используете библиотеку Джеффа (или ту, которая основана на ней), вам нужно будет убедиться, что детектор находится на одном уровне и неподвижен, прежде чем отправлять символ по последовательному каналу для запуска калибровки, и вам нужно делать это каждый раз при включении питания. Библиотека и скетчи несколько ошеломляют/пугают новых пользователей. Это тоже можно исправить.

Если ты этого захочешь

(а) Узнайте больше обо всей этой теме

(b) Используйте правильное преобразование из кватерниона в крен шага рыскания (тот, который не производит блокировку кардана).

(c) Скрыть библиотеку Джеффа за простым и удобным в использовании интерфейсом

(d) Выполните калибровку только один раз и сохраните эти результаты в постоянной памяти вашего arduino, чтобы вам не приходилось повторять калибровку каждый раз при включении устройства.

Тогда я бы порекомендовал следующий учебник:

https://youtu.be/k5i-vE5rZR0

,