Ардуино: акселерометр 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 вертикально, акселерометр выдает значения близкие к 4000 тысячам. Откуда берется это число?

Точность измерения ускорения в 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 роботу.

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

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

2+

Изменено:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

      0

Добавить комментарий

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

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