MPU6050 — это 6-осевой инерциальный датчик (IMU, Inertial Measurement Unit) производства InvenSense, объединяющий в одном корпусе 3-осевой МЭМС-гироскоп и 3-осевой МЭМС-акселерометр. Отличительная особенность чипа — встроенный DMP (Digital Motion Processor), аппаратный блок, способный самостоятельно выполнять сенсорное слияние (sensor fusion) и выдавать готовые кватернионы ориентации, снижая нагрузку на микроконтроллер. Чаще всего встречается в виде готового модуля GY-521. Используется в балансирующих роботах и сегвеях, квадрокоптерах, системах стабилизации изображения и управления жестами.
- 1 Распиновка модуля GY-521 (MPU6050)
- 2 Технические характеристики MPU6050
- 3 Принцип работы и DMP
- 4 Структурная схема MPU6050
- 5 Девятиосевое слияние данных по I2C: подключение магнитометра
- 6 Типовая схема включения чипа
- 7 Подключение к Arduino
- 8 Библиотеки
- 9 Применение
- 10 Калибровка смещения нуля (offset)
- 11 Сенсорное слияние: простой фильтр без DMP
- 12 MPU6050 и аналоги
- 13 Типичные проблемы
- 14 Материалы и Datasheet
- 15 Читайте также
Распиновка модуля GY-521 (MPU6050)
| Вывод | Описание |
|---|---|
| VCC | Питание |
| GND | Земля |
| SCL | Линия тактирования I2C (Serial CLock) |
| SDA | Линия данных I2C (Serial DAta) |
| XDA / XCL | Вспомогательная шина I2C для подключения внешних датчиков (например, магнитометра) |
| AD0 | Выбор адреса I2C |
| INT | Выход прерывания |
Так выглядит модуль GY-521: вид сверху (на плате подписаны выводы и нанесены обозначения осей X и Y) и вид снизу (контактные площадки выводов).
Технические характеристики MPU6050
- Интерфейс: I2C (до 400 кГц в Fast-mode). SPI есть только у родственной микросхемы MPU-6000, у MPU6050 его нет
- Акселерометр: 3 оси, программируемый диапазон ±2/±4/±8/±16 g, ток потребления 500 мкА
- Гироскоп: 3 оси, программируемый диапазон ±250/±500/±1000/±2000 °/с, ток потребления 3,6 мА
- АЦП: 16-битный, по одному на каждую из 6 осей
- Частота выборки: гироскоп 4–8000 Гц, акселерометр 4–1000 Гц; программируемые фильтры низких частот
- Встроенный DMP: аппаратное сенсорное слияние, расчёт кватернионов; ток потребления при включённых 6 осях и DMP 3,9 мА
- Встроенный датчик температуры: диапазон -40…+85 °C
- Буфер FIFO: 1024 байта
- Напряжение питания чипа (VDD): 2,375–3,46 В (на модуле GY-521 стоит стабилизатор для работы от 3,3–5 В)
- I2C адрес: 0x68 (0x69, если AD0 подключен к VCC)
- Ударопрочность: до 10 000 g
- Размеры чипа: 4 х 4 х 0,9 мм (QFN)
Чувствительность: во сколько раз делить показания
Чип выдаёт «сырые» числа АЦП, а чтобы получить физические величины, их нужно делить на коэффициент, который зависит от выбранного диапазона. После включения питания по умолчанию выбраны диапазоны ±2 g и ±250 °/с.
| Диапазон акселерометра | Коэффициент, LSB/g | Диапазон гироскопа | Коэффициент, LSB/(°/с) |
|---|---|---|---|
| ±2 g | 16384 | ±250 °/с | 131 |
| ±4 g | 8192 | ±500 °/с | 65,5 |
| ±8 g | 4096 | ±1000 °/с | 32,8 |
| ±16 g | 2048 | ±2000 °/с | 16,4 |
Например, если акселерометр лежит горизонтально (диапазон ±2 g), по оси Z получится около 16384, то есть +1 g.
Принцип работы и DMP
Гироскоп и акселерометр — это МЭМС-структуры: миниатюрные механические элементы на кристалле, изменяющие электрическую емкость при ускорении (акселерометр) или воздействии кориолисовой силы при вращении (гироскоп). Сырые данные (raw) с каждой оси представляют собой 16-битные знаковые числа (дополнительный код) в условных единицах АЦП — их нужно делить на коэффициент чувствительности (зависит от выбранного диапазона, см. таблицу выше) для получения g или °/с. Главная сложность в работе с IMU — дрейф и шум: акселерометр подвержен шуму и вибрациям, а показания гироскопа со временем «уплывают» (drift) из-за интегрирования угловой скорости. Встроенный DMP объединяет данные обоих сенсоров прямо в чипе и отдаёт уже готовую ориентацию в виде кватернионов, но настройка и работа с DMP существенно сложнее, чем чтение сырых данных: прошивку DMP нужно загружать в чип при каждом включении питания, это делает библиотека i2cdevlib.
Оси чувствительности и направление вращения
Все показания привязаны к осям X, Y и Z относительно корпуса микросхемы. На рисунке из даташита стрелками показаны положительные направления осей и положительное направление вращения вокруг каждой из них, а точка на корпусе обозначает вывод 1. Знак показаний гироскопа и акселерометра определяется именно этими направлениями, поэтому перед использованием в проекте стоит проверить, как модуль повёрнут относительно вашей конструкции. На модуле GY-521 направления осей X и Y нанесены на плату рядом с микросхемой (см. фото выше), ось Z направлена от платы к вам.
Структурная схема MPU6050
Структурная схема из даташита одинаковая для MPU-6000 и MPU-6050. Названия выводов в круглых скобках относятся только к MPU-6000, а в квадратных (например, [VLOGIC] на выводе 8) только к MPU-6050.
- Датчики. Три гироскопа (X, Y, Z) и три акселерометра, у каждого свой 16-битный АЦП, а затем общий блок обработки сигналов (Signal Conditioning). У каждого датчика есть собственный блок самотестирования (Self test). Рядом стоит датчик температуры с АЦП;
- Регистры, FIFO и прерывания. Результаты измерений попадают в регистры данных (Sensor Registers) и в буфер FIFO на 1024 байта, а настройками управляют конфигурационные регистры (Config Registers). Выход INT (вывод 12) сообщает микроконтроллеру о новых данных;
- DMP (Digital Motion Processor) обрабатывает данные датчиков и складывает результат в FIFO;
- Основной интерфейс. Через выводы SCL и SDA микроконтроллер читает регистры, у MPU-6000 ещё есть SPI. У MPU6050 вывод 9 (AD0) задаёт младший бит I2C-адреса;
- Вспомогательный интерфейс. Выводы AUX_DA и AUX_CL (6 и 7) — вторая шина I2C, по которой сам чип может читать внешние датчики, например магнитометр. Интерфейсный мультиплексор (Serial Interface Bypass Mux) позволяет соединить её напрямую с основной шиной;
- Питание и тактирование. Внутренний стабилизатор (Bias & LDO) формирует напряжение REGOUT, а генератор напряжения (Charge Pump, вывод CPOUT) нужен для работы датчиков. Тактовый генератор (CLOCK) работает от внутреннего источника с точностью ±1% или от внешнего сигнала на выводе CLKIN (32,768 кГц или 19,2 МГц);
- Вывод FSYNC (11) принимает внешний синхросигнал для синхронизации с видео или GPS.
Девятиосевое слияние данных по I2C: подключение магнитометра
Для определения абсолютного направления (компаса) к MPU6050 можно подключить внешний магнитометр. Чип умеет собирать данные с него сам: у него есть вторая, вспомогательная шина I2C (выводы AUX_DA и AUX_CL, на модуле GY-521 они выведены как XDA и XCL), а DMP объединяет данные гироскопа, акселерометра и магнитометра в 9-осевой результат.
Схема работает так:
- микроконтроллер (системный процессор) подключён к основной шине I2C чипа и читает через неё все данные и настраивает всё остальное;
- сам MPU6050 для магнитометра выступает ведущим устройством (мастером) на вспомогательной шине, но возможности у него ограничены, поэтому первоначально настроить магнитометр должен микроконтроллер;
- для этого в чипе есть интерфейсный мультиплексор, который соединяет основную шину (выводы 23 и 24, SCL и SDA) напрямую со вспомогательной (выводы 6 и 7), и микроконтроллер видит магнитометр как будто он подключён к нему самому;
- когда магнитометр настроен, мультиплексор нужно отключить, и тогда вспомогательный мастер чипа берёт управление шиной на себя и сам собирает данные с магнитометра.
Такой режим нужен только при подключении внешнего датчика, а для обычной работы с гироскопом и акселерометром вспомогательную шину можно не трогать. Подробности про управление вспомогательным мастером даташит выносит в раздел 10 и в документ Register Map.
Типовая схема включения чипа
Если вы делаете собственную плату на MPU6050, а не используете готовый модуль, обвязка чипа состоит всего из четырёх конденсаторов. На модуле GY-521 она уже установлена, вместе со стабилизатором напряжения и резисторами шины I2C.
| Деталь | Вывод чипа | Назначение | Параметры |
|---|---|---|---|
| C1 | 10 (REGOUT) | Конденсатор внутреннего стабилизатора | 0,1 мкФ, керамика X7R, ±10%, не менее 2 В |
| C2 | 13 (VDD) | Блокировочный конденсатор питания | 0,1 мкФ, керамика X7R, ±10%, не менее 4 В |
| C3 | 20 (CPOUT) | Конденсатор генератора напряжения (Charge Pump) | 2,2 нФ, керамика X7R, ±10%, 50 В |
| C4 | 8 (VLOGIC) | Блокировочный конденсатор питания логики, только у MPU6050 | 10 нФ, керамика X7R, ±10%, не менее 4 В |
Вывод VLOGIC задаёт уровни сигналов шины I2C: это 1,8 В ±5% или напряжение VDD. Порядок включения питания важен: напряжение VLOGIC никогда не должно быть выше VDD, оба напряжения должны нарастать плавно, время нарастания VDD (от 10% до 90%) не больше 100 мс, а VLOGIC не больше 3 мс. Выводы SDA, SCL и AD0, INT и FSYNC подключают так, как показано на схеме: AD0 к земле или к питанию, FSYNC, если синхронизация не нужна, к земле.
Подключение к Arduino
| Arduino Uno/Nano/Pro Mini | MPU6050 |
|---|---|
| 5V | VCC |
| GND | GND |
| A4 (SDA) | SDA |
| A5 (SCL) | SCL |
Библиотеки
Arduino:
- i2cdevlib (jrowberg) — исходная и самая функциональная библиотека, включает полноценную работу с DMP (кватернионы, углы Эйлера).
- Adafruit_MPU6050 — простая библиотека в стиле Adafruit Unified Sensor, без DMP, но с удобным API для сырых данных акселерометра/гироскопа и температуры.
- MPU6050 (Electronic Cats) — форк i2cdevlib с добавленной поддержкой ESP32, ESP8266 и других платформ.
Raspberry Pi / Python: пакет mpu6050-raspberrypi (pip install mpu6050-raspberrypi), работает через smbus/smbus2, предоставляет методы get_accel_data(), get_gyro_data(), get_temp().
MicroPython (ESP32/ESP8266): сообществом поддерживаются несколько реализаций драйвера mpu6050.py, работающих через стандартный модуль machine.I2C.
Пример скетча: настройка и чтение данных без библиотек
Ниже полноценный пример, который работает только со стандартной библиотекой Wire. Он проверяет, что на шине действительно MPU6050, настраивает датчик, определяет смещение нуля гироскопа и выводит в Монитор порта ускорения в g, угловые скорости в °/с, температуру и углы наклона. Если датчик пропадёт с шины, программа сообщит об ошибке и настроит его заново.
Что делает программа
| Шаг | Регистр | Что записываем или читаем |
|---|---|---|
| Проверка | WHO_AM_I (0x75) | Читаем байт: у MPU6050 всегда 0x68, независимо от состояния вывода AD0. Если ответа нет, значит, неверно подключены провода или адрес |
| Сброс | PWR_MGMT_1 (0x6B) | Записываем 0x80: все регистры возвращаются к значениям по умолчанию. После сброса чип засыпает, поэтому нужна пауза 100 мс |
| Пробуждение | PWR_MGMT_1 (0x6B) | Записываем 0x01: выходим из спящего режима и берём тактовую частоту от гироскопа оси X. Производитель рекомендует именно такой источник, он точнее встроенного генератора |
| Фильтр | CONFIG (0x1A) | Значение 3: цифровой фильтр с полосой около 44 Гц у акселерометра и 42 Гц у гироскопа, он подавляет шум и вибрации. Включённый фильтр задаёт частоту выборки гироскопа 1 кГц |
| Частота выборки | SMPLRT_DIV (0x19) | Значение 9: частота = 1000 / (1 + 9) = 100 Гц |
| Диапазон гироскопа | GYRO_CONFIG (0x1B) | Биты 4..3: 0 = ±250 °/с, 1 = ±500, 2 = ±1000, 3 = ±2000. В примере 0 |
| Диапазон акселерометра | ACCEL_CONFIG (0x1C) | Биты 4..3: 0 = ±2 g, 1 = ±4, 2 = ±8, 3 = ±16. В примере 0 |
| Чтение данных | ACCEL_XOUT_H (0x3B) | За один запрос читаем 14 байт подряд: ускорения X, Y, Z, температура, угловые скорости X, Y, Z. Каждое значение занимает два байта, старший байт идёт первым |
Если вы меняете диапазоны, замените в скетче и коэффициенты ACCEL_LSB_PER_G и GYRO_LSB_PER_DPS на значения из таблицы чувствительности выше.
#include <Wire.h>
/*
MPU6050 без сторонних библиотек: настройка и чтение данных по I2C.
Плата: Arduino Uno/Nano/Pro Mini, модуль GY-521.
VCC -> 5V, GND -> GND, SDA -> A4, SCL -> A5.
Монитор порта: 115200 бод.
*/
// Адрес на шине I2C (0x69, если вывод AD0 подключён к питанию)
const uint8_t MPU_ADDR = 0x68;
// Регистры MPU6050 (из документа Register Map)
const uint8_t REG_SMPLRT_DIV = 0x19; // делитель частоты выборки
const uint8_t REG_CONFIG = 0x1A; // цифровой фильтр низких частот (DLPF)
const uint8_t REG_GYRO_CONFIG = 0x1B; // диапазон гироскопа
const uint8_t REG_ACCEL_CONFIG = 0x1C; // диапазон акселерометра
const uint8_t REG_ACCEL_XOUT_H = 0x3B; // с него начинаются 14 байт данных
const uint8_t REG_PWR_MGMT_1 = 0x6B; // питание и источник тактовой частоты
const uint8_t REG_WHO_AM_I = 0x75; // всегда читается 0x68
// Коэффициенты для диапазонов ±2 g и ±250 °/с (см. таблицу чувствительности)
const float ACCEL_LSB_PER_G = 16384.0;
const float GYRO_LSB_PER_DPS = 131.0;
// Сколько раз усреднять показания гироскопа при калибровке
const uint16_t CALIBRATION_SAMPLES = 200;
// Как часто выводить данные, мс
const uint16_t PRINT_INTERVAL_MS = 200;
// Смещение нуля гироскопа в «сырых» единицах (определяется при запуске)
int16_t gyroOffsetX = 0;
int16_t gyroOffsetY = 0;
int16_t gyroOffsetZ = 0;
uint32_t lastPrintTime = 0;
/*
Записывает один байт в регистр.
Возвращает true, если датчик подтвердил приём.
*/
bool writeRegister(uint8_t reg, uint8_t value) {
Wire.beginTransmission(MPU_ADDR);
Wire.write(reg);
Wire.write(value);
return Wire.endTransmission() == 0;
}
/*
Читает подряд len байт, начиная с регистра reg.
Возвращает true, если все байты получены.
*/
bool readRegisters(uint8_t reg, uint8_t *buffer, uint8_t len) {
Wire.beginTransmission(MPU_ADDR);
Wire.write(reg);
// false: не освобождаем шину, чтобы сразу прочитать ответ
if (Wire.endTransmission(false) != 0) {
return false;
}
if (Wire.requestFrom(MPU_ADDR, len) != len) {
return false;
}
for (uint8_t i = 0; i < len; i++) {
buffer[i] = Wire.read();
}
return true;
}
/*
Собирает число со знаком из двух байт (старший байт идёт первым).
*/
int16_t toInt16(const uint8_t *bytes) {
return (int16_t)((bytes[0] << 8) | bytes[1]);
}
/*
Читает все шесть осей и температуру одной посылкой.
Результат в «сырых» единицах АЦП.
*/
bool readRaw(int16_t &ax, int16_t &ay, int16_t &az,
int16_t &temp,
int16_t &gx, int16_t &gy, int16_t &gz) {
uint8_t data[14];
if (!readRegisters(REG_ACCEL_XOUT_H, data, sizeof(data))) {
return false;
}
ax = toInt16(&data[0]);
ay = toInt16(&data[2]);
az = toInt16(&data[4]);
temp = toInt16(&data[6]);
gx = toInt16(&data[8]);
gy = toInt16(&data[10]);
gz = toInt16(&data[12]);
return true;
}
/*
Настраивает датчик. Возвращает false, если он не отвечает
или это не MPU6050.
*/
bool initMpu() {
uint8_t whoAmI = 0;
if (!readRegisters(REG_WHO_AM_I, &whoAmI, 1)) {
Serial.println(F("MPU6050 не отвечает: проверьте провода и адрес"));
return false;
}
if (whoAmI != 0x68) {
Serial.print(F("Неожиданный WHO_AM_I: 0x"));
Serial.println(whoAmI, HEX);
return false;
}
// Сброс всех регистров в значения по умолчанию (бит DEVICE_RESET)
writeRegister(REG_PWR_MGMT_1, 0x80);
delay(100);
// Выходим из спящего режима и берём тактовую частоту от гироскопа по оси X:
// так рекомендует производитель, это точнее встроенного генератора
if (!writeRegister(REG_PWR_MGMT_1, 0x01)) {
return false;
}
delay(50);
// Цифровой фильтр низких частот: значение 3 это около 44 Гц у акселерометра
// и 42 Гц у гироскопа. Он убирает высокочастотный шум и вибрации.
// Частота выборки гироскопа при включённом фильтре равна 1 кГц
writeRegister(REG_CONFIG, 3);
// Частота выборки = 1000 Гц / (1 + SMPLRT_DIV) = 1000 / (1 + 9) = 100 Гц
writeRegister(REG_SMPLRT_DIV, 9);
// Диапазон гироскопа: 0 = ±250 °/с, 1 = ±500, 2 = ±1000, 3 = ±2000 (биты 4..3)
writeRegister(REG_GYRO_CONFIG, 0 << 3);
// Диапазон акселерометра: 0 = ±2 g, 1 = ±4, 2 = ±8, 3 = ±16 (биты 4..3)
writeRegister(REG_ACCEL_CONFIG, 0 << 3);
delay(100);
return true;
}
/*
Определяет смещение нуля гироскопа. Во время калибровки
датчик должен лежать неподвижно.
*/
void calibrateGyro() {
int32_t sumX = 0;
int32_t sumY = 0;
int32_t sumZ = 0;
uint16_t good = 0;
for (uint16_t i = 0; i < CALIBRATION_SAMPLES; i++) {
int16_t ax, ay, az, temp, gx, gy, gz;
if (readRaw(ax, ay, az, temp, gx, gy, gz)) {
sumX += gx;
sumY += gy;
sumZ += gz;
good++;
}
delay(10); // выборка идёт с частотой 100 Гц
}
if (good > 0) {
gyroOffsetX = sumX / good;
gyroOffsetY = sumY / good;
gyroOffsetZ = sumZ / good;
}
}
void setup() {
Serial.begin(115200);
Wire.begin();
Wire.setClock(400000); // быстрый режим I2C, 400 кГц
if (!initMpu()) {
Serial.println(F("Остановка: датчик не настроен"));
while (true) {
delay(1000);
}
}
Serial.println(F("Калибровка гироскопа: не двигайте датчик..."));
calibrateGyro();
Serial.println(F("Готово"));
}
void loop() {
if (millis() - lastPrintTime < PRINT_INTERVAL_MS) {
return;
}
lastPrintTime = millis();
int16_t rawAx, rawAy, rawAz, rawTemp, rawGx, rawGy, rawGz;
if (!readRaw(rawAx, rawAy, rawAz, rawTemp, rawGx, rawGy, rawGz)) {
Serial.println(F("Ошибка чтения, пробуем настроить датчик заново"));
initMpu();
return;
}
// Перевод в физические величины
float ax = rawAx / ACCEL_LSB_PER_G; // g
float ay = rawAy / ACCEL_LSB_PER_G;
float az = rawAz / ACCEL_LSB_PER_G;
float gx = (rawGx - gyroOffsetX) / GYRO_LSB_PER_DPS; // °/с
float gy = (rawGy - gyroOffsetY) / GYRO_LSB_PER_DPS;
float gz = (rawGz - gyroOffsetZ) / GYRO_LSB_PER_DPS;
float temperature = rawTemp / 340.0 + 36.53; // °C, формула из Register Map
// Углы наклона по акселерометру (в покое): крен вокруг X, тангаж вокруг Y
float roll = atan2(ay, az) * 180.0 / PI;
float pitch = atan2(-ax, sqrt(ay * ay + az * az)) * 180.0 / PI;
Serial.print(F("Acc g: "));
Serial.print(ax, 2); Serial.print(' ');
Serial.print(ay, 2); Serial.print(' ');
Serial.print(az, 2);
Serial.print(F(" | Gyro °/с: "));
Serial.print(gx, 1); Serial.print(' ');
Serial.print(gy, 1); Serial.print(' ');
Serial.print(gz, 1);
Serial.print(F(" | T: "));
Serial.print(temperature, 1);
Serial.print(F(" °C | Крен: "));
Serial.print(roll, 1);
Serial.print(F("° Тангаж: "));
Serial.print(pitch, 1);
Serial.println(F("°"));
}
Результат
В Мониторе порта (скорость 115200 бод) сначала появится сообщение о калибровке гироскопа, во время которой датчик должен лежать неподвижно, а затем строки такого вида:
Acc g: -0.07 -0.01 1.09 | Gyro °/с: -0.1 0.0 -0.1 | T: 27.1 °C | Крен: -0.5° Тангаж: 3.5°
Так выглядит вывод на реальном модуле GY-521 с Arduino Uno. Датчик лежит на столе: ускорение по оси Z около 1 g, угловые скорости близки к нулю, потому что гироскоп откалиброван при запуске. Заметно и смещение нуля акселерометра: по оси X он показывает −0,07 g, а по оси Z 1,09 g. Из-за этого датчик «думает», что наклонён на 3,5° по тангажу, хотя лежит ровно. В последних строках датчик взяли в руки и наклонили: ускорения, углы и угловые скорости заметно изменились.
Акселерометр в примере не калибруется, поэтому в покое его показания отличаются от идеальных. По даташиту начальное отклонение нуля может достигать ±50 mg по осям X и Y и ±80 mg по оси Z, а у конкретного модуля оно бывает и больше. Отклонение в 0,07 g даёт ошибку угла около 4°, так что для точных углов акселерометр тоже нужно калибровать. Крен (roll) и тангаж (pitch) в примере считаются только по акселерометру и работают, пока датчик неподвижен или движется плавно. Резкие движения создают ускорения, которые искажают угол. В разделе про комплементарный фильтр ниже показано, как соединить их с данными гироскопа.
Применение
- Балансирующие роботы и сегвеи (определение угла наклона для удержания равновесия);
- Квадрокоптеры и другие дроны (стабилизация полёта по показаниям гироскопа и акселерометра);
- Системы стабилизации изображения (gimbal) для камер;
- Управление жестами (наклон контроллера меняет поведение устройства);
- Шагомеры и трекеры активности (обнаружение характерных пиков ускорения при ходьбе);
- Определение ориентации устройства (портретная/ландшафтная) в самодельных гаджетах.
Калибровка смещения нуля (offset)
Из-за технологического разброса МЭМС-структур у каждого экземпляра MPU6050 есть собственное отклонение нулевой точки (offset) — если положить датчик на идеально горизонтальную поверхность, акселерометр по оси Z покажет не ровно 1g, а, например, 0,96g, а гироскоп в состоянии покоя может показывать небольшое ненулевое значение вместо нуля. По даташиту начальное отклонение нуля акселерометра может достигать ±50 mg по осям X и Y и ±80 mg по оси Z, а гироскопа — ±20 °/с. Перед точными измерениями калибровку выполняют одним из способов:
- Снять показания в состоянии покоя несколько сотен раз, усреднить и вычесть полученное смещение из всех последующих измерений (простой программный способ);
- Воспользоваться готовым скетчем калибровки
IMU_Zeroиз состава библиотеки i2cdevlib — он автоматически подбирает регистры смещения (offset registers), встроенные в сам чип; - Для гироскопа дополнительно учитывать температурный дрейф — смещение нуля гироскопа слегка меняется при изменении температуры чипа (до ±20 °/с во всём рабочем диапазоне температур).
Сенсорное слияние: простой фильтр без DMP
Если DMP кажется избыточно сложным, базовое сенсорное слияние (получение стабильного угла наклона без дрейфа гироскопа и без шума акселерометра) можно реализовать простым комплементарным фильтром:
/*
angleAcc - угол, вычисленный из акселерометра (подвержен шуму, но не дрейфует)
gyroRate - угловая скорость с гироскопа, град/с
dt - интервал времени между измерениями, секунды
*/
float angle = 0;
angle = 0.98 * (angle + gyroRate * dt) + 0.02 * angleAcc;
Коэффициенты 0,98/0,02 определяют, насколько фильтр «доверяет» гироскопу (быстрый, но дрейфующий) против акселерометра (медленный, но не дрейфующий) — это самый простой способ получить стабильный угол без написания полноценного фильтра Калмана.
MPU6050 и аналоги
| Модуль | Отличие от MPU6050 |
|---|---|
| MPU9250 / MPU9255 | Добавлен 3-осевой магнитометр (9 DOF) — позволяет определять абсолютное направление (компас), а не только относительный наклон |
| MPU6500 | Преемник MPU6050: более низкий уровень шума, поддержка SPI, питание от 1,71 В; как и у MPU6050, магнитометра нет |
| BMI160 / BMI270 (Bosch) | Альтернативные 6-осевые IMU с меньшим энергопотреблением, популярны во фитнес-трекерах |
Типичные проблемы
- Датчик не отвечает по I2C (ошибка подключения) — проверьте, что используется правильный I2C-адрес (0x68 по умолчанию, 0x69 при AD0=HIGH), а также качество пайки/контактов на выводах SDA/SCL;
- Показания гироскопа «уплывают» с течением времени — это нормальное физическое свойство МЭМС-гироскопов (дрейф); решается либо периодической коррекцией по акселерометру (см. комплементарный фильтр выше), либо использованием встроенного DMP;
- Сильный шум в показаниях акселерометра — механические вибрации платформы (моторы, винты дрона) передаются через корпус; помогает демпфирующее крепление модуля (резиновые проставки) и программное усреднение.
Материалы и Datasheet
- MPU-6000/MPU-6050 Product Specification, Rev. 3.4 (InvenSense / TDK)
- i2cdevlib — GitHub
- Adafruit_MPU6050 — GitHub
- mpu6050-raspberrypi — PyPI









