Компоненты · 8 мин чтения

MPU6050 и Arduino: акселерометр, гироскоп и угол наклона

MPU6050 с Arduino: подключение, I2C-адрес, сырые значения, калибровка, угол наклона через atan2 и комплементарный фильтр, библиотека Adafruit, код для ESP32 и Pico.

MPU6050 объединяет в одной крошечной микросхеме 3-осевой акселерометр и 3-осевой гироскоп и считается самым популярным датчиком движения в проектах на Arduino. Он измеряет, насколько наклонена плата, в какую сторону и с какой скоростью она вращается, трясут ли её и не упала ли она. На этом датчике строят балансирующих роботов, дроны, стабилизаторы камеры (подвесы, gimbal), шагомеры и игры с управлением движением. MPU6050 подключается к Arduino всего четырьмя проводами по I2C.

В этой статье шаг за шагом разберём, как работает MPU6050, что такое его оси и сырые значения, как подключить его по I2C, как читать данные с библиотекой и без неё, как провести калибровку, посчитать углы наклона через atan2 и применить комплементарный фильтр, который объединяет сильные стороны обоих датчиков. Затем соберём на ESP32 сигнализацию падения и напишем код на MicroPython для Raspberry Pi Pico.

Модуль акселерометра и гироскопа MPU6050 GY-521
MPU6050 на плате GY-521: пины VCC, GND, SCL, SDA, XDA, XCL, AD0 и INT; направления осей X и Y напечатаны на плате.

Что такое MPU6050 и как он работает?

MPU6050 производства InvenSense (сейчас TDK) — это IMU, инерциальный измерительный модуль. Внутри находятся крошечные механические структуры из кремния (MEMS). Акселерометр измеряет, насколько смещается при ускорении маленькая масса на пружинах; поскольку он чувствует силу тяжести даже в покое, датчик, лежащий ровно на столе, показывает по оси Z около 1 g (9,81 м/с²), и по этому можно определить его наклон относительно земли. Гироскоп измеряет угловую скорость, то есть на сколько градусов в секунду поворачивается датчик, по силе Кориолиса, действующей на колеблющиеся структуры. Измерения переводятся в числа 16-битными АЦП внутри микросхемы и читаются по I2C. Ещё в микросхеме есть датчик температуры и цифровой процессор движения (DMP), который может взять на себя расчёты движения.

ПараметрЗначение
Датчики3-осевой акселерометр + 3-осевой гироскоп + температура
Диапазон акселерометра±2, ±4, ±8, ±16 g
Диапазон гироскопа±250, ±500, ±1000, ±2000 °/с
Разрешение16 бит (от −32768 до 32767 на каждую ось)
ИнтерфейсI2C, до 400 kHz
I2C-адрес0x68 (AD0 на GND) или 0x69 (AD0 на 3,3 V)
Напряжение микросхемы2,375–3,46 V (плата GY-521 принимает 3,3–5 V)
ТокОколо 3,9 mA (5 µA во сне)
ДополнительноDMP, FIFO на 1024 байта, прерывание по движению, вспомогательная шина I2C для внешнего датчика

Оси, сырые значения и чувствительность

Стрелки на плате показывают оси X и Y; ось Z перпендикулярна плате и направлена вверх. Для каждой оси датчик выдаёт 16-битное число со знаком. Чтобы перевести это сырое число в физическую величину, его делят на чувствительность выбранного диапазона. Например, в диапазоне по умолчанию ±2 g сырое значение 16384 означает 1 g; у датчика, лежащего на столе, будет az ≈ 16384, а ax, ay ≈ 0. У гироскопа в диапазоне ±250 °/с сырое значение 131 соответствует повороту на 1 градус в секунду. Широкий диапазон позволяет измерять более резкие движения, но мелкие изменения показывает грубее, поэтому выбирай самый узкий диапазон, которого хватает для проекта.

НастройкаДиапазон акселерометраLSB/gДиапазон гироскопаLSB/(°/с)
0±2 g16384±250 °/с131
1±4 g8192±500 °/с65,5
2±8 g4096±1000 °/с32,8
3±16 g2048±2000 °/с16,4

Микросхема измеряет и температуру: °C = сырое значение / 340 + 36.53. Это температура самой микросхемы, а не комнаты, но поскольку нулевая точка гироскопа уплывает вместе с температурой, она пригодится для продвинутых поправок.

Подключение MPU6050: Arduino Uno, ESP32 и Pico

Пин MPU6050Arduino UnoESP32Raspberry Pi Pico
VCC5V3V33V3(OUT)
GNDGNDGNDGND
SCLA5GPIO 22GP5
SDAA4GPIO 21GP4
AD0Не подключён (адрес 0x68)Не подключён (адрес 0x68)Не подключён (адрес 0x68)
INTD2 (по желанию)Любой GPIO (по желанию)Любой пин GP (по желанию)
XDA, XCLНе подключаютсяНе подключаютсяНе подключаются

На плате GY-521 есть стабилизатор на 3,3 V, поэтому VCC можно подключить к пину 5V на Uno. Пин AD0 на плате подтянут к GND через резистор 4,7 kΩ, так что, если оставить его неподключённым, адрес будет 0x68; если нужны два MPU6050 на одной шине, подключи AD0 одного из них к 3,3 V, и его адрес сменится на 0x69. Пин INT сообщает, что готовы новые данные или обнаружено движение; для простых проектов его можно не подключать. После подключения полезно проверить скетчем-сканером I2C, что датчик виден на шине; как это сделать, рассказано в статье I2C LCD-дисплей.

Не путай SDA и SCL с XDA и XCL. XDA и XCL — это вспомогательная шина I2C, через которую MPU6050 подключает к себе внешний датчик-компас; если завести туда провода от Arduino, датчик никогда не найдётся. Кроме того, у некоторых голых плат MPU6050 нет стабилизатора, и их можно питать только от 3,3 V; если на твоей плате не видно маленькой микросхемы стабилизатора, не подавай на неё 5 V.

Быстрый старт с библиотекой: Adafruit MPU6050

  1. Открой в Arduino IDE «Менеджер библиотек» (Library Manager) и найди Adafruit MPU6050.
  2. Когда при установке появится вопрос о зависимостях, выбери «Установить все» (Install all), чтобы заодно установились Adafruit Unified Sensor и Adafruit BusIO.
  3. Подключи датчик по таблице, загрузи скетч ниже и открой монитор порта на скорости 115200 бод.
  4. Открой в меню «Инструменты» (Tools) «Плоттер по последовательному соединению» (Serial Plotter), чтобы смотреть на все шесть осей в виде живых графиков: при наклоне платы меняются кривые ускорения, при вращении — кривые гироскопа.
C++ (Arduino IDE)
1#include <Wire.h>
2#include <Adafruit_MPU6050.h>
3#include <Adafruit_Sensor.h>
4
5Adafruit_MPU6050 mpu;
6
7void setup() {
8  Serial.begin(115200);
9  if (!mpu.begin()) {                             // varsayılan adres 0x68 / default address 0x68
10    Serial.println("MPU6050 bulunamadi / not found");
11    while (true) delay(10);
12  }
13  mpu.setAccelerometerRange(MPU6050_RANGE_4_G);   // ±4 g
14  mpu.setGyroRange(MPU6050_RANGE_500_DEG);        // ±500 °/s
15  mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);     // titreşimi süz / filter out vibration
16}
17
18void loop() {
19  sensors_event_t a, g, t;
20  mpu.getEvent(&a, &g, &t);
21  Serial.print("ax:");  Serial.print(a.acceleration.x);   // m/s²
22  Serial.print(" ay:"); Serial.print(a.acceleration.y);
23  Serial.print(" az:"); Serial.print(a.acceleration.z);
24  Serial.print(" gx:"); Serial.print(g.gyro.x);           // rad/s
25  Serial.print(" gy:"); Serial.print(g.gyro.y);
26  Serial.print(" gz:"); Serial.print(g.gyro.z);
27  Serial.print(" T:");  Serial.println(t.temperature);    // °C
28  delay(100);
29}

Библиотека Adafruit сразу выдаёт результаты в физических единицах: ускорение в м/с², угловую скорость в рад/с и температуру в °C. Чтобы перевести значение гироскопа в градусы в секунду, достаточно умножить его на 57.3. Встроенный фильтр нижних частот, который выбирают через setFilterBandwidth, уменьшает шум от вибраций: 21 Hz — хорошая отправная точка для движений рукой, а если нужно ловить короткие удары, выбери 94 или 260 Hz. При запуске библиотека читает регистр идентификатора микросхемы (WHO_AM_I), и begin() возвращает false, если там не 0x68.

Чтение без библиотеки, калибровка и угол наклона

Библиотеки облегчают жизнь, но прямое чтение регистров — отличный способ понять, что происходит внутри датчика. MPU6050 запускается в спящем режиме; сначала его нужно разбудить, записав 0 в регистр 0x6B (PWR_MGMT_1). Затем читаются 14 байт, начиная с адреса 0x3B: 6 байт ускорения, 2 байта температуры и 6 байт данных гироскопа. Каждое значение занимает два байта, старший байт идёт первым. Вот основные регистры, которые используются в коде и которые стоит знать:

РегистрАдресНазначение
SMPLRT_DIV0x19Делитель частоты выборки
CONFIG0x1AВстроенный фильтр нижних частот (DLPF)
GYRO_CONFIG0x1BДиапазон гироскопа (±250 … ±2000 °/с)
ACCEL_CONFIG0x1CДиапазон акселерометра (±2 … ±16 g)
ACCEL_XOUT_H0x3BАдрес, с которого начинаются измерения (14 байт)
PWR_MGMT_10x6BСон и источник тактирования; запись 0 будит датчик
WHO_AM_I0x75Идентификатор; у оригинального MPU6050 возвращает 0x68

У неподвижного датчика единственная сила, которую видит акселерометр, — это сила тяжести. По тому, как она распределяется между осями, находят два угла: угол крена (roll) вокруг оси X — roll = atan2(ay, az), а угол тангажа (pitch) вокруг оси Y — pitch = atan2(−ax, √(ay² + az²)). В отличие от обычного арктангенса, atan2 даёт правильный знак во всех четырёх четвертях и не делит на ноль, когда az приближается к нулю. Например, при ay = 8192 и az = 14189 получится roll = atan2(8192, 14189) ≈ 30°. А вот поворот вокруг оси Z (рыскание, yaw) акселерометр не видит, потому что он не меняет распределение силы тяжести между осями.

У обоих датчиков есть слабое место. Акселерометр точен на длинной дистанции, но сильно шумит при движении и вибрации, потому что поверх силы тяжести измеряет и ускорение самого движения. Гироскоп плавный на коротком отрезке, но чтобы получить угол, угловую скорость суммируют во времени (angle += rate × dt), и даже небольшое смещение накапливается и потихоньку уводит угол. Комплементарный фильтр объединяет их: angle = 0.98 × (angle + gyro × dt) + 0.02 × угол акселерометра. На коротком отрезке он доверяет гироскопу, на длинном — акселерометру. При 100 Hz (dt = 0.01 с) эти коэффициенты дают постоянную времени около половины секунды: τ = 0.98 × 0.01 / 0.02 = 0.49 с.

Калибровка важна не меньше фильтра. Даже совершенно неподвижный гироскоп может показывать постоянное смещение в несколько °/с; если его не убрать, рассчитанный угол за считаные секунды уплывёт на десятки градусов. Скетч ниже при запуске, пока датчик неподвижен, усредняет 500 показаний и потом вычитает это значение из каждого следующего. Положи плату на ровную поверхность и не трогай её во время калибровки, а затем смотри на кривые roll, pitch и yaw в плоттере.

C++ (Arduino IDE)
1#include <Wire.h>
2
3const int MPU_ADDR = 0x68;           // AD0 GND'de ya da boşta / AD0 to GND or floating
4const float GYRO_LSB = 131.0;        // ±250 °/s aralığında 1 °/s / 1 °/s at the ±250 °/s range
5const float ALPHA = 0.98;            // tamamlayıcı filtre katsayısı / complementary filter weight
6
7int16_t ax, ay, az, tempRaw, gx, gy, gz;
8float gxOff = 0, gyOff = 0, gzOff = 0;   // jiroskop sapmaları / gyro offsets
9float roll = 0, pitch = 0, yaw = 0;
10unsigned long lastMicros;
11
12void writeReg(uint8_t reg, uint8_t val) {
13  Wire.beginTransmission(MPU_ADDR);
14  Wire.write(reg);
15  Wire.write(val);
16  Wire.endTransmission();
17}
18
19int16_t read16() {
20  uint8_t hi = Wire.read();          // önce yüksek bayt / high byte first
21  uint8_t lo = Wire.read();
22  return (int16_t)(((uint16_t)hi << 8) | lo);
23}
24
25void readMPU() {
26  Wire.beginTransmission(MPU_ADDR);
27  Wire.write(0x3B);                  // ACCEL_XOUT_H
28  Wire.endTransmission(false);       // hattı bırakma, tekrar başlat / repeated start
29  Wire.requestFrom(MPU_ADDR, 14);    // ivme 6 + sıcaklık 2 + jiroskop 6 bayt / accel 6 + temp 2 + gyro 6 bytes
30  ax = read16(); ay = read16(); az = read16();
31  tempRaw = read16();
32  gx = read16(); gy = read16(); gz = read16();
33}
34
35void calibrateGyro() {
36  const int N = 500;
37  long sx = 0, sy = 0, sz = 0;
38  for (int i = 0; i < N; i++) {
39    readMPU();
40    sx += gx; sy += gy; sz += gz;
41    delay(3);
42  }
43  gxOff = sx / (float)N;
44  gyOff = sy / (float)N;
45  gzOff = sz / (float)N;
46}
47
48void setup() {
49  Serial.begin(115200);
50  Wire.begin();
51  Wire.setClock(400000);             // 400 kHz hızlı mod / 400 kHz fast mode
52  writeReg(0x6B, 0x00);              // PWR_MGMT_1: uykudan uyandır / wake up
53  writeReg(0x1A, 0x03);              // CONFIG: alçak geçiren filtre ~44 Hz / low-pass ~44 Hz
54  writeReg(0x1B, 0x00);              // GYRO_CONFIG: ±250 °/s
55  writeReg(0x1C, 0x00);              // ACCEL_CONFIG: ±2 g
56  delay(100);
57  Serial.println("Kalibrasyon: sensoru oynatma / calibrating: keep still");
58  calibrateGyro();
59  readMPU();
60  roll  = atan2(ay, az) * RAD_TO_DEG;                                    // başlangıç açıları / initial angles
61  pitch = atan2(-ax, sqrt((float)ay * ay + (float)az * az)) * RAD_TO_DEG;
62  lastMicros = micros();
63}
64
65void loop() {
66  readMPU();
67  unsigned long now = micros();
68  float dt = (now - lastMicros) / 1000000.0;   // saniye / seconds
69  lastMicros = now;
70
71  float accRoll  = atan2(ay, az) * RAD_TO_DEG;                           // ivmeölçerden açı / angle from accelerometer
72  float accPitch = atan2(-ax, sqrt((float)ay * ay + (float)az * az)) * RAD_TO_DEG;
73  float gxRate = (gx - gxOff) / GYRO_LSB;      // °/s
74  float gyRate = (gy - gyOff) / GYRO_LSB;
75  float gzRate = (gz - gzOff) / GYRO_LSB;
76
77  roll  = ALPHA * (roll  + gxRate * dt) + (1 - ALPHA) * accRoll;        // tamamlayıcı filtre / complementary filter
78  pitch = ALPHA * (pitch + gyRate * dt) + (1 - ALPHA) * accPitch;
79  yaw  += gzRate * dt;                         // yalnız jiroskop: zamanla kayar / gyro only: drifts over time
80
81  Serial.print("roll:");   Serial.print(roll, 1);
82  Serial.print(" pitch:"); Serial.print(pitch, 1);
83  Serial.print(" yaw:");   Serial.println(yaw, 1);
84  delay(10);                                   // yaklaşık 100 Hz / about 100 Hz
85}
Строка кодаЧто делает
writeReg(0x6B, 0x00)Выводит датчик из спящего режима
writeReg(0x1A, 0x03)Включает встроенный фильтр примерно на 44 Hz
Wire.requestFrom(MPU_ADDR, 14)Читает ускорение, температуру и данные гироскопа за один раз
calibrateGyro()Находит смещение гироскопа, усредняя 500 показаний
atan2(ay, az) * RAD_TO_DEGСчитает по акселерометру угол крена в градусах
ALPHA * (...) + (1 - ALPHA) * ...Комплементарный фильтр: объединяет гироскоп и акселерометр
yaw += gzRate * dtСчитает рыскание только по гироскопу, чтобы было видно, как оно уплывает со временем
Слегка потряси плату, глядя на плоттер: сырой угол акселерометра скачет, а отфильтрованный остаётся спокойным. Для более быстрой реакции уменьши ALPHA до 0.95, для меньшего дрожания увеличь до 0.99. Ещё более стабильный результат даёт пример DMP из библиотеки MPU6050 от Electronic Cats: углы там получаются из кватернионов, которые считает собственный процессор датчика.

MPU6050 и ESP32: сигнализация падения

На ESP32 подключение такое же, как на Uno, только пины I2C — GPIO 21 (SDA) и GPIO 22 (SCL), а модуль питается от 3V3. Все скетчи выше работают на ESP32 без изменений; при желании пины можно задать явно через Wire.begin(21, 22). Пример ниже — детектор падения. В свободном падении акселерометр показывает почти 0 g, потому что корпус датчика и масса внутри него падают вместе; следующий за этим удар даёт пик в несколько g. Если скетч видит свободное падение длительностью не меньше 100 мс, а в течение полсекунды после него — удар сильнее 2,5 g, он на одну секунду включает активный зуммер на GPIO 25. Свободное падение длительностью 100 мс соответствует высоте около 5 см (h = ½ × g × t²).

C++ (Arduino IDE)
1#include <Wire.h>
2#include <Adafruit_MPU6050.h>
3#include <Adafruit_Sensor.h>
4
5Adafruit_MPU6050 mpu;
6const int BUZZER_PIN = 25;           // aktif buzzer / active buzzer
7const float FREE_FALL_G = 0.4;       // serbest düşüş eşiği / free-fall threshold
8const float IMPACT_G = 2.5;          // darbe eşiği / impact threshold
9unsigned long fallStart = 0, fallEnd = 0;
10
11void setup() {
12  Serial.begin(115200);
13  pinMode(BUZZER_PIN, OUTPUT);
14  Wire.begin(21, 22);                // SDA, SCL
15  if (!mpu.begin(0x68, &Wire)) {
16    Serial.println("MPU6050 bulunamadi / not found");
17    while (true) delay(10);
18  }
19  mpu.setAccelerometerRange(MPU6050_RANGE_8_G);   // darbeler için geniş aralık / wide range for impacts
20  mpu.setFilterBandwidth(MPU6050_BAND_94_HZ);     // kısa darbeleri kaçırma / keep short peaks
21}
22
23void loop() {
24  sensors_event_t a, g, t;
25  mpu.getEvent(&a, &g, &t);
26  float x = a.acceleration.x, y = a.acceleration.y, z = a.acceleration.z;
27  float total = sqrt(x * x + y * y + z * z) / SENSORS_GRAVITY_STANDARD;   // toplam ivme, g / total acceleration in g
28  unsigned long now = millis();
29
30  if (total < FREE_FALL_G) {
31    if (fallStart == 0) fallStart = now;             // düşüş başladı / fall started
32  } else if (fallStart != 0) {
33    if (now - fallStart > 100) fallEnd = now;        // en az 100 ms süren düşüş / fall of at least 100 ms
34    fallStart = 0;
35  }
36
37  if (fallEnd != 0 && now - fallEnd < 500 && total > IMPACT_G) {   // düşüşten sonra 0,5 s içinde darbe / impact within 0.5 s
38    Serial.println("DUSME ALGILANDI / FALL DETECTED");
39    digitalWrite(BUZZER_PIN, HIGH);
40    delay(1000);
41    digitalWrite(BUZZER_PIN, LOW);
42    fallEnd = 0;
43  }
44  if (fallEnd != 0 && now - fallEnd >= 500) fallEnd = 0;   // darbe gelmedi, sıfırla / no impact, reset
45  delay(5);
46}

Дальше можно подключить Wi-Fi на ESP32 и, например, отправлять уведомление в Telegram на телефон, если упадёт пожилой родственник, или показывать углы на веб-странице в реальном времени. Пороги подбирай по своим тестам: коробка, упавшая со стола, и датчик на запястье дают разные пики. Как выбрать и подключить зуммер, читай в статье Что такое зуммер?.

MPU6050 и Raspberry Pi Pico (MicroPython)

На Pico дополнительная библиотека не нужна: встроенный класс I2C в MicroPython умеет читать регистры напрямую. Подключи датчик к шине I2C0: SDA на GP4, SCL на GP5. С помощью struct.unpack 14 байт превращаются в семь 16-битных чисел со знаком; «>» означает big-endian (старший байт первым), а «h» — 16-битное число со знаком. Сначала код печатает найденные I2C-адреса; если в списке нет 0x68, проверь подключение. Для простоты калибровку мы не добавляли; при необходимости метод усреднения из скетча для Arduino применяется точно так же.

MicroPython
1from machine import Pin, I2C
2import math, struct, time
3
4MPU = 0x68
5i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=400000)
6print("Bulunan adresler / found addresses:", [hex(a) for a in i2c.scan()])
7
8i2c.writeto_mem(MPU, 0x6B, b"\x00")     # uykudan uyandır / wake up
9i2c.writeto_mem(MPU, 0x1A, b"\x03")     # alçak geçiren filtre ~44 Hz / low-pass ~44 Hz
10i2c.writeto_mem(MPU, 0x1B, b"\x00")     # jiroskop ±250 °/s / gyro ±250 °/s
11i2c.writeto_mem(MPU, 0x1C, b"\x00")     # ivmeölçer ±2 g / accelerometer ±2 g
12roll = pitch = 0.0
13last = time.ticks_us()
14
15while True:
16    data = i2c.readfrom_mem(MPU, 0x3B, 14)
17    ax, ay, az, t, gx, gy, gz = struct.unpack(">hhhhhhh", data)   # büyük endian, işaretli / big-endian, signed
18    now = time.ticks_us()
19    dt = time.ticks_diff(now, last) / 1000000
20    last = now
21    acc_roll = math.degrees(math.atan2(ay, az))
22    acc_pitch = math.degrees(math.atan2(-ax, math.sqrt(ay * ay + az * az)))
23    roll = 0.98 * (roll + gx / 131 * dt) + 0.02 * acc_roll        # tamamlayıcı filtre / complementary filter
24    pitch = 0.98 * (pitch + gy / 131 * dt) + 0.02 * acc_pitch
25    temp = t / 340 + 36.53                                        # °C
26    print("roll {:.1f}  pitch {:.1f}  T {:.1f}".format(roll, pitch, temp))
27    time.sleep_ms(10)

Идеи проектов с MPU6050

  • Электронный уровень: показывай углы крена и тангажа на OLED-дисплее с движущимся пузырьком.
  • Сервопривод с управлением движением: наклоняешь датчик в руке, и сервопривод поворачивается на тот же угол; идеально для руки робота или поворотной головки камеры.
  • Игра с управлением наклоном: играй в Pong или лабиринт, наклоняя плату вместо джойстика.
  • Балансирующий робот: обрабатывай угол тангажа ПИД-регулятором и удерживай робота в вертикальном положении с помощью DC-моторов на драйвере L298N.
  • Шагомер: считай шаги по регулярным пикам полного ускорения.
  • Регистратор вибраций: измеряй тряску станка или стиральной машины и подавай сигнал, когда превышен порог.

Частые ошибки и как их исправить

СимптомВероятная причинаРешение
begin() возвращает false («MPU6050 not found»)Ошибка в подключении, неверный адрес или микросхема-клонНайди адрес сканером I2C; если WHO_AM_I не 0x68 (например, 0x70), используй код без библиотеки
Все значения равны 0Датчик в спящем режимеЗапиши 0 в регистр 0x6B
Значения равны -1 или замираютПлохой контакт, слишком длинная шина I2CУкороти провода, припаяй пины
Угол уплывает в покоеНе убрано смещение гироскопаОткалибруй датчик при запуске, пока он неподвижен
Угол скачет при движенииИспользуется только акселерометрДобавь комплементарный фильтр
Рыскание постоянно уплываетУ MPU6050 нет компасаДобавь магнитометр, например QMC5883L, или возьми 9-осевой датчик
Крен считается неверно, когда тангаж близок к ±90°Сингулярность углов ЭйлераИзбегай этой области или используй кватернионы из DMP
Закрепляя датчик в проекте, надёжно зафиксируй плату винтом или двусторонним скотчем: плохо закреплённая плата измеряет собственную вибрацию. Калибровка при той температуре, при которой датчик будет работать, тоже уменьшает дрейф.

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

Частые вопросы

Для чего используют MPU6050?

MPU6050 измеряет наклон предмета, скорость его вращения и ускорение. Его используют в балансирующих роботах, дронах и подвесах для камер, шагомерах, для обнаружения падений и ударов, а также в играх с управлением движением.

Какой адрес у MPU6050: 0x68 или 0x69?

Адрес 0x68, если пин AD0 не подключён или соединён с GND, и 0x69, если он подключён к 3,3 V. На плате GY-521 AD0 подтянут к GND через резистор, поэтому адрес по умолчанию 0x68. Чтобы знать наверняка, запусти скетч-сканер I2C.

Работает ли MPU6050 от 5 V?

Сама микросхема MPU6050 работает максимум от 3,46 V, но благодаря стабилизатору на плате GY-521 на пин VCC можно подавать 5 V. Линии I2C остаются на уровне 3,3 V, и Arduino Uno читает их без проблем. На голые платы без стабилизатора 5 V подавать нельзя.

Как посчитать углы с помощью MPU6050?

Когда датчик неподвижен, углы получают из акселерометра: roll = atan2(ay, az) и pitch = atan2(−ax, √(ay² + az²)). Чтобы результат был точным и при движении, угловую скорость гироскопа интегрируют во времени и объединяют с углом акселерометра комплементарным фильтром или фильтром Калмана.

Может ли MPU6050 измерять рыскание (yaw)?

На коротких отрезках — да: рыскание можно посчитать, интегрируя угловую скорость по оси Z. Но поскольку у MPU6050 нет магнитометра, рыскание со временем уплывает, а абсолютное направление (на север) датчик знать не может. Для стабильного курса нужен датчик-компас, например QMC5883L, или 9-осевой IMU.

Чем MPU6050 отличается от MPU9250?

MPU6050 — 6-осевой датчик с акселерометром и гироскопом. В MPU9250 добавлен 3-осевой магнитометр, поэтому он 9-осевой и может измерять рыскание без дрейфа; кроме того, он поддерживает SPI. MPU9250 снят с производства, поэтому для новых проектов предпочитают его преемников, например ICM-20948.

Все проекты
Работа с сервоприводом
#35Новичок
Premium

Работа с сервоприводом

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

4.7(48)
67
Управление сервоприводом джойстиком
#60Средний
Premium

Управление сервоприводом джойстиком

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

4.7(42)
58
Сервопривод на ESP32 (управление потенциометром)
#118Средний
Premium

Сервопривод на ESP32 (управление потенциометром)

В этом проекте сервопривод SG90 управляется потенциометром. Угол сервопривода задаётся сопоставлением аналогового значения потенциометра с диапазоном 0–180 градусов. Библиотека ESP32Servo формирует сигналы сервопривода на подходящих выходных пинах GPIO у ESP32; этот проект использует GPIO 18. Это базовый способ управления для роборук, подвесов камер и механизмов автоматических дверей.

4.3(29)
42
Игра в пинг-понг — SSD1306
#86Средний
Premium

Игра в пинг-понг — SSD1306

Мяч, две ракетки и ты: на маленьком OLED-экране ты играешь в настольный теннис — одну из самых первых видеоигр. Две кнопки двигают твою ракетку справа вверх и вниз, а левой ракеткой управляет компьюте

4.5(47)
65
LCD-экран с I2C
#32Новичок
Premium

LCD-экран с I2C

Дай своему Arduino собственный экран и заставь его написать первое сообщение. Двухстрочный LCD-экран подключается всего несколькими проводами; в верхней строке появляется приветствие, затем второе соо

4.8(53)
70
I2C LCD-дисплей (16x2) на ESP32
#119Средний
Premium

I2C LCD-дисплей (16x2) на ESP32

В этом проекте символьный LCD-экран 16x2 подключается к ESP32 по протоколу I2C и выводит текст. Благодаря I2C экраном можно управлять всего двумя пинами данных (SDA и SCL), не тратя 6+ пинов, как при классическом параллельном подключении. Код печатает постоянное сообщение в первой строке и счётчик, растущий каждую секунду, во второй. Кроме того, при запуске работает сканер I2C, который выводит адрес дисплея в монитор порта.

4.9(23)
40
Робот, объезжающий препятствия
#81Продвинутый
Premium

Робот, объезжающий препятствия

Как насчёт того, чтобы собрать умную машину, которая сама находит дорогу? Робот, объезжающий препятствия, постоянно осматривает всё вокруг благодаря ультразвуковому датчику спереди. Встретив препятств

5.0(38)
49