Návod pro akcelerometr a gyroskop MPU-6050

 Návod pro akcelerometr a gyroskop MPU-6050

Člověk se umí skvěle orientovat v prostoru, ale umí to také Arduino? Neumí, ale my mu k tomu dopomůžeme. Tedy spíše gyroskop a akcelerometr v jednom, a to hned 3osý! V našem případě se bude jednat o elektronický modul senzor GY-521, který disponuje MPU-6050. Tyto moduly najdou v dnešní době využití především v kvadrokoptérách nebo dronech. Dnešní článek bude celý o využití akcelerometru a gyra GY-521 s čipem MPU6050.

Zapojení GY-521

Modul GY-521 vyžaduje 3,3V, avšak se zde nachází regulátor, který nám umožnuje připojit 5V, tím je vyřešené napájení. Komunikace probíhá pomocí I2C sběrnice tzn. Potřebujeme pull-up rezistor. Ten je však už také zabudovaný v modulu. Ostatní piny slouží pro různé buzení, nebo přerušení signálu, hraní si s FIFO bufferem atd. Tím se my zabývat nebudeme, zapojte tedy modul podle schématu.

Schéma zapojení 3osého akcelerometru a gyroskopu GY-521

Program pro GY-521

Pro správnou funkčnost musíme importovat 2 knihovny, které jsou ke stažení na konci článku. Pokud nevíte, jak správně importovat knihovnu, podívejte se na návod, kde se věnujeme knihovnám na stránce Jak správně naimportovat knihovnu?. Knihovna nabízí nepřeberné množství nových funkcí, my si ukážeme jen ty základní.
První program, bude mít za úkol otestovat zařízení (připojení a komunikaci) a poté vypisovat všech 6 naměřených hodnot po seriál monitoru.

// importování knihoven
#include "I2Cdev.h"
#include "MPU6050.h"

// knihovna "Wire" je vyžadována, pokud je knhovna I2Cdev obsažena v programu
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
#endif

MPU6050 accelgyro;

// vytvoříme proměné
int16_t ax, ay, az;
int16_t gx, gy, gz;

// pokud chceme, aby hodnoty byly v tabulce, napíšeme:
#define OUTPUT_READABLE_ACCELGYRO

void setup()
{
    // přopojíme se na I2C sběrnici, knihovna to sama neumí
    #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
        Wire.begin();
    #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
        Fastwire::setup(400, true);
    #endif

    // zvolíme rychlsot sériové komunikace
    Serial.begin(9600);

    // inicializujem (sputíme) zařízení
    Serial.println("Spousteni zarizeni MPU6050");
    accelgyro.initialize();

    // oveříme funkčnost zařízení
    Serial.println("Testovani zarizeni");
    Serial.println(accelgyro.testConnection() ? "Zarizeni funguje spravne" : "Zarizeni se nepodarilo pripojit");
}

void loop() {
    // přečteme neupravená data ze senzoru
    accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

    // jelikož jsme si na 17. řádku nastavili "READABLE"
    #ifdef OUTPUT_READABLE_ACCELGYRO
        // vypíšeme hodnoty po sériové lince
        // "/t" zalamuje řádek
        Serial.print("a|g:\t");
        Serial.print(ax); Serial.print("\t");
        Serial.print(ay); Serial.print("\t");
        Serial.print(az); Serial.print("\t");
        Serial.print(gx); Serial.print("\t");
        Serial.print(gy); Serial.print("\t");
        Serial.println(gz);
    #endif
}

 

Pokud vše funguje, jak má, uvidíme po zapnutí seriál monitoru toto:

Výstup GY-521 do seriál monitoru

Zdá se vám, že čidlo v klidu měří různé hodnoty? Ano, máte pravdu. Čidlo je neskutečně citlivé a pouhé bouchnutí do stolu (vibrace) změní výsledek měření. Pokud by jste chtěli o tomtu problému vědět více, navštivte stránku playground.arduino.cc/Main/MPU-6050, kde se těmto problémům věnují dopodrobna. My si alespoň ukážeme, jak čidlo kalibrovat.

Kompenzace odchylek/kalibrování GY-521

Kalibrace samozřejmě probíhá pomocí programu. Program otestuje funkčnost zařízení, poté vypíše nastavené odchylky. Pak přijde část, kde odchylky změníme a znova si je necháme vypsat. Aby jste v seriál monitoru viděli změnu, zapněte ho ještě před náhráním programu. Pokud by jste program nahráli a až pak otevřeli seriál monitor (program by proběhl 2x), tak už byste změnu neviděli.

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

#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
#endif

MPU6050 accelgyro;

int16_t ax, ay, az;
int16_t gx, gy, gz;

#define OUTPUT_READABLE_ACCELGYRO

void setup()
{
    #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
        Wire.begin();
    #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
        Fastwire::setup(400, true);
    #endif

    Serial.begin(9600);

    Serial.println("Spousteni zarizeni MPU6050");
    accelgyro.initialize();

    Serial.println("Testovani zarizeni");
    Serial.println(accelgyro.testConnection() ? "Zarizeni funguje spravne" : "Zarizeni se nepodarilo pripojit");

    // vypíšeme si současnou hodnotu odchylek
    Serial.println("Uprava/kompenzovani odchylek zarizeni");
    Serial.print(accelgyro.getXAccelOffset()); Serial.print("\t"); 
    Serial.print(accelgyro.getYAccelOffset()); Serial.print("\t"); 
    Serial.print(accelgyro.getZAccelOffset()); Serial.print("\t"); 
    Serial.print(accelgyro.getXGyroOffset()); Serial.print("\t"); 
    Serial.print(accelgyro.getYGyroOffset()); Serial.print("\t"); 
    Serial.print(accelgyro.getZGyroOffset()); Serial.print("\t"); 
    Serial.print("\n");

    // změníme hodnotu odchylek
    accelgyro.setXAccelOffset(20);
    accelgyro.setYAccelOffset(30);
    accelgyro.setZAccelOffset(40);
    
    accelgyro.setXGyroOffset(-20);
    accelgyro.setYGyroOffset(-40);
    accelgyro.setZGyroOffset(-60);

    // znova vypíšeme hodnotu odchylek
    Serial.print(accelgyro.getXAccelOffset()); Serial.print("\t"); 
    Serial.print(accelgyro.getYAccelOffset()); Serial.print("\t"); 
    Serial.print(accelgyro.getZAccelOffset()); Serial.print("\t"); 
    Serial.print(accelgyro.getXGyroOffset()); Serial.print("\t"); 
    Serial.print(accelgyro.getYGyroOffset()); Serial.print("\t"); 
    Serial.print(accelgyro.getZGyroOffset()); Serial.print("\t"); 
    Serial.print("\n");
}

void loop()
{
  // sem nic nepíšeme
}

 

Pokud vše uděláte správně, uvidíte toto:

Ukázka kalibrace čidla GY-521

 

Vlastní vodováha pomocí MPU-6050

Tak jsme dostali ze senzoru tzv. „raw data“, které se sice nějak logicky mění, ale nic nám neříkají, proto si je převedeme na stupně, které už budou mít daleko větší vypovídací hodnotu. Můžete použít jinou knihovnu, která to udělá za vás. Jelikož my už nějakou knihovnu máme, tak si vystačíme s ní. Na internetu si najdeme vzorečky, které právě umí z naměřených hodnot vypočítat sklon v ose x a v ose y. Tyto vzorečky mají tvar:

Vzorečky pro přepočet raw dat na radiány

Pokud máte strach z radiánů, tak výsledek ještě podělte (π/180) – výsledek tedy bude ve °. Program bude pak vypadat takle:

#include "Wire.h"
#include "Math.h"
#include "I2Cdev.h"
#include "MPU6050.h"
 
MPU6050 accelgyro;
 
const float pi = 3.141592;


const int counter_w = 100;

int16_t ax, ay, az;
float x, y, z;
int counter;
float  angle_x, angle_y, angle_z, _angle_x, _angle_y, _angle_z;
long ax_p, ay_p, az_p;
 
void setup()
{
  Wire.begin();
  Serial.begin(9600);
  
  Serial.println("Spousteni zarizeni MPU6050");
  accelgyro.initialize();
  
  Serial.println("Testovani zarizeni");
  Serial.println(accelgyro.testConnection() ? "Zarizeni funguje spravne" : "Zarizeni se nepodarilo pripojit");
}
 
void loop()
{
  // zjistí všechny hodnoty z akcelerometru
  accelgyro.getAcceleration(&ax, &ay, &az);
  
  // sčítáme potřebný počet hodnot
  ax_p = ax_p + ax;
  ay_p = ay_p + ay;
  az_p = az_p + az;

  // pocitadlo mereni
  counter++;
  
  // az bude mereni counter_w (100), tak:  
  if (counter == counter_w)
  {
    //zjistíme průmerné hodnoty
    x = ax_p/counter;
    y = ay_p/counter;
    z = az_p/counter;
     
    // vypočteme sklon a náklon [°]
    angle_x = atan2(x, sqrt(square(y) + square(z)))/(pi/180);
    angle_y = atan2(y, sqrt(square(x) + square(z)))/(pi/180);
    angle_z = atan2(z, sqrt(square(x) + square(y)))/(pi/180);
     
    // vynulujeme hodnoty    
    counter = 0;
    ax_p = 0;
    ay_p = 0;
    az_p = 0;

    // hodnoty si vypíšme do portu  
    Serial.print(angle_x); Serial.print("\t"); 
    Serial.print(angle_y); Serial.print("\t"); 
    Serial.println(angle_z);
  }
}

 

 

MPU-6050 s výstupem na i2c LED displej

Ne každý se spokojí s výstupem do Seriál monitoru, proto si připojíme také LCD displej. Použijeme LCD s I2C převodníkem, který můžeme klidně zapojit do stejných I2C pinů, protože LCD displej má definovanou adresu.

#include "Wire.h"
#include "Math.h"
#include "I2Cdev.h"
#include "MPU6050.h"
// přidáme knihovnu pro display
#include "LiquidCrystal_I2C.h"
 
MPU6050 accelgyro;
// definujeme LCD displej
LiquidCrystal_I2C lcd(0x27, 16, 2);
 
const float pi = 3.141592;

const int counter_w = 100;

int16_t ax, ay, az;
float x, y, z;
int counter;
float  angle_x, angle_y, angle_z, _angle_x, _angle_y, _angle_z;
long ax_p, ay_p, az_p;
 
void setup()
{
  Wire.begin();
  Serial.begin(9600);
  // spustíme LCD display
  lcd.begin();
  lcd.backlight();
  
  Serial.println("Spousteni zarizeni MPU6050");
  accelgyro.initialize();
  
  Serial.println("Testovani zarizeni");
  Serial.println(accelgyro.testConnection() ? "Zarizeni funguje spravne" : "Zarizeni se nepodarilo pripojit");
}
 
void loop()
{
  accelgyro.getAcceleration(&ax, &ay, &az);
  
  ax_p = ax_p + ax;
  ay_p = ay_p + ay;
  az_p = az_p + az;

  counter++;
    
  if (counter == counter_w)
  {
    x = ax_p/counter;
    y = ay_p/counter;
    z = az_p/counter;
     
    angle_x = atan2(x, sqrt(square(y) + square(z)))/(pi/180);
    angle_y = atan2(y, sqrt(square(x) + square(z)))/(pi/180);
    angle_z = atan2(z, sqrt(square(x) + square(y)))/(pi/180);
       
    counter = 0;
    ax_p = 0;
    ay_p = 0;
    az_p = 0;

    // před novým výpisem, ten starý smažeme
    lcd.clear();
    // zobrazíme nový výpis
    lcd.print(angle_x);
    lcd.print(" ");
    lcd.print(angle_y);
    lcd.print(" ");
    lcd.print(angle_z);
    delay(500);
  }
}

 

 

jednoduchý alarm s mpu-6050

Plán je jednoduchý - zjistíme jaké hodnoty vypisuje senzor v klidovém stavu, to budou naše referenční hodnoty, ke kterým budeme porovnávat naměřené hodnoty. Pokud se budou lišit o naši toleranci (5°), tak se alarm spustí. Do programu tedy přidáme proměnné referenčních hodnot a toleranci, pak už jen díky jednoduchým podmínkám uděláme zbytek. Pokud tedy někdo zvedne, nakloní, nebo otočí předmět, ve kterém je MPU-6050, tak se sepne alarm.

#include "Wire.h"
#include "Math.h"
#include "I2Cdev.h"
#include "MPU6050.h"
 
MPU6050 accelgyro;
 
const float pi = 3.141592;

const int counter_w = 100;

int16_t ax, ay, az;
float x, y, z;
int counter;
float  angle_x, angle_y, angle_z, _angle_x, _angle_y, _angle_z;
long ax_p, ay_p, az_p;

// proměnné, které senzor vypisuje v klidovém stavu
int alarm_x = 0;
int alarm_y = 0;
int alarm_z = 90;
// tolerance pro spuštění alarmu
int tolerance = 5;
 
void setup()
{
  Wire.begin();
  Serial.begin(9600);
  
  Serial.println("Spousteni zarizeni MPU6050");
  accelgyro.initialize();
  
  Serial.println("Testovani zarizeni");
  Serial.println(accelgyro.testConnection() ? "Zarizeni funguje spravne" : "Zarizeni se nepodarilo pripojit");
}
 
void loop()
{
  accelgyro.getAcceleration(&ax, &ay, &az);
  
  ax_p = ax_p + ax;
  ay_p = ay_p + ay;
  az_p = az_p + az;

  counter++;
  
  if (counter == counter_w)
  {
    //zjistíme průmerné hodnoty
    x = ax_p/counter;
    y = ay_p/counter;
    z = az_p/counter;
     
    angle_x = atan2(x, sqrt(square(y) + square(z)))/(pi/180);
    angle_y = atan2(y, sqrt(square(x) + square(z)))/(pi/180);
    angle_z = atan2(z, sqrt(square(x) + square(y)))/(pi/180);
       
    counter = 0;
    ax_p = 0;
    ay_p = 0;
    az_p = 0;

    if (angle_x > alarm_x + tolerance || angle_x < alarm_x - tolerance)
    {
      Serial.println("Alarm spusten");
    }
    else if (angle_y > alarm_y + tolerance || angle_y < alarm_y - tolerance)
    {
      Serial.println("Alarm spusten");
    }
    else if (angle_z > alarm_z + tolerance || angle_z < alarm_z - tolerance)
    {
      Serial.println("Alarm spusten");
    }

  }
}

 

Slovo na závěr

Ukázali jsme si absolutní základ práce s GY-521, ale je toho mnohem více k prozkoumání. Nezapomeňte na jeho přesnost, pouhé špatné uchycení v breadboadru dělá chybu!

Bastlení ZDAR!

Soubory ke stažení pro bastlení s GY-521