ELECTRONICS

MPU6050 и Arduino: схема подключения по I2C, библиотека и скетч расчёта угла

Датчики движения и наклонаСкетч проверен компиляцией

MPU6050 — самый распространённый датчик ориентации: в одном корпусе трёхосевой акселерометр и трёхосевой гироскоп. Акселерометр чувствует притяжение Земли и по нему понимает, где низ. Гироскоп меряет скорость вращения по каждой оси.

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

Схема подключения

Наведите курсор на провод — расскажу, зачем он нужен.

Распиновка

ПроводКуда и зачем
VCCПитание. 5 В для модуля GY-521 со стабилизатором, 3,3 В для голой микросхемы.
GNDЗемля.
SDAДанные I2C. На UNO — только A4.
SCLТакт I2C. На UNO — только A5.
AD0Выбор адреса. Не подключён — адрес 0x68, подан на питание — 0x69. Так на одну шину вешают два датчика.
INTПрерывание. Датчик сам сообщает, что новые данные готовы. Нужен для быстрых задач.
XDA, XCLВторая шина для подключения магнитометра. В обычных проектах не используются.

Характеристики

Оси
3 акселерометра + 3 гироскопа
Диапазон акселерометра
±2, ±4, ±8, ±16 g
Диапазон гироскопа
±250…±2000 °/с
Разрядность
16 бит на канал
Интерфейс
I2C, адрес 0x68 или 0x69
Частота выдачи
до 1 кГц

Почему угол «уплывает» и как это лечится

Гироскоп меряет не угол, а скорость вращения. Чтобы получить угол, показания складывают по времени — и вместе с ними накапливается ошибка. Лежащий неподвижно датчик за минуту «повернётся» на несколько градусов. Это дрейф нуля, и он есть у всех гироскопов.

Акселерометр дрейфа лишён: он всегда знает, где низ. Но он реагирует на тряску, и при движении показания скачут.

Комплементарный фильтр объединяет оба: девяносто восемь процентов берём от гироскопа, потому что он точен на коротких промежутках, и два процента от акселерометра, который медленно, но верно возвращает угол к правде. Одна строка кода — и дрейф исчезает.

Библиотека

Wire (встроенная)Датчик можно читать напрямую через встроенную Wire, как в скетче ниже — так понятнее, что происходит. Готовые библиотеки MPU6050 от Electronic Cats или MPU6050_light берут расчёты на себя и добавляют калибровку.

Готовый скетч

#include <Wire.h>

const int MPU = 0x68;      // адрес датчика на шине

float angleX = 0;
unsigned long lastTime = 0;

void setup() {
  Serial.begin(9600);
  Wire.begin();

  // будим датчик: по умолчанию он в спящем режиме
  Wire.beginTransmission(MPU);
  Wire.write(0x6B);
  Wire.write(0);
  Wire.endTransmission(true);

  lastTime = millis();
}

void loop() {
  // читаем 14 байт начиная с регистра 0x3B
  Wire.beginTransmission(MPU);
  Wire.write(0x3B);
  Wire.endTransmission(false);
  Wire.requestFrom(MPU, 14, true);

  int16_t accX = Wire.read() << 8 | Wire.read();
  int16_t accY = Wire.read() << 8 | Wire.read();
  int16_t accZ = Wire.read() << 8 | Wire.read();
  Wire.read(); Wire.read();            // температура, пропускаем
  int16_t gyroX = Wire.read() << 8 | Wire.read();

  // угол по акселерометру: где низ
  float accAngle = atan2(accY, accZ) * 180.0 / PI;

  // скорость вращения в градусах в секунду
  float gyroRate = gyroX / 131.0;

  float dt = (millis() - lastTime) / 1000.0;
  lastTime = millis();

  // комплементарный фильтр: гироскоп быстрый, акселерометр честный
  angleX = 0.98 * (angleX + gyroRate * dt) + 0.02 * accAngle;

  Serial.print("Угол: ");
  Serial.println(angleX);

  delay(20);
}

Скетч собирается arduino-cli под Arduino UNO

Первое, что делает скетч, — записывает ноль в регистр 0x6B. Без этого датчик остаётся в спящем режиме и отдаёт одни нули: причина номер один вопроса «почему MPU6050 не работает».

Частые ошибки

Датчик отдаёт одни нули

Не разбудили: при включении MPU6050 находится в спящем режиме, и в регистр 0x6B нужно записать ноль. Готовые библиотеки делают это сами, при работе напрямую — забывают почти всегда.

Угол медленно уплывает

Дрейф гироскопа. Без фильтра он неизбежен. Комплементарный фильтр из скетча решает вопрос за одну строку.

Значения дрожат при работе мотора рядом

Акселерометр честно чувствует вибрацию. Датчик крепят через мягкую прокладку и усредняют показания — иначе робот будет реагировать на собственную тряску.

Датчик не находится на шине

Проверьте адрес сканером I2C: он равен 0x68, а если вывод AD0 подан на питание — 0x69. И проверьте, что SDA и SCL не перепутаны: на UNO это строго A4 и A5.

Нужен курс относительно севера, а его нет

MPU6050 — шестиосевой, магнитометра в нём нет. Без компаса азимут определить невозможно: нужен MPU9250 или отдельный магнитометр.

Что понадобится