
Подключение гироскопа-акселерометра MPU6050 к Wemos d1
Для того чтобы наше устройство могло отображать и записывать в лог ускорение и перегрузки во время разгона, мы подключим к нему популярный высокоточный модуль GY-521, на основе чипа MPU-6050, являющегося трех-осевым гироскопом и трех-осевым акселерометром. Гироскоп нам пока не понадобится, поэтому в этой части я буду рассказывать только про акселерометр.
Основные характеристики MPU6050:
- 16-битный АЦП
- Напряжение питания 3-5В
- Поддержка протокола I2C
- Диапазон ускорений: ± 2 ± 4 ± 8 ± 16g
- Диапазон «гиро»: ± 250 500 1000 2000 °/s
Подключение MPU6050 к Wemos d1
Модуль работает по I2C, поэтому подключить его весьма просто, соединим акселерометр с платой Wemos D1: VCC -> 3V3, GND -> GND, SCL -> D1, SDA -> D2.
Для проверки давайте зальём в плату следующий скетч:
#include <Wire.h> const int MPU_addr = 0x68; // I2C address of the MPU-6050 int16_t AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ; void setup() { Serial.begin(115200); Wire.begin(); Wire.beginTransmission(MPU_addr); Wire.write(0x6B); // PWR_MGMT_1 register Wire.write(0); // set to zero (wakes up the MPU-6050) Wire.endTransmission(true); } void loop() { Wire.beginTransmission(MPU_addr); Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H) Wire.endTransmission(false); Wire.requestFrom(MPU_addr, 14, true); // request a total of 14 registers AcX = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L) AcY = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L) AcZ = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L) Tmp = Wire.read() << 8 | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L) GyX = Wire.read() << 8 | Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L) GyY = Wire.read() << 8 | Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L) GyZ = Wire.read() << 8 | Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L) Serial.print("AcX = "); Serial.print(AcX); Serial.print(" | AcY = "); Serial.print(AcY); Serial.print(" | AcZ = "); Serial.print(AcZ); Serial.print(" | Tmp = "); Serial.print(Tmp / 340.00 + 36.53); // temperature in degrees C from datasheet Serial.print(" | GyX = "); Serial.print(GyX); Serial.print(" | GyY = "); Serial.print(GyY); Serial.print(" | GyZ = "); Serial.println(GyZ); delay(500); }
Скачать архив со скетчем: MPU6050.zip
Теперь, если вы откроете терминал com порта, то
увидите примерно следующую картину: ускорение по трём осям, температура, углы
положения по трем осям.
Из даташита, мы знаем, что при настройке чувствительности акселерометра до 2g на каждую единицу g приходится 16384 единиц измерения датчика. Самые наблюдательные наверно уже заметили по фото, что лежа на столе датчик почему-то показывает ускорения по горизонтальным осям, а по вертикальной показывает значение больше 16384 (я надеюсь все помнят со школы, что на все объекты на земле действует сила тяжести в 1g). Это проблема всех подобных акселерометров – они очень шумят. Их обязательно нужно калибровать и фильтровать получаемые данные.
Фильтр Калмана MPU6050
Давайте добавим в скетч упрощенный фильтр Калмана, для того чтобы сгладить шумы датчика.
#include <Wire.h> const int MPU_addr = 0x68; // I2C address of the MPU-6050 int16_t AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ; // переменные для Калмана float varVolt = 78.9; // среднее отклонение (ищем в excel) float varProcess = 0.5; // скорость реакции на изменение (подбирается вручную) float Pc = 0.0, G = 0.0, P = 1.0, Xp = 0.0, Zp = 0.0, Xe = 0.0; // переменные для Калмана // Функция фильтрации float filter(float val) { Pc = P + varProcess; G = Pc / (Pc + varVolt); P = (1 - G) * Pc; Xp = Xe; Zp = Xp; Xe = G * (val - Zp) + Xp; // "фильтрованное" значение return (Xe); } void setup() { Serial.begin(115200); Wire.begin(); Wire.beginTransmission(MPU_addr); Wire.write(0x6B); // PWR_MGMT_1 register Wire.write(0); // set to zero (wakes up the MPU-6050) Wire.endTransmission(true); } void loop() { Wire.beginTransmission(MPU_addr); Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H) Wire.endTransmission(false); Wire.requestFrom(MPU_addr, 6, true); // request a total of 14 registers AcX = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L) AcY = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L) AcZ = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L) Serial.print(AcZ); Serial.print(" "); Serial.println((int)filter(AcZ)); delay(100); }
Скачать архив со скетчем: MPU6050Kalman.zip
Для фильтра нам необходимо подобрать два значения:
1) varVolt - это среднее отклонение, его можно либо высчитать самостоятельно либо забить значения в файл excel который я положил в архив со скетчем
2) varProcess - это время реакции, чем меньше это число, тем плавнее будут меняться значения.
Попробуйте поиграться с этими параметрами.
Теперь зайдем в меню «Инструменты – Плоттер по последовательному соединению», откроется вот такое окно:
Синяя линия - это не фильтрованные данные, а красная это после обработки фильтром Калмана. Пики это - я поднимал и опускал акселерометр примерно на пол метра над столом. С такими данными уже можно будет комфортно работать.
На этом пока всё, в одной из следующих частей мы с вами соберем полноценный G-meter.