Tento modul obsahuje integrovaný obvod s funkcí zastupující dvě zařízení, gyroskop a akcelerometr. Gyroskop je zařízení, které se používá hlavně v navigaci a obsahuje setrvačník, který zachovává polohu osy své rotace. Můžeme tedy díky němu poznat, jaká je poloha celého modulu vůči ploše Země. Akcelerometr je pak zařízení, které měří gravitační zrychlení a můžeme s ním tedy měřit náklon či vibrace modulu.
Námi vybraný modul gyroskopu a akcelerometru pak ještě obsahuje DMP (Digital Motion Processor), který nám velice zjednoduší práci s daty, protože v reálném čase sbírá data ze zmíněných dvou zařízení a poskytuje nám přímo tři důležité hodnoty, které udávají rotace kolem jednotlivých os. V angličtině se nazývají yaw (Z osa), pitch (Y osa) a roll (X osa). Modul má v sobě také integrovaný teploměr, ten je však velmi nepřesný a proto se nevyužívá.
Tento modul s gyroskopem a akcelerometrem má celkem 8 propojovacích pinů, nám však bude stačit zapojit pouze 5. Propojíme tedy VCC na napájecí napětí +5V, GND na zem, SCL na A5, SDA na A4 a INT na D2. Piny SCL a SDA jsou připojeny na I2C sběrnici a pin INT slouží pro detekci přerušení od DMP.
První ukázkový kód pro zapojení a vyzkoušení gyroskopu a akcelerometru obsahuje jednoduchou komunikaci přes knihovnu Wire, která je již od instalace přítomna v Arduino IDE. Na začátku programu tedy vytvoříme potřebné proměnné a v podprogramu setup nastavíme nejprve modul přes I2C sběrnici a také komunikaci po sériové lince. V nekonečné smyčce loop pak vždy aktivujeme I2C sběrnici, na ní pošleme žádost o data od modulu a poté vyčteme data ze všech tří os akcelerometru a gyroskopu. Tato naměřená data se poté vytisknou po sériové lince včetně informace o teplotě.
// Arduino gyroskop a akcelerometr 1
// připojení knihovny Wire
#include <Wire.h>
// inicializace proměnné pro určení adresy senzoru
// 0x68 nebo 0x69, dle připojení AD0
const int MPU_addr=0x68;
// inicializace proměnných, do kterých se uloží data
int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;
void setup()
{
// komunikace přes I2C sběrnici
Wire.begin();
Wire.beginTransmission(MPU_addr);
Wire.write(0x6B);
Wire.write(0);
Wire.endTransmission(true);
// komunikace přes sériovou linku rychlostí 115200 baud
Serial.begin(115200);
}
void loop()
{
// zapnutí přenosu
Wire.beginTransmission(MPU_addr);
// zápis do registru ACCEL_XOUT_H
Wire.write(0x3B);
Wire.endTransmission(false);
// vyzvednutí dat z 14 registrů
Wire.requestFrom(MPU_addr,14,true);
AcX=Wire.read()<<8|Wire.read();
AcY=Wire.read()<<8|Wire.read();
AcZ=Wire.read()<<8|Wire.read();
Tmp=Wire.read()<<8|Wire.read();
GyX=Wire.read()<<8|Wire.read();
GyY=Wire.read()<<8|Wire.read();
GyZ=Wire.read()<<8|Wire.read();
// výpis surových dat z proměnných na sériovou linku
Serial.print("AcX = "); Serial.print(AcX);
Serial.print(" | AcY = "); Serial.print(AcY);
Serial.print(" | AcZ = "); Serial.print(AcZ);
// přepočtení teploty dle datasheetu
Serial.print(" | Temp = "); Serial.print(Tmp/340.00+36.53);
Serial.print(" | GyX = "); Serial.print(GyX);
Serial.print(" | GyY = "); Serial.print(GyY);
Serial.print(" | GyZ = "); Serial.println(GyZ);
delay(500);
}
Data, která dostaneme s prvním ukázkovým kódem, však nejsou moc čitelná a slouží hlavně pro první otestování modulu. Pro získání lepších dat je pak nutné využít knihovny MPU-6050, která je ke stažení zde a knihovny I2Cdev, která je ke stažení zde. Po stažení a rozbalení balíčků s knihovnami zkopírujeme obě složky do naší složky libraries v místě, kde si ukládáme veškeré programy (standardně v Dokumentech). Po novém spuštění Arduino IDE uvidíme mezi příklady knihovnu MPU-6050. Druhý ukázkový kód je založen právě na příkladu od zmíněné knihovny a jeho výstupem jsou již data o rotacích jednotlivých os získáné z DMP čipu.
V druhém ukázkovém programu jsou tedy opět nejprve připojeny všechny důležité knihovny a poté vytvořeny všechny potřebné proměnné. Následně je vytvořen podprogram dmpINT, který obsahuje nastavení informací o detekci přerušení. Poté následuje podprogram setup s nastavením všech potřebných pinů a sběrnic, včetně sériové linky a také kontroly připojeného DSP. V nekonečné smyčce loop pak vždy detekujeme přerušení od DMP čipu a v případě jeho nečinnosti můžeme provádět libovolné operace uvnitř while smyčky (označeno komentářem). Při zachycení přerušení vyčteme informace o rotacích kolem všech os a tyto informace následně vytiskneme do sériové linky.
Níže si můžete prohlédnout nejprve zdrojový kód, poté obrázek objasňující zmíněné rotace kolem os a nakonec ukázkový výpis z tohoto ukázkového programu.
// Arduino gyroskop a akcelerometr 2
// knihovny potřebné pro modul
#include "Wire.h"
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
// nastavení adresy modulu
// 0x68 nebo 0x69, dle připojení AD0
// MPU6050 mpu(0x69)
MPU6050 mpu;
// číslo pinu s LED diodou pro notifikaci
#define LED_PIN 13
// inicializace proměnných, do kterých se uloží data
bool dmpReady = false;
uint8_t mpuIntStatus;
uint8_t devStatus;
uint16_t packetSize;
uint16_t fifoCount;
uint8_t fifoBuffer[64];
// inicializace proměnných pro výpočet
Quaternion q; // [w, x, y, z] kvaternion
VectorFloat gravity; // [x, y, z] vektor setrvačnosti
float rotace[3]; // rotace kolem os x,y,z
// Rutina přerušení
volatile bool mpuInterrupt = false;
void dmpINT() {
mpuInterrupt = true;
}
void setup() {
// nastavení LED jako výstupní
pinMode(LED_PIN, OUTPUT);
// nastavení I2C sběrnice
Wire.begin();
// komunikace přes sériovou linku rychlostí 115200 baud
Serial.begin(115200);
while (!Serial);
// inicializace akcelerometru a gyroskopu
Serial.println(F("Inicializace I2C zarizeni.."));
mpu.initialize();
Serial.println(F("Test pripojenych zarizeni.."));
Serial.println(mpu.testConnection() ? F("Modul pripojeni") : F("Pripojeni modulu selhalo"));
// incializace DMP
Serial.println(F("Inicializace DMP..."));
devStatus = mpu.dmpInitialize();
// kontrola funkčnosti DMP
if (devStatus == 0) {
// zapnutí DMP
Serial.println(F("Povoleni DMP..."));
mpu.setDMPEnabled(true);
// nastavení pinu INT jako přerušovacího, interrupt 0 odpovídá pinu 2
attachInterrupt(0, dmpINT, RISING);
mpuIntStatus = mpu.getIntStatus();
Serial.println(F("DMP pripraveno, cekam na prvni preruseni.."));
dmpReady = true;
// načtení velikosti zpráv, které bude DMP posílat
packetSize = mpu.dmpGetFIFOPacketSize();
}
else {
// V případě chyby:
// 1 : selhání připojení k DMP
// 2 : selhání při nastavení DMP
Serial.print(F("DMP inicializace selhala (kod "));
Serial.print(devStatus);
Serial.println(F(")"));
}
digitalWrite(LED_PIN, LOW);
}
void loop() {
// dokud nepošle DMP přerušení, můžeme provádět ostatní příkazy
// ve smyčce while níže
if (!dmpReady) return;
// tato podmínka čeká na příjem přerušení a můžeme v ní provádět
// ostatní operace
while (!mpuInterrupt & fifoCount < packetSize) {
// místo pro ostatní operace
// ..
}
// získání informace o statusu DSP
mpuInterrupt = false;
mpuIntStatus = mpu.getIntStatus();
// získání velikosti zásobníku dat
fifoCount = mpu.getFIFOCount();
// kontrola přetečení zásobníku dat
if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
mpu.resetFIFO();
Serial.println(F("Preteceni zasobniku dat!"));
// v případě přetečení zásobníku je nutné
// častěji vyčítat data
}
else if (mpuIntStatus & 0x02) {
// kontrola délky dat
while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
// čtení paketu ze zásobníku
mpu.getFIFOBytes(fifoBuffer, packetSize);
// při větším množství paketů snížíme počítadlo
fifoCount -= packetSize;
// přečtení dat z DSP a uložení do proměnných
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(rotace, &q, &gravity);
// výpis informací o rotacích kolem jednotlivých os
Serial.print("Rotace t X ");
Serial.print(rotace[2] * 180/M_PI);
Serial.print("st t Y ");
Serial.print(rotace[1] * 180/M_PI);
Serial.print("st t Z ");
Serial.print(rotace[0] * 180/M_PI);
Serial.println("st");
}
}
Obrázek s názorným příkladem rotací kolem os x, y a z včetně anglických názvů.
Ukázkový výpis ze Sériového monitoru:
Inicializace I2C zarizeni..
Test pripojenych zarizeni..
Modul pripojeni
Inicializace DMP...
Povoleni DMP...
DMP pripraveno, cekam na prvni preruseni..
Rotace X -2.15st Y -2.90st Z -0.03st
Rotace X -2.06st Y -2.90st Z -0.03st
..
Tento modul obsahující gyroskop, akcelerometr a DMP čip se využívá často u kvadrokoptér, helikoptér a podobných zařízení, kdy potřebujeme kontrolovat právě rotace samotných zařízení či různé vibrace vyskytující se v okolí. Rád bych upozornil na to, že po každém nahrání programu či zapnutí zařízení s tímto senzorem je nutné vyčkat okolo 15 až 20 sekund kvůli kalibraci DMP čipu, sami uvidíte, že v prvních sekundách jsou výstupní hodnoty velice nestálé.
Poznámka: na rozdíl od většiny článků uvedených na tomto webu byla použita rychlost sériové linky větší než 9600 a to konkrétně 115200 baud. Tato změna byla nutná kvůli rychlejšímu vypisování informací ze zásobníku dat a je tedy nutné v Sériovém monitoru také změnit rychlost v pravém spodním rohu, jinak budete dostávat falešné znaky.
Seznam použitých komponent:
http://dratek.cz/arduino-vstupni-periferie/830-arduino-gyroskop-akcelerometr.html
http://dratek.cz/arduino/974-arduino-uno-r3-atmega328p-1424115860.html
https://dratek.cz/arduino/1424-nepajive-kontaktni-pole-zy-170-w.html
http://dratek.cz/arduino-kabelaz-propoje-rozsireni/1063-arduino-vodice-samec-samec-40-kusu.html