Arduino и акселерометр MPU6050

Arduino и акселерометр MPU6050 Машинки
Содержание
  1. Motionapps
  2. Акселерометр
  3. Визуализация
  4. Гироскоп
  5. Калибровка
  6. Комплектация
  7. Макетная плата, предназначенная для прототипирования
  8. Микроконтроллер arduino uno r3
  9. Модуль датчика для гироскопа акселерометра на аrduino с 3 осями – gy-521 (mpu-6050)
  10. Обзор датчика пространства gy-521 (mpu6050)
  11. Общие сведения
  12. Питание
  13. Подключение
  14. Подключение гироскопа mpu6050 к arduino: схема и программа
  15. Подключение к плате arduino
  16. Подробнее о сенсоре
  17. Получение показаний датчика mpu6050
  18. Пример использования
  19. Совместное использование гироскопа и акселерометра
  20. Соединительные провода папа-папа
  21. Схема подключения
  22. Характеристики
  23. Шаг 1. компоненты для подключения акселерометра к arduino
  24. Шаг 2. схема подключения акселерометра к микроконтроллеру arduino
  25. Шаг 3. программируем arduino для обработки информации, полученной с акселерометра
  26. Калибровка компаса и вывод значений осей в монитор порта.
  27. Заключение

Motionapps

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

MotionApps

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

FIFO

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

Акселерометр

Для определения положения системы можно использовать трехосевой акселерометр. Акселерометр также имеет настраиваемые пределы измерений ±2g, ±4g, ±8g і ±16g. Эти пределы устанавливаются в зависимости от динамичности Вашей системы. Напомню, что на любое тело действует сила притяжения. В состоянии покоя g=1. В состоянии свободного падения, когда тело движется к земле с ускорением 9,81 м/с

2

– g=0. При разных ускорениях g будет разным. Чем выше ускорение, тем больше g. Поэтому если у Вас достаточно медленная, задемпфированная система, которая физически не способна быстро ускоряться, не стоит устанавливать максимальные пределы измерений. Правильно выбранный диапазон измерений упростит в будущем фильтрацию показаний датчика.

Когда мы поворачиваем датчик в пространстве, показания акселерометра на каждой из трех осей будет изменяться в зависимости от положения. Так, с помощью трехосевого акселерометра под воздействием силы тяжести можно определить положение системы. См. работу скрипта mpu6050_accel_no_filter.py.

Мы видим, что значения достаточно зашумлены. Попробуем их фильтровать. Я применил очень упрощенный фильтр Калмана. См. работу скрипта mpu6050_accel_kf.py. Показания стали более стабильными, однако в нашем случае фильтр малополезен. Если датчик потрясти, мы увидим, что показания углов изменяются и иногда очень сильно, хотя мы его не поворачиваем, а перемещаем с ускорением вдоль осей.

Это логично, поскольку на акселерометр теперь кроме силы тяжести действует дополнительная сила, и результирующий вектор изменяет направление. Наглядно это видно на примере скрипта pyplay_accel.py (в этом скрипте фильтрация не используется).

Визуализация

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

pygame

. Запуск этих скриптов рекомендуется выполнять из графической оболочки.

Успехов.

Смотри также:

Гироскоп

Гироскоп измеряет угловые скорости по трем осям с разными пределами измерений: 250, 500, 1000, и 2000 градусов в секунду. Пределы измерения могут быть выставлены в соответствии с Вашими задачами. Не стоит устанавливать без необходимости максимальные пределы, если у вас достаточно медленная система. Правильно выбранные пределы повысят точность измерений.

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

С помощью электронного гироскопа можно определить положение системы следующим образом. При включении принять начальное положение за нулевую позицию. Затем опрашивать гироскоп с заданным интервалом, зная интервал и скорость вращения, вычислять смещение и добавлять к текущему положению.

При этом мы предполагаем, что между двумя опросами датчика система поворачивалась с постоянной скоростью. Такой подход ведет к неизбежному накоплению ошибки. Что видно на примере. Смотри работу скрипта: mpu5060_gyro.py  или скрипта, графически отображающего положение гироскопа pyplay_gyro.py.

Калибровка

Если считать данные с датчика можно заметить некоторую погрешность. Например, при абсолютном покое датчика показания гироскопа будут отличаться от нуля.
А показания акселерометра по модулю могут превышать 1. См. работу скрипта

mpu6050_get_raw_no_calibr.py

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

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

MPU-6050-offset1MPU-6050-offset2Arduino и акселерометр MPU6050MPU-6050-offset3
В примере я предусмотрел процедуру калибровки. Скрипт калибровки: mpu6050_calibr.py. Калибровка выполняется в два этапа. Сначала датчик должен быть неподвижен. Подразумевается, что угловые скорости равны нулю. Калибруется гироскоп. Затем калибруется акселерометр. Нужно его не спеша поворачивать во всех направлениях. Эта процедура занимает около минуты. После чего функция калибровки выдает вычисленные значения, которые нужно прописать в скрипте. На этом калибровка закончена. После калибровки погрешность значительно снизится. См. Скрипт: mpu6050_get_raw.py. В этом скрипте в следующих строках указываются калибровочные данные:



mpu.gyro_offs = {`x`: -178, `y`: 259, `z`: -104}
mpu.accel_offs =  {`y`: -354, `x`: 389, `z`: -1482}

Комплектация

  • 1х сенсор MPU-9250;
  • 1х СОединитель типа “ПАПА-ПАПА”;

Макетная плата, предназначенная для прототипирования

Отладка – неотъемлемая часть построения электронных схем. Макетная плата незаменима для конструкции электронной аппаратуры. Ранее в изобретательстве использовали традиционные макетные платы, но сейчас широко распространены макетные платы, которые удобны тем, что не требуют дополнительных спаек.

Таким образом, процесс сборки и отладки электронной схемы в разы ускоряется: не приходится часто использовать паяльник, чтобы поменять сломанные радиодетали.

Материал для изготовления беспаечных макетных плат – пластик. Кроме того, все контакты надежно скреплены к плате, поэтому частые переключения не испортят элемент.

Микроконтроллер arduino uno r3

МК создан с использованием материалов контроллера ATmega328:

  1. цифровые входы и выходы в количестве 14 штук, причем половина приходится на ШИМ-выходы;
  2. аналогичные входы, количество – 6 штук;
  3. резонатор на основе кварца, мощностью 16 МГц;
  4. встроен usb-вход;
  5. контакт для подключения питания;
  6. на МК располагается кнопка, с помощью которой возможен сброс данных и кода;
  7. контакт для программирования данных, находящихся внутри схемы, именуемый ICSP.

Старт работы начинается с подачи электрического питания в плату. Пользователь подключает к плате со схемой блок питания или зарядное устройство. Также процедура осуществляется с помощью usb-кабеля, который подключен к компьютеру и микроконтроллеру. Для разработки программы понадобится бесплатная среда программирования – Arduino IDE.

Смотрите про коптеры:  Квадрокоптер syma x5c тюнинг двигателя

Внимание! Пользователь разрабатывает приложения с использованием Ардуино, только если платы совместимы с архитектурой микроконтроллера. В противном случае программа не заработает.

Пользователь создает в бесплатной среде код, затем его компилирует и загружает проработанную программу в пространство памяти в Ардуино. Язык, на котором программируется код, Wiring максимально приближен к популярному среди программистов языку – C . Кроме того МК поддерживает версии для осей Виндовс, Мак ОС и Линукс.

Модуль датчика для гироскопа акселерометра на аrduino с 3 осями – gy-521 (mpu-6050)

В основе компонента лежит микросхема MPU-6050. В комплект входят 2 предмета – гироскоп и акселерометр. Данные устройства перед конструированием обрабатываются и затем переносятся прямиком в микроконтроллер через интерфейс

Модуль датчика помогает определять место и перемещение инструмента в пространстве. Измеряются дифферент и углы крена посредством вектора силы тяжести и скорости в процессе вращения. Также включена функция измерения температурного режима. Перемещение определяется линейным ускорением и угловой скоростью. Полная картина рисуется по 3 осям.

Компонент нередко сравнивают с человеческим вестибулярным аппаратом, который помогает людям чувствовать силу тяготения и удерживать равновесие.

Обзор датчика пространства gy-521 (mpu6050)

GY-521 (рис. 1) – модуль с гироскопом, акселерометром и термометром на базе микросхемы MPU-6050 используется в любительской робототехнике для  определения положения в пространстве.

Рисунок 1. Модуль GY521.

Модуль GY-521 построен на базе микросхемы MPU6050. На плате модуля также расположена необходимая обвязка MPU6050, включая подтягивающие резисторы интерфейса I2C. Гироскоп используется для измерения линейных ускорений, а акселерометр – угловых скоростей. Совместное использование акселерометра и гироскопа позволяет определить движение тела в трехмерном пространстве.

Общие сведения

9-осевой сенсор MPU-9250 9DOF — сенсор второго поколения компании InvenSense для определения положения в пространстве, включающий в себя 3-осевой Гироскоп, 3-осевой Акселерометр и 3-осевой Компас (Магнетометр).

Питание

Для удобства подключения к Arduino воспользуйтесь Trema Shield, Trema Power Shield, Motor Shield или Trema Set Shield.

Входное напряжение питания 3,3 В или 5 В постоянного тока, подаётся на выводы VCC и GND модуля.

Подключение

Подключить сенсор к микроконтроллеру Вы можете одним из 2 способов:

  • по шине I2C: используя 4 контакта VCC, GNG, SCL, SDA
  • по шине SPI: используя 5 контактов VCC, GND, SCL, SDA, CS, SDO

Подключение гироскопа mpu6050 к arduino: схема и программа

#include<LiquidCrystal.h> // библиотека для работы с ЖК дсиплеем

LiquidCrystallcd(8,9,10,11,12,13);// номера контактов, к которым подключен ЖК дисплей

#include <Wire.h>

#include <MPU6050.h> // библиотека для работы с датчиком MPU6050 (ссылка для ее скачивания приведена в тексте статьи)

#define period 10000

MPU6050mpu;

intcount=0;

charokFlag=0;

bytedegree[8]={

  0b00000,

  0b00110,

  0b01111,

  0b00110,

  0b00000,

  0b00000,

  0b00000,

  0b00000

};// символ градуса

voidsetup()

{

  lcd.begin(16,2);

  lcd.createChar(0,degree);

  Serial.begin(9600);// инициализируем последовательный порт для работы на скорости 9600 бод/с

  Serial.println(“Initialize MPU6050”);

  while(!mpu.begin(MPU6050_SCALE_2000DPS,MPU6050_RANGE_2G))

  {//если нет соединения с MPU6050, выдаем предупреждающие сообщения

    lcd.clear();

    lcd.print(“Device not Found”);

    Serial.println(“Could not find a valid MPU6050 sensor, check wiring!”);

    delay(500);

  }

  count=0;

  mpu.calibrateGyro();// калибровка гироскопа

  mpu.setThreshold(3);

  lcd.clear();

  lcd.print(“MPU6050 Interface”);

  lcd.setCursor(0,1);

  lcd.print(” Circuit Digest”);

  delay(2000);

  lcd.clear();

}

voidloop()

{

    lcd.clear();

    lcd.print(“Temperature”);

    longst=millis();

    Serial.println(“Temperature”);

    while(millis()<st period)

    {

      lcd.setCursor(0,1);

      tempShow();

    }

    lcd.clear();

    lcd.print(“Gyro”);

    delay(2000);

    st=millis();

    Serial.println(“Gyro”);

    while(millis()<st period)

    {

      lcd.setCursor(0,1);

      gyroShow();

    }

    lcd.clear();

    lcd.print(“Accelerometer”);

    delay(2000);

    st=millis();

    Serial.println(“Accelerometer”);

    while(millis()<st period)

    {

      lcd.setCursor(0,1);

      accelShow();

    }

}

voidtempShow()//данные температуры

{

    floattemp=mpu.readTemperature();

    Serial.print(” Temp = “);

    Serial.print(temp);

    Serial.println(” *C”);

    lcd.clear();

    lcd.print(“Temperature”);

    lcd.setCursor(0,1);

    lcd.print(temp);

    lcd.write((byte)0);

    lcd.print(“C”);

    delay(400);

}

voidgyroShow()//данные гироскопа

{

  //lcd.setCursor(0,0);

  lcd.clear();

  lcd.print(” X     Y     Z”);

  VectorrawGyro=mpu.readRawGyro();

  VectornormGyro=mpu.readNormalizeGyro();

  lcd.setCursor(0,1);

  lcd.print(normGyro.XAxis,1);

  lcd.setCursor(6,1);

  lcd.print(normGyro.YAxis,1);

  lcd.setCursor(12,1);

  lcd.print(normGyro.ZAxis,1);

  Serial.print(” Xnorm = “);

  Serial.print(normGyro.XAxis);

  Serial.print(” Ynorm = “);

  Serial.print(normGyro.YAxis);

  Serial.print(” Znorm = “);

  Serial.println(normGyro.ZAxis);

  delay(200);

}

voidaccelShow()// данные акселерометра

{

// lcd.setCursor(0,0);

  lcd.clear();

  lcd.print(” X     Y     Z”);

  VectorrawAccel=mpu.readRawAccel();

  VectornormAccel=mpu.readNormalizeAccel();

  lcd.setCursor(0,1);

  lcd.print(normAccel.XAxis,1);

  lcd.setCursor(6,1);

  lcd.print(normAccel.YAxis,1);

  lcd.setCursor(12,1);

  lcd.print(normAccel.ZAxis,1);

  Serial.print(” Xnorm = “);

  Serial.print(normAccel.XAxis);

  Serial.print(” Ynorm = “);

  Serial.print(normAccel.YAxis);

  Serial.print(” Znorm = “);

  Serial.println(normAccel.ZAxis);

  delay(200);

}

Подключение к плате arduino


Подключение к плате Arduino по интерфейсу I2C. Схема подключения показана на рис. 2.

Рисунок 2.

Загрузив на плату Arduino скетч сканирования I2C-устройств (Листинг 1), в мониторе последовательного порта увидим I2C-адрес модуля MPU6050 – 0x68 (рис. 3).

Листинг 1

#include "Wire.h"

//#define MY_SERIAL //

void setup() 
  {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Serial.println("nI2C Scanner");
  Wire.begin();
  }

void loop() 
  {
  int nDevices;
  byte error, address;  
 
  Serial.println("Scanning I2C bus...n");
 

  nDevices = 0;

  Serial.print("   00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
  
  
  for(address = 0; address < 128; address   )
  {
    if((address % 0x10) == 0)
    {
      Serial.println();
      if(address < 16)
        Serial.print('0');
      Serial.print(address, 16);
      Serial.print(" ");
    }
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);error = Wire.endTransmission();

    
    if (error == 0)
    {
      if (address<16)
         Serial.print("0");
      Serial.print(address, HEX);
    
      nDevices  ;
    }
    else 
    {
      Serial.print("--");
    } 

    Serial.print(" ");
    delay(1);
  }
  Serial.println();
  
  if (nDevices == 0)
     Serial.println("No I2C devices foundn");
   else
   {
    
     Serial.print("Found ");
     Serial.print(nDevices);
     Serial.println(" device(s) "); 
   }
 
  delay(2500);           // wait 5 seconds for next scan

  }

Рисунок 3.

Подробнее о сенсоре

Микросхема сенсора MPU-9250 9DOF состоит из 2 чипов: MPU-6500 — чип, включающий в себя 3-осевой гироскоп и акселерометр и AK8963 — чип, включающий в себя 3-осевой компас и интегрированный Digital Motion Processor (DMP).

Смотрите про коптеры:  Стратегия развития боевого флота - Deep games

Данный сенсор является одним из самых миниатюрных в мире (3мм*3мм*1мм). Используется в смартфонах, планшетах, носимых датчиках и других устройствах. Если к модулю добавить барометр, получится сенсор на 10 степеней свободы.

Может использоваться для создания дронов, роботов, 3-мерных контроллеров, а так же в системах, поддерживающих управление жестами.

Обратите внимание, что в микросхеме MPU9250 определение осей у Гироскопа и Акселерометра одно, а у Магнитометра другое!

Для работы с сенсором вам понадобится библиотека IMU_10DOF. При необходимости Вы так же можете ознакомиться с DataSheet’ом.

Получение показаний датчика mpu6050

Для работы с датчиком MPU6050 будем использовать библиотеки I2Cdev и MPU6050. После установки библиотек загрузим на плату Arduino скетч для отображения показаний акселерометра по одной из осей – оси x. Содержимое скетча показано в листинге 2.

Листинг 2

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

#define TIME_OUT 20

MPU6050 accgyro;
unsigned long int t1;

void setup() {
    Serial.begin(9600);
    accgyro.initialize();
}

void loop() {
    long int t = millis();
    if( t1 < t ){
        int16_t ax, ay, az, gx, gy, gz;

        t1 = t   TIME_OUT;
        accgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
        Serial.println(ax); 
    }
}

Для отображения данных выбираем в настройках Плоттер по последовательному соединению (рис. 4). Смотрим показания вращая датчик по оси x в одну и другую стороны.

Рисунок 4.

Библиотека MPU6050 по умолчанию настраивает датчик на диапазон ±8g (возможные значения ±2g, 4g, 8g и 16g). для 16 разрядного АЦП датчика это значения от -215
до 215 , поэтому возможные значения на графике ±215/16*8 (-16384 до 16384).

Скетч из листинга 3 преобразует сырые показания датчика MPU6050 в угол наклона датчика относительно оси x.

Листинг 3

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

#define TO_DEG 57.2957f
#define TIME_OUT 20

MPU6050 accgyro;

float anglex;
long int t1;

void setup() {
    Serial.begin(9600);
    // инициализация датчика 
    accgyro.initialize(); 
}

void loop() {
    long int t = millis();
    if( t1 < t ){
        int16_t ax, ay, az, gx, gy, gz;
        float accy,gyrox;

        t1 = t   TIME_OUT;
        accgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
 
        // преобразование в единицы гравитации при настройках 1G 
        accy = ax /4096.0;
        //  границы от -1G до  1G  
        accy = clamp(accy, -1.0, 1.0);
        // получить значение в градусах
        if( accy >= 0){
            anglex = 90 - TO_DEG*acos(accy);
        } else {
            anglex = TO_DEG*acos(-ay) - 90;
        }
        Serial.println(anglex); 
    }
}

И смотрим показания угла наклона, вращая датчик по оси x в одну и другую стороны (рис. 5).

Рисунок 5.

Пример использования

В качестве примера рассмотрим проект по созданию пульта на MPU6050 для удаленного управления движущейся платформой.

Нам потребуются следующие компоненты. Для пульта управления:


Для движущейся платформы:

Схема соединения элементов пульта управления показана на рис. 6.

Рисунок 6.

Схема соединений для компонентов для движущейся платформы показана на рис. 7.

Рисунок 7.

Приступим к написанию скетчей. Передатчик отправляет 3 значения – начальный байт отправки B11111111 и 2 значения наклона датчика – по оси x и по оси y.

Содержимое скетча показано в листинге 4.

Листинг 4

#include "I2Cdev.h"
#include "MPU6050.h"
#include <RCSwitch.h>

#define TO_DEG 57.2957f
#define TIME_OUT 20

MPU6050 accgyro;
RCSwitch mySwitch = RCSwitch();

float anglex;
float angley;
long int t1;

void setup() {
    Serial.begin(9600);
    // инициализация датчика 
    accgyro.initialize(); 
    mySwitch.enableTransmit(2);
}

void loop() {
    long int t = millis();
    if( t1 < t ){
        int16_t ax, ay, az, gx, gy, gz;
        float accy,gyrox;

        t1 = t   TIME_OUT;
        accgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
 
        // преобразование в единицы гравитации при настройках 1G = 4096
        accx = ax/4096.0;
        accy = ax/4096.0;
        // границы от -1G до  1G  
        accx = clamp(accx, -1.0, 1.0);
        accy = clamp(accy, -1.0, 1.0);

        // получить значение в градусах
        if( accy >= 0){
            anglex = 90 - TO_DEG*acos(accy);
        } else {
            anglex = TO_DEG*acos(-accy) - 90;
        }
        if( accx >= 0){
            angley = 90 - TO_DEG*acos(accx);
        } else {
            angley = TO_DEG*acos(-accx) - 90;
        }
        // отправка данных
        mySwitch.send(B11111111, 8);
        delay(50);
        mySwitch.send((byte)anglex, 8);
        delay(50);
        mySwitch.send((byte)angley, 8);
        delay(100); 
    }
}


Плата Arduino на движущейся платформе должна получать данные и преобразовывать их в команды установки скорости для двух моторов.

Содержимое скетча показано в листинге 5.

Листинг 5

// подключение библитеки
#include <RCSwitch.h>
// создание объекта
RCSwitch mySwitch = RCSwitch();

int motor=0;

void setup() {
  pinMode(10,OUTPUT);
  pinMode(9,OUTPUT);
  pinMode(8,OUTPUT);
  pinMode(5,OUTPUT);
  pinMode(7,OUTPUT);
  pinMode(6,OUTPUT);
  // запуск приемника
  mySwitch.enableReceive(0);
}

void loop() {
    if( mySwitch.available() ){
        // получить данные
        int value = mySwitch.getReceivedValue();
        
        if( value == B11111111 ) {// начало передачи
            motor=1;
        }
        else {
            if(motor==1) {
                go(10,9,8,value);
            }
            else if(motor==2) {
                go(5,7,6,value);
            }
            motor  ;
        }
        mySwitch.resetAvailable();
    }
}
// запуск двигателей
void go(int pina,int pin1,int pin2,int val) {
   analogWrite(pina,map(abs(val),0,90,0,255));
   if(val<=0) {
      digitalWrite(pin1,0);
      digitalWrite(pin2,1);
   }
   else {
      digitalWrite(pin1,1);
      digitalWrite(pin2,0);
   }
}

Рисунок 8. Пульт

Рисунок 9. Движущаяся платформа

Совместное использование гироскопа и акселерометра

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

Он достаточно прост и работает следующим образом.
За первоначальное положение принимается положение, вычисленное на основании данных акселерометра. Затем с заданным интервалом вычисляются положение на основе данных гироскопа и положение на основе данных акселерометра.

См. работу скрипта mpu6050_final.py или скрипта pyplay_final.py, который графически изображает процесс работы MPU-6050

Соединительные провода папа-папа

Обычные провода папа-папа нам подойдут, еще их называют провода-перемычки. Такие стоят недорого и продаются везде, на любом рынке или в любом онлайн-магазине для радиолюбителей.

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

Для подключения к контроллеру или микрокомпьютеру, у датчика имеется шина I

2

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

  • Микросхема : MPU9250
  • Интерфейс: I2C (400кГц) / SPI (1 МГц)
  • Буфер: FIFO 512B
  • Рабочие диапазоны гироскопа: ±250, ±500, ±1000, ±2000 °/с;
  • Рабочие диапазоны акселерометра: ±2, ±4, ±8, ±16 g;
  • Рабочий диапазон магнитометра: ±4800 мкТл;
  • Напряжение питания: 2,4–3,6 В;
  • Рабочий ток: гироскоп – 3,2 мА, акселерометр – 450 мкА, магнитометр – 280 мкА;
  • Размер: 15мм х 25мм

Шаг 1. компоненты для подключения акселерометра к arduino

Для проекта понадобятся несколько компонентов:

Шаг 2. схема подключения акселерометра к микроконтроллеру arduino

Порядок и схема подключения довольно просты:

GY-521 (MPU-6050)Arduino Uno
VCC3.3 V
GNDGND
SCLA5
SDAA4
  1. Присоединяем модуль датчика к микроконтроллеру.
  2. На МК Ардуино загружаем проработанный код, представленный в разделе ниже.
  3. Открываем среду разработки Arduino IDE и мониторим последовательный порт.
  4. Сверяем выводимые данные акселерометра и гироскопа.
  5. Во время поворота датчика сведения не производят изменений.

Гироскоп – инструмент, который позволяет измерить реакцию тела на перемещение углов и вообще ориентации. Акселерометр же служит измерителем проекции ускорения, которое только кажется.

Шаг 3. программируем arduino для обработки информации, полученной с акселерометра

Алгоритм написания программы в последовательности:

// Подключаем необходимые для работы библиотек
#include "MPU6050.h";
#include "I2Cdev.h";
#include "Wire.h";

// Создаем объект, символизирующий модуль датчика
MPU6050 axeler;

// Создаем объект библиотеки Wire
Wire b;

// Создаем объект, который символизирует контакт I2C
I2Cdev h;

// Вводим цифровые данные, отвечающие за точки в 3-х осях
int16_t axx, axy, axz;
int16_t gix, giy, giz;

// Объявляем метод, который будет запускать программу
void setup()

{
// Начинаем работу
Wire.begin();
h.begin(38400);

// Производим инициализацию, отчет выводится после компиляции
h.println("Initializing I2C devices...");
axeler.initialize();
delay(100);
}

// Считываем значения гироскопа и акселерометра с помощью адресов, которые принадлежат описанным выше переменным
void loop()
{
axeler.getMotion6(&axx, &axy, &axz, &gix, &giy, &giz);

// Выводим получившиеся значения на экран
h.print("a/g:t");
h.print(axx); 
h.print("t");
h.print(axy);
hl.print("t");
hl.print(axz); 
h.print("t");
h.print(gix); 
h.print("t");
h.print(giy); 
h.print("t");
h.println(giz);
}

Вуаля! Акселерометр Аrduino запрограммирован.

Смотрите про коптеры:  Схема стабилизатора напряжения - простой расчёт

В принципе, для разнообразия можно написать еще один скетч (ниже), но тогда нам нужна будет еще одна библиотека – Kalman (Gy-521, mpu6050), которая преобразует показания координат X и Y.

#include <Wire.h>
#include "Kalman.h"
Kalman kalmanX;
Kalman kalmanY;
uint8_t IMUAddress = 0x68;
/* IMU Data */
int16_t accX;
int16_t accY;
int16_t accZ;
int16_t tempRaw;
int16_t gyroX;
int16_t gyroY;
int16_t gyroZ;
double accXangle; // Angle calculate using the accelerometer
double accYangle;
double temp;
double gyroXangle = 180; // Angle calculate using the gyro
double gyroYangle = 180;
double compAngleX = 180; // Calculate the angle using a Kalman filter
double compAngleY = 180;
double kalAngleX; // Calculate the angle using a Kalman filter
double kalAngleY;
uint32_t timer;
void setup() {
  Wire.begin();
  Serial.begin(9600);
  i2cWrite(0x6B,0x00); // Disable sleep mode      
  kalmanX.setAngle(180); // Set starting angle
  kalmanY.setAngle(180);
  timer = micros();
}
void loop() {
  /* Update all the values */
  uint8_t* data = i2cRead(0x3B,14);
  accX = ((data[0] << 8) | data[1]);
  accY = ((data[2] << 8) | data[3]);
  accZ = ((data[4] << 8) | data[5]);
  tempRaw = ((data[6] << 8) | data[7]);
  gyroX = ((data[8] << 8) | data[9]);
  gyroY = ((data[10] << 8) | data[11]);
  gyroZ = ((data[12] << 8) | data[13]);
  /* Calculate the angls based on the different sensors and algorithm */
  accYangle = (atan2(accX,accZ) PI)*RAD_TO_DEG;
  accXangle = (atan2(accY,accZ) PI)*RAD_TO_DEG;  
  double gyroXrate = (double)gyroX/131.0;
  double gyroYrate = -((double)gyroY/131.0);
  gyroXangle  = kalmanX.getRate()*((double)(micros()-timer)/1000000); // Calculate gyro angle using the unbiased rate
  gyroYangle  = kalmanY.getRate()*((double)(micros()-timer)/1000000);
  kalAngleX = kalmanX.getAngle(accXangle, gyroXrate, (double)(micros()-timer)/1000000); // Calculate the angle using a Kalman filter
  kalAngleY = kalmanY.getAngle(accYangle, gyroYrate, (double)(micros()-timer)/1000000);
  timer = micros();
Serial.println();
    Serial.print("X:");
    Serial.print(kalAngleX,0);
    Serial.print(" ");
    Serial.print("Y:");
    Serial.print(kalAngleY,0);
    Serial.println(" ");
  // The accelerometer's maximum samples rate is 1kHz
}
void i2cWrite(uint8_t registerAddress, uint8_t data){
  Wire.beginTransmission(IMUAddress);
  Wire.write(registerAddress);
  Wire.write(data);
  Wire.endTransmission(); // Send stop
}
uint8_t* i2cRead(uint8_t registerAddress, uint8_t nbytes) {
  uint8_t data[nbytes];
  Wire.beginTransmission(IMUAddress);
  Wire.write(registerAddress);
  Wire.endTransmission(false); // Don't release the bus
  Wire.requestFrom(IMUAddress, nbytes); // Send a repeated start and then release the bus after reading
  for(uint8_t i = 0; i < nbytes; i  )
    data [i]= Wire.read();
  return data;
}

После второго скетча вы на экране сможете увидеть подобные цифры:

Калибровка компаса и вывод значений осей в монитор порта.

Подключим сенсор через I2C.

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

#include <Wire.h>
#include <I2Cdev.h>
#include <MPU9250.h>
// По умолчанию адрес устройства на шине I2C - 0x68
MPU9250 accelgyro;
I2Cdev   I2C_M;
uint8_t buffer_m[6];
int16_t ax, ay, az;
int16_t gx, gy, gz;
int16_t   mx, my, mz;
float heading;
float tiltheading;
float Axyz[3];
float Gxyz[3];
float Mxyz[3];
// время выполнения предварительной калибровки
#define sample_num_mdate  5000
volatile float mx_sample[3];
volatile float my_sample[3];
volatile float mz_sample[3];
static float mx_centre = 0;
static float my_centre = 0;
static float mz_centre = 0;
volatile int mx_max = 0;
volatile int my_max = 0;
volatile int mz_max = 0;
volatile int mx_min = 0;
volatile int my_min = 0;
volatile int mz_min = 0;
void setup()
{
    //подключаемся к шине I2C (I2Cdev не может сделать это самостоятельно)
    Wire.begin();
    // инициализация подключения в Мониторе порта
    // ( 38400бод выбрано потому, что стабильная работа наблюдается и при 8MHz и при 16Mhz, поэтому
    // в дальнейшем выставляйте скорость согласно ваших требований)
    Serial.begin(38400);
    // Инициализация устройства
    Serial.println("Initializing I2C devices...");
    accelgyro.initialize();
    // Подтверждение подключения
    Serial.println("Testing device connections...");
    Serial.println(accelgyro.testConnection() ? "MPU9250 connection successful" : "MPU9250 connection failed");
    delay(1000);
    Serial.println("     ");
    // Предварительная калибровка магнитометра
    Mxyz_init_calibrated ();
}
void loop()
{
    getAccel_Data();             // Получение значений Акселерометра
    getGyro_Data();              // Получение значений Гироскопа
    getCompassDate_calibrated(); // В этой функции происходит калибровка магнитометра
    getHeading();                // после чего мы получаем откалиброванные значения углов поворота
    getTiltHeading();            // и наклона
    Serial.println("calibration parameter: ");
    Serial.print(mx_centre);
    Serial.print("         ");
    Serial.print(my_centre);
    Serial.print("         ");
    Serial.println(mz_centre);
    Serial.println("     ");
    Serial.println("Acceleration(g) of X,Y,Z:");
    Serial.print(Axyz[0]);
    Serial.print(",");
    Serial.print(Axyz[1]);
    Serial.print(",");
    Serial.println(Axyz[2]);
    Serial.println("Gyro(degress/s) of X,Y,Z:");
    Serial.print(Gxyz[0]);
    Serial.print(",");
    Serial.print(Gxyz[1]);
    Serial.print(",");
    Serial.println(Gxyz[2]);
    Serial.println("Compass Value of X,Y,Z:");
    Serial.print(Mxyz[0]);
    Serial.print(",");
    Serial.print(Mxyz[1]);
    Serial.print(",");
    Serial.println(Mxyz[2]);
    Serial.println("The clockwise angle between the magnetic north and X-Axis:"); // "Угол поворота"
    Serial.print(heading);
    Serial.println(" ");
    Serial.println("The clockwise angle between the magnetic north and the projection of the positive X-Axis in the horizontal plane:"); // "Угол наклона"
    Serial.println(tiltheading);
    Serial.println("   ");
    Serial.println();
    delay(1000);
}
void getHeading(void)
{
    heading = 180 * atan2(Mxyz[1], Mxyz[0]) / PI;
    if (heading < 0) heading  = 360;
}
void getTiltHeading(void)
{
    float pitch = asin(-Axyz[0]);
    float roll = asin(Axyz[1] / cos(pitch));
    float xh = Mxyz[0] * cos(pitch)   Mxyz[2] * sin(pitch);
    float yh = Mxyz[0] * sin(roll) * sin(pitch)   Mxyz[1] * cos(roll) - Mxyz[2] * sin(roll) * cos(pitch);
    float zh = -Mxyz[0] * cos(roll) * sin(pitch)   Mxyz[1] * sin(roll)   Mxyz[2] * cos(roll) * cos(pitch);
    tiltheading = 180 * atan2(yh, xh) / PI;
    if (yh < 0)    tiltheading  = 360;
}
void Mxyz_init_calibrated ()
{
    Serial.println(F("Before using 9DOF,we need to calibrate the compass first. It will takes about 1 minute."));  // Перед использованием сенсора необходимо произвести калибровку компаса. Это займёт около минуты.
    Serial.print("  ");
    Serial.println(F("During  calibrating, you should rotate and turn the 9DOF all the time within 1 minute."));   // На протяжении всего времени калибровки Вам необходимо вращать сенсор во все стороны.
    Serial.print("  ");
    Serial.println(F("If you are ready, please sent a command data 'ready' to start sample and calibrate."));      // Если Вы готовы, для начала калибровки отправьте в Мониторе Порта "ready". 
    while (!Serial.find("ready"));
    Serial.println("  ");
    Serial.println("ready");
    Serial.println("Sample starting......");
    Serial.println("waiting ......");
    get_calibration_Data ();
    Serial.println("     ");
    Serial.println("compass calibration parameter ");
    Serial.print(mx_centre);
    Serial.print("     ");
    Serial.print(my_centre);
    Serial.print("     ");
    Serial.println(mz_centre);
    Serial.println("    ");
}
void get_calibration_Data ()
{
    for (int i = 0; i < sample_num_mdate; i  )
    {
        get_one_sample_date_mxyz();
        /*
        Serial.print(mx_sample[2]);
        Serial.print(" ");
        Serial.print(my_sample[2]);                            // здесь Вы можете увидеть полученные "сырые" значения.
        Serial.print(" ");
        Serial.println(mz_sample[2]);
        */
        if (mx_sample[2] >= mx_sample[1])mx_sample[1] = mx_sample[2];
        if (my_sample[2] >= my_sample[1])my_sample[1] = my_sample[2]; // Поиск максимального значения
        if (mz_sample[2] >= mz_sample[1])mz_sample[1] = mz_sample[2];
        if (mx_sample[2] <= mx_sample[0])mx_sample[0] = mx_sample[2];
        if (my_sample[2] <= my_sample[0])my_sample[0] = my_sample[2]; // Поиск минимального значения
        if (mz_sample[2] <= mz_sample[0])mz_sample[0] = mz_sample[2];
    }
    mx_max = mx_sample[1];
    my_max = my_sample[1];
    mz_max = mz_sample[1];
    mx_min = mx_sample[0];
    my_min = my_sample[0];
    mz_min = mz_sample[0];
    mx_centre = (mx_max   mx_min) / 2;
    my_centre = (my_max   my_min) / 2;
    mz_centre = (mz_max   mz_min) / 2;
}
void get_one_sample_date_mxyz()
{
    getCompass_Data();
    mx_sample[2] = Mxyz[0];
    my_sample[2] = Mxyz[1];
    mz_sample[2] = Mxyz[2];
}
void getAccel_Data(void)
{
    accelgyro.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);
    Axyz[0] = (double) ax / 16384;
    Axyz[1] = (double) ay / 16384;
    Axyz[2] = (double) az / 16384;
}
void getGyro_Data(void)
{
    accelgyro.getMotion9(&ax, &ay, &az, &gx, &gy, &gz, &mx, &my, &mz);
    Gxyz[0] = (double) gx * 250 / 32768;
    Gxyz[1] = (double) gy * 250 / 32768;
    Gxyz[2] = (double) gz * 250 / 32768;
}
void getCompass_Data(void)
{
    I2C_M.writeByte(MPU9150_RA_MAG_ADDRESS, 0x0A, 0x01); // активируем магнетометр
    delay(10);
    I2C_M.readBytes(MPU9150_RA_MAG_ADDRESS, MPU9150_RA_MAG_XOUT_L, 6, buffer_m);
    mx = ((int16_t)(buffer_m[1]) << 8) | buffer_m[0] ;
    my = ((int16_t)(buffer_m[3]) << 8) | buffer_m[2] ;
    mz = ((int16_t)(buffer_m[5]) << 8) | buffer_m[4] ;
    Mxyz[0] = (double) mx * 1200 / 4096;
    Mxyz[1] = (double) my * 1200 / 4096;
    Mxyz[2] = (double) mz * 1200 / 4096;
}
void getCompassDate_calibrated ()
{
    getCompass_Data();
    Mxyz[0] = Mxyz[0] - mx_centre;
    Mxyz[1] = Mxyz[1] - my_centre;
    Mxyz[2] = Mxyz[2] - mz_centre;
}

Заключение

Модуль датчика – устройство, которое широко используется во многих сферах человеческой жизни. С помощью датчика приводят в норму полет квадрокоптера, потому что гироскоп и акселерометр часто применяются в совокупности.

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

Оцените статью
Радиокоптер.ру
Добавить комментарий