Ардуино: акселерометр MPU6050

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

На этот раз мы перейдем от теории к практике: подключим датчик к Ардуино, и напишем пару программ для работы с ним. Подключать будем модуль MPU6050 от RobotClass.

Акселерометр и гироскоп MPU6050 от RobotClass - ROC

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

Характеристики модуля MPU6050 ROC:

  • напряжение питания: от 3,5 до 6 В;
  • потребляемый ток: 500 мкА;
  • ток в режиме пониженного потребления: 10 мкА при 1,25 Гц, 20 мкА при 5 Гц, 60 мкА при 20 Гц, 110 мкА при 40 Гц;
  • диапазон: ± 2, 4, 8, 16g;
  • разрядность АЦП: 16;
  • интерфейс: I2C (до 400 кГц).

На плате имеется 8 контактов:

  • VCC — положительный контакт питания;
  • GND — земля;
  • SDA — линия данных I2C;
  • SCL — линия синхроимпульсов I2C;
  • INT — настраиваемое прерывание;
  • AD0 — I2C адрес; по-умолчанию AD0 подтянут к земле, поэтому адрес устройства — 0x68; если соединить AD0 к контактом питания, то адрес изменится на 0x69;
  • XCL, XDA — дополнительный I2C интерфейс для подключения внешнего магнитометра.

Подключение MPU6050 к Ардуино

Соединим контакты датчика с Ардуино Уно согласно стандартной схеме для интерфейса I2C:

MPU6050 ROCGNDVCCSDASCL
Ардуино УноGND+5VA4A5

Принципиальная схема

Схема подключения MPU6050 к Ардуино

Внешний вид макета

Схема подключения MPU6050 к Ардуино

Программа для получения сырых данных с акселерометра MPU6050

Составим программу, которая будет каждые 20 миллисекунд получать данные из MPU6050 и выводить их в последовательный порт.

#include "I2Cdev.h"
#include "MPU6050.h"

#define T_OUT 20

MPU6050 accel;

unsigned long int t_next;

void setup() {
    Serial.begin(9600);
    accel.initialize();
    Serial.println(accel.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
}

void loop() {
    long int t = millis();
    if( t_next < t ){
        int16_t ax_raw, ay_raw, az_raw, gx_raw, gy_raw, gz_raw;

        t_next = t + T_OUT;
        accel.getMotion6(&ax_raw, &ay_raw, &az_raw, &gx_raw, &gy_raw, &gz_raw);
 
        Serial.println(ay_raw); // вывод в порт проекции ускорения на ось Y
    }
}

Для работы программы потребуются библиотеки: MPU6050 и I2Cdev, ссылки на которые можно найти в конце урока.

Загружаем программу на Ардуино и открываем окно графика. Поворачиваем датчик вокруг оси X на 90 градусов в одну сторону, потом на 90 в другую. Получится примерно такая картина.

Сырые данные с акселерометра MPU6050

На графике хорошо видно, что при наклоне оси Y вертикально, акселерометр выдает значения близкие к четырём тысячам. Откуда берется это число?

Точность измерения ускорения в MPU6050

Дело в том, что датчик MPU6050 позволяет настраивать точность измерений. Можно выбрать один из четырех классов точности: ±2G, 4G, 8G и 16G, где 1G — это одна земная гравитация.  Используемая нами библиотека по-умолчанию настраивает датчик на диапазон ±8G (прим. по ссылке внизу статьи библиотека по-умолчанию устанавливает ±2G).

С другой стороны, MPU6050 имеет 16 разрядный АЦП. 2 в степени 16 даст нам число 65 536. Поскольку датчик может измерять и отрицательное и положительное ускорение, то он будет выдавать нам числа от -32768 до +32768.

Сложив эти два факта вместе получаем, что при таких настройках 1G будет равен числу 4096 (ну а -1G равен числу -4096). Это вполне совпадает с наблюдаемыми на графике значениями!

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

Программа для вычисления угла наклона акселерометра MPU6050

Добавим в предыдущую программу вычисление угла поворота датчика вокруг оси X:

#include "I2Cdev.h"
#include "MPU6050.h"

#define TO_DEG 57.29577951308232087679815481410517033f
#define T_OUT 20

MPU6050 accel;

float angle_ax;
long int t_next;

float clamp(float v, float minv, float maxv){
    if( v>maxv )
        return maxv;
    else if( v<minv )
        return minv;
    return v;
}

void setup() {
    Serial.begin(9600);
    accel.initialize(); // первичная настройка датчика
    Serial.println(accel.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
}

void loop() {
    long int t = millis();
    if( t_next < t ){
        int16_t ax_raw, ay_raw, az_raw, gx_raw, gy_raw, gz_raw;
        float ay,gx;

        t_next = t + T_OUT;
        accel.getMotion6(&ax_raw, &ay_raw, &az_raw, &gx_raw, &gy_raw, &gz_raw);
 
        // сырые данные акселерометра нужно преобразовать в единицы гравитации
        // при базовых настройках 1G = 4096
        ay = ay_raw / 4096.0;
        // на случай, если на акселерометр действуют посторонние силы, которые могут
        // увеличить ускорение датчика свыше 1G, установим границы от -1G до +1G  
        ay = clamp(ay, -1.0, 1.0);

        // функция acos возвращает угол в радианах, так что преобразуем
        // его в градусы при помощи коэффициента TO_DEG
        if( ay >= 0){
            angle_ax = 90 - TO_DEG*acos(ay);
        } else {
            angle_ax = TO_DEG*acos(-ay) - 90;
        }
 
        Serial.println(angle_ax); // вывод в порт угла поворота вокруг оси X
    }
}

Загружаем программу в Ардуино и снова пробуем вращать датчик. Теперь на графике отображается угол наклона в градусах!

График угла наклона, полученного с помощью акселерометра MPU6050

Ну вот, мы получили уже что-то пригодное для дальнейшего использования. Видно, что датчик поворачивался сначала на 30 с лишним градусов в одну сторону, потом примерно на 60 в другую. Работает!

Заключение

На этом уроке мы получили с датчика MPU6050 сначала сырые данные, а потом и угол его наклона в градусах. Это большое достижение. Но впереди еще немного математики и еще более крутые результаты! Будем делать комплементарный фильтр, который позволит работать с датчиком даже в условиях вибрации и тряски.

Несколько идей/заданий:

  • Детектор стука, он же детектор попадания пули в мишень. Программа должна обнаружить всплеск показаний датчика по одной из осей и сигнализировать об этом, например, с помощью зуммера.
  • Кодовый замок, открывающийся по определенной последовательности стука. То же, что и в предыдущем задании, только нужно считать паузы между стуками и сверять их с эталонной последовательностью.
  • Детектор свободного падения. Если значения акселерометра по всем трем осям близки к нулю, значит тело находится в состоянии свободного падения.
  • Пульт управления роботом. Можно прикрепить датчик на перчатку и отслеживать наклоны ладони по двум осям. Передавать значения датчика через Bluetooth роботу.

Принципиальная схема датчика

Полезные ссылки


Изменено:

Ардуино: акселерометр MPU6050: 27 комментариев

  1. Подробная статья, чувствуется что автор хорошо владеет материалом.
    А не доводилось ли автору использовать MPU-6050 для вычисления траектории? Если такой опыт имеется, то прошу поделиться. Спасибо!

  2. Всё хорошо, но автору нужно быть корректнее. Если что-то объясняешь, то не должно быть ошибок. Иначе начинающий, попробовав приведённые примеры и не получив положительного результата, может вообще забить на тему.
    Загрузив первый пример, тут же получаешь ошибку компиляции. А проблема в ошибке: Объявляется MPU6050 accel;, а дальше применяется accelgyro (должно быть одинаково). Мелочь, конечно, но начинающего может ввести в ступор. Далее объясняется, откуда взялось «4000 тысячам», а фактически значения около 16000. Фразу «открываем окно графика» тоже не сразу понять. Оказывается, в версии 1.8.5 IDE Arduino появилось «Плоттер по последовательному соединению». Дальше пока не разбирался, но хотелось бы начать въежать в тему, а не ребусы разгадывать.

    • Владимир, спасибо за замечания! Код исправили. Насчёт 4000 вместо 16000, то это особенность той версии библиотеки, с которой запускалась программа. В текущей версии действительно стоит другой диапазон — ±2G, поэтому и числа у вас ±16000.
      А плоттер хорошая штука, рекомендую всегда иметь под рукой свежую версию IDE, благо она свободно распространяемая!

  3. Подскажите, где в программе обозначено, что подключаться надо к А4 и А5?

    • Эти пины явно не указываются, так как библиотека I2cdev использует по-умолчанию аппаратный i2c на выбранном типе контроллера. A4 и A5 — это как раз аппаратный i2c на atmega328.

  4. Здравствуйте. Касаемо I2Cdev и назначение выводов для esp8266(esp13), почему то не работает. По умолчанию аппаратно GPIO14;GPIO2. Но осциллографом только на 2 номере имеются запросы, 14 молчит.

  5. Добрый день.
    Зачем использовать getMotion6, если для данного примера достаточно getAccelerationY?

  6. Хотелось бы сделать систему фиксации тряски автомобиля во время движения.
    Данный модуль подойдёт для этого?

  7. Здравствуйте. Сможет данный датчик определить наклон в 0.0375 градусов. мне нужно определить возвышение одного конца уровня (длинной 1520мм) над другим в диапазоне от 0 мм до 160 мм. 1 мм возвышения равен 0.0375 градусов. и вывода на дисплей значение в миллиметрах. Спасибо.

  8. Добрый день!
    Очень нравится результаты, которые представлены у Вас и они подходят для моего проекта, но к сожалению выдаётся ошибка » MPU6050 connection failed » в «монитор порта» и дальше просто выводятся нули (как и на графике…). Пробовал разные варианты подключения vcc датчика на 5v и 3v3, также подключал INT к D2 на ардуино и тоже не дало результатов.
    Из примеров брал MPU6050_DMP6 и всё работает. Проверял подключение с помощью i2c_scanner и тоже всё подключено.
    Использую датчик GY-521 mpu6050 и arduino Nano.
    Подскажите в чём может быть проблема?

  9. Не знаю насчёт конкретно вашего 6050, но по даташиту их напряжение питания 3.3V и я крайне не советую подключать его к +5. А то из него может выйти волшебный дым. А без волшебного дыма он не работает.

    • Не пугайте зря читателей. На плате есть понижающий преобразователь напряжения для правильного питания чипа. Сигнальные линии толерантны к 5В логике. Всё будет прекрасно работать с обычной Ардуиной.

  10. Не подскажете, градусы выводятся десятичным числом или целым? Есть ли пример сообщеения этого датчика с сервомотором?

    • Во второй программе переменная angle_ax имеет тип float, так что значения будут вещественными.
      Насчет сервомотора, достаточно сдвинуть показания датчика из диапазона -90..90 в диапазон 0..180 и передать в функцию, которая крутит сервомотор (зависит от используемой библиотеки).
      Типа так: my_servo.write(angle_ax+90)

  11. 1. Поправка — не «4000 тысячам» (это 4 миллиона!), а «4-м тысячам».
    2. Как получить «окно графика»? Я что-то не нашел (версия IDE 1.8.10).
    3. Как получить данные по другим осям?

    • Спасибо за замечание, исправили!
      График живет тут: Инструменты/Плоттер по последовательному соединению
      Что касается других осей. Сырые данные хранятся в переменных: ax_raw, ay_raw, az_raw. Для ax_raw сделан ряд преобразований, которые можно повторить и для других осей, по аналогии.

  12. Есть очень важная и принципиальная ошибка, которая запутает любого, начинающего погружаться в тему инерционных датчиков, человека. «Программа для вычисления угла наклона акселерометра MPU6050» — заголовок неверен. Объяснюсь. В данном модуле есть два датчика, акселерометр и гироскоп. Акселерометр измеряет усокорение по трем осям. Гироскоп измеряет угловую скорость по трем осям, то есть скорость поворота вокруг трех осей. На основе данных акселерометра невозможно получить угол поворота. На основе данных об ускорениях возможно построить только траекторию перемещения(стоит учитывать ошибку интегрирования). Но невозможно узнать положение объекта в пространстве. Невозможно узнать угол его наклона. Угол наклона можно получить только проинтегрировав данные гироскопа. Ну а еще для более точного измерения угла по нескольким осям можно использовать Инклинометр — он измеряет и выдает именно угол отклонения.

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

      • Еще вот тут ошибка. «С другой стороны, MPU6050 имеет 16 разрядный АЦП. 2 в степени 16 даст нам число 65 536. Поскольку датчик может измерять и отрицательное и положительное ускорение, то он будет выдавать нам числа от -32768 до +32768.» — диапазон неверен. Диапазон до +32767. Да, всего лишь единичка. Но если кто-то захочет конвертировать значение из этого диапазона в другой, то получит бред на графике, при движениях близких к зашкаливанию показаний. (я столкнулся с этой проблемой, долго не мог понять где допустил ошибку.)

        • Насчет диапазона, верно, единичка лишняя!

          Что касается остального, то тут вы заблуждаетесь. На показания акселерометра действительно влияет любое ускорение, что «портит» вычисление угла наклона. Об этом, в частности, говорится в уроках про альфа-бета фильтр и фильтр Мажвика, которые как раз и позволяют реализовать инклинометр. Насчет «невозможности» извлечения положения тела в пространстве — это вы уже перегибаете:) В конце урока мы как раз и получаем угол наклона, который можно использовать в разного рода DIY задачах, держа в уме особенности акселерометра (про вибрацию и пр.). Зачем игнорировать очевидную пользу.
          Дабы не быть голословным (хотя и так имеется очевидный результат), вот для всех интересующихся app note от NXP: https://cache.freescale.com/files/sensors/doc/app_note/AN3461.pdf
          Читать вторую главу.

  13. В статье написано: «Детектор свободного падения. Если значения акселерометра по всем трем осям близки к нулю, значит тело находится в состоянии свободного падения.»
    На тело, находящееся в состоянии свободного падения, действует сила тяжести mg. Значит акселерометр будет измерять три проекции ускорения свободного падения, т.е. g=9,81.
    А если тело летит, т.е. совершает относительное движение, то на него будет действовать ещё и сила Кориолиса. Значит к G добавится ещё и кориолисово ускорение. Оно тоже даст проекции на все три оси акселерометра.

    • Нет, неверно. Да, на все тела, безусловно, действует сила гравитации. Но гравитация не вызывает собственное ускорение тела, которое и фиксирует акселерометр. Поэтому, он будет оказывать 0.

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

      На всякий случай рекомендую почитать ещё: про собственное ускорение

  14. Здравствуйте, дорогие друзья.
    У меня проблема, — ни как не могу понять на что влияет настройка 2G, 4G, 8G, 16G…
    Использую эту библиотеку: https://github.com/bolderflight/MPU9250
    функция опроса датчика выводит результат в м/с*с
    менял настройку с 2g to 16G, выходные значения вроде не менялись…

    Я понял так, что если поставить 2G и приложить ускорение больше 2G, то прибор его не сможет зафиксировать.
    В ручную на проводочке это не удается проверить.

    Пожалуйста поправьте меня… =(

    • У датчика есть встроенный АПЦ конечной разрядности, в данном случае — 16. Если указать диапазон 2G, то датчик достигнет максимальной точности в рамках этих 2G (16384 градаций на каждое G), но не сможет измерить значения за пределами 2G.

      При 2G в свободном состоянии ось Z должна выдавать 16384 (примерно). Это соответствует земной гравитации 1 G.

      Странно, что не менялись выходные значения. Вероятно датчик не принял настройки: баг в коде библиотеки, баг у вас в коде, надо искать…

Добавить комментарий для Владимир Отменить ответ

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.