Arduino İle MPU6050 İvme ve Gyro Sensörü Kullanımı

Bu yazımızda MPU6050 sensörünü öğreneceğiz. İvmeölçer ve jiroskopun açı ve hareket değerlerini hesaplar. Bununla birlikte geniş uygulama yelpazesini de göreceğiz.

MPU6050 Nedir?

MPU6050, Atalet Ölçüm Birimi anlamına gelen bir IMU cihazıdır. Üç eksenli ivmeölçer ve üç eksenli jiroskop verilerini hesaplayan altı eksenli hareket takip cihazıdır. Bu kartın en büyük avantajı dijital hareket işlemcisi ile geliyor. DMP’nin (Dijital hareket işlemcisi) önemi, kendi tarafında çok karmaşık hesaplamalar/işlemler yapması ve böylece mikrodenetleyiciyi yormamasıdır. Yuvarlanma, eğim, sapma, açılar, manzara ve portre hissi vb. gibi hareket verileri sağlar.

Her kanal için 16 bit atandığı için analog verileri dijital veri bitlerine dönüştürürken çok hassastır. Dijital Hareket İşlemcisi veya DMP (Dijital Matris İşlemcisi), İvmeölçer, Jiroskop ve harici bir Manyetometreden veri alıp işleyerek ana işlemcinin hesaplama yükünü azaltabilen yerleşik bir işlemcidir.

MPU6050 Sensörü
MPU6050 Sensörü

MPU6050 Özellikleri

  • 3 eksenli jiroskop
  • 3 eksenli ivmeölçer
  • Her kanal için 16 bit ADC dönüştürme
  • 1024 bit FIFO arabelleği
  • Dijital çıkış sıcaklık sensörü
  • Entegre dijital hareket işlemcisi
  • Dahili sıcaklık sensörü

MPU6050 Pin Diyagramı

MPU6050 Pİnleri
  • VCC: Bu pin güç sağlamak için kullanılır (5v /3.3v)
  • GND: GND(Toprak) pinine bağlamak içindir.
  • SDA: Bu pin sensörden seri olarak veri almak için kullanılır.
  • SCL: Bu pin seri saat girişi için kullanılır.
  • XDA: Bu, harici bir sensörden yapılandırma ve okuma için bir SDA olarak kullanılır (Opsiyonel).
  • XCL: Bu, harici sensörden yapılandırma ve okuma için bir SCL olarak kullanılır (Opsiyonel).
  • AD0: Bu, I2c bağımlı(slave) adresi Bus, (anlamlı bit).
  • INT: Bu, verilerin hazır olduğunu gösteren bir Kesinti pinidir.

İvmeölçer Nasıl Çalışır?

Bir ivmeölçer, piezoelektrik etki ilkesine göre çalışır. İçinde bir top bulunan küboidal bir kutu düşünün. Kutunun içindeki kutu topunu hareket ettirir veya eğersek, yerçekimi nedeniyle kutunun duvarlarına düşecektir. Benzer şekilde, MPU6050 gibi IMU da tam olarak içinde bir top bulunan kübik kutu gibi çalışan bu tür MEMS’leri (mikro-elektromekanik sistemler) içerir.

Cihaz/kutu eğildiğinde, kutunun içindeki bir top piezoelektrik duvarların üzerine düşer. Ayrıca, analog veriler o duvarın kanalından yakalanır ve dijital verilere ilerler. Genellikle bir ivmeölçer böyle çalışır ve çıktısı çok hassastır çünkü her kanal için 16-bit ADC bulunur.

Jiroskop Nasıl Çalışır?

Coriolis ivmesi prensibi ile çalışır. Son derece sabit bir ileri geri hareket eden çatal benzeri bir yapı olduğunu hayal edin. Bu düzenlemeyi ne zaman eğmeye çalışırsanız, kristaller eğim yönünde bir kuvvete maruz kalır. Genellikle hareketli çatalın ataletinin bir sonucu olarak ortaya çıkar. Böylece kristaller, piezo etkisi ile fikir birliği içinde bir akım üretir ve akım yükseltilir.

Arduino İle MPU6050 Sensörü Bağlantı Şeması

MPU6050 bir I2C iletişim cihazı olduğu için Arduino ile bağlantılar oldukça basittir. Aşağıdaki devre şeması size Arduino ile bağlantıların nasıl yapıldığını göstermektedir.

Arduino İle MPU6050 Sensörü Bağlantı Şeması
Arduino İle MPU6050 Sensörü Bağlantı Şeması

MPU6050’nin Arduino ile bağlantıları aşağıdaki gibidir:

ArduinoMPU6050
5v/3vVCC
GNDGND
A5/ SCL pinSCL
A4/SDA pinSDA
pin 2INT
Arduino İle MPU6050 Bağlantı Pinleri

MPU6050 Sensör Programlanması

MPU6050’den veri elde etmek için wire.h kitaplığını kurmanız gerekecektir.

Her iki kütüphaneyi de aşağıdaki bağlantıdan indirebilirsiniz:

Bu koddan Roll, Pitch, Yaw adlı üç temel parametre elde edeceğiz. Temel olarak, bu üç şey ne anlama geliyor? Bir arabanın içinden geçerken ileri, geri, sol ve sağ hareketini ölçebilirsiniz. Ancak dronlar veya uçan araçlar söz konusu olduğunda aynı senaryo düşünülmeyecek. Uçan kontrol panoları, sapma, eğim ve Yuvarlanma gibi farklı terminolojilere sahiptir.

  • Uçağın önünden arkasına uzanan eksene yuvarlanma(roll) ekseni denir. Bu eksen etrafındaki dönüşe yuvarlanma hareketi denir.
  • Uçağın solundan sağa doğru uzanan eksene eğim(pitch) ekseni denir. Bu eksen etrafındaki dönüşe adım hareketi denir.
  • Uçağın yukarıdan aşağıya doğru uzanan eksenine yalpalama(yaw) ekseni denir. Bu eksen etrafındaki dönüşe yalpalama hareketi denir.

Kısaca şunu söyleyebiliriz.

  • Önden arkaya eksen etrafında dönmeye yuvarlanma(roll) denir.
  • Yan yana eksen etrafında dönmeye adım(pitch) denir.
  • Dikey eksen etrafında dönmeye yalpalama(yaw) denir.

Olayları açıklamak için, daha iyi anlamanız için aşağıdaki resime bakalım.

Hareket Eksenleri
#include <Wire.h>
const int MPU = 0x68; // MPU6050 I2C address
float AccX, AccY, AccZ;
float GyroX, GyroY, GyroZ;
float accAngleX, accAngleY, gyroAngleX, gyroAngleY, gyroAngleZ;
float roll, pitch, yaw;
float AccErrorX, AccErrorY, GyroErrorX, GyroErrorY, GyroErrorZ;
float elapsedTime, currentTime, previousTime;
int c = 0;
void setup() {
  Serial.begin(19200);
  Wire.begin();                      // Initialize comunication
  Wire.beginTransmission(MPU);       // Start communication with MPU6050 // MPU=0x68
  Wire.write(0x6B);                  // Talk to the register 6B
  Wire.write(0x00);                  // Make reset - place a 0 into the 6B register
  Wire.endTransmission(true);        //end the transmission

/*
  
  // Configure Accelerometer Sensitivity - Full Scale Range (default +/- 2g)
  Wire.beginTransmission(MPU);
  Wire.write(0x1C);                  //Talk to the ACCEL_CONFIG register (1C hex)
  Wire.write(0x10);                  //Set the register bits as 00010000 (+/- 8g full scale range)
  Wire.endTransmission(true);
  // Configure Gyro Sensitivity - Full Scale Range (default +/- 250deg/s)
  Wire.beginTransmission(MPU);
  Wire.write(0x1B);                   // Talk to the GYRO_CONFIG register (1B hex)
  Wire.write(0x10);                   // Set the register bits as 00010000 (1000deg/s full scale)
  Wire.endTransmission(true);
  delay(20);


  */
  // Call this function if you need to get the IMU error values for your module
  calculate_IMU_error();
  delay(20);
}
void loop() {
  // === Read acceleromter data === //
  Wire.beginTransmission(MPU);
  Wire.write(0x3B); // Start with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU, 6, true); // Read 6 registers total, each axis value is stored in 2 registers
  //For a range of +-2g, we need to divide the raw values by 16384, according to the datasheet
  AccX = (Wire.read() << 8 | Wire.read()) / 16384.0; // X-axis value
  AccY = (Wire.read() << 8 | Wire.read()) / 16384.0; // Y-axis value
  AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0; // Z-axis value
  // Calculating Roll and Pitch from the accelerometer data
  accAngleX = (atan(AccY / sqrt(pow(AccX, 2) + pow(AccZ, 2))) * 180 / PI) - 0.58; // AccErrorX ~(0.58) See the calculate_IMU_error()custom function for more details
  accAngleY = (atan(-1 * AccX / sqrt(pow(AccY, 2) + pow(AccZ, 2))) * 180 / PI) + 1.58; // AccErrorY ~(-1.58)
  // === Read gyroscope data === //
  previousTime = currentTime;        // Previous time is stored before the actual time read
  currentTime = millis();            // Current time actual time read
  elapsedTime = (currentTime - previousTime) / 1000; // Divide by 1000 to get seconds
  Wire.beginTransmission(MPU);
  Wire.write(0x43); // Gyro data first register address 0x43
  Wire.endTransmission(false);
  Wire.requestFrom(MPU, 6, true); // Read 4 registers total, each axis value is stored in 2 registers
  GyroX = (Wire.read() << 8 | Wire.read()) / 131.0; // For a 250deg/s range we have to divide first the raw value by 131.0, according to the datasheet
  GyroY = (Wire.read() << 8 | Wire.read()) / 131.0;
  GyroZ = (Wire.read() << 8 | Wire.read()) / 131.0;
  // Correct the outputs with the calculated error values
  GyroX = GyroX + 0.56; // GyroErrorX ~(-0.56)
  GyroY = GyroY - 2; // GyroErrorY ~(2)
  GyroZ = GyroZ + 0.79; // GyroErrorZ ~ (-0.8)
  // Currently the raw values are in degrees per seconds, deg/s, so we need to multiply by sendonds (s) to get the angle in degrees
  gyroAngleX = gyroAngleX + GyroX * elapsedTime; // deg/s * s = deg
  gyroAngleY = gyroAngleY + GyroY * elapsedTime;
  yaw =  yaw + GyroZ * elapsedTime;
  // Complementary filter - combine acceleromter and gyro angle values
  roll = 0.96 * gyroAngleX + 0.04 * accAngleX;
  pitch = 0.96 * gyroAngleY + 0.04 * accAngleY;
  
  // Print the values on the serial monitor
  Serial.print(roll);
  Serial.print("/");
  Serial.print(pitch);
  Serial.print("/");
  Serial.println(yaw);
}
void calculate_IMU_error() {
  // We can call this funtion in the setup section to calculate the accelerometer and gyro data error. From here we will get the error values used in the above equations printed on the Serial Monitor.
  // Note that we should place the IMU flat in order to get the proper values, so that we then can the correct values
  // Read accelerometer values 200 times
  while (c < 200) {
    Wire.beginTransmission(MPU);
    Wire.write(0x3B);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU, 6, true);
    AccX = (Wire.read() << 8 | Wire.read()) / 16384.0 ;
    AccY = (Wire.read() << 8 | Wire.read()) / 16384.0 ;
    AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0 ;
    // Sum all readings
    AccErrorX = AccErrorX + ((atan((AccY) / sqrt(pow((AccX), 2) + pow((AccZ), 2))) * 180 / PI));
    AccErrorY = AccErrorY + ((atan(-1 * (AccX) / sqrt(pow((AccY), 2) + pow((AccZ), 2))) * 180 / PI));
    c++;
  }
  //Divide the sum by 200 to get the error value
  AccErrorX = AccErrorX / 200;
  AccErrorY = AccErrorY / 200;
  c = 0;
  // Read gyro values 200 times
  while (c < 200) {
    Wire.beginTransmission(MPU);
    Wire.write(0x43);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU, 6, true);
    GyroX = Wire.read() << 8 | Wire.read();
    GyroY = Wire.read() << 8 | Wire.read();
    GyroZ = Wire.read() << 8 | Wire.read();
    // Sum all readings
    GyroErrorX = GyroErrorX + (GyroX / 131.0);
    GyroErrorY = GyroErrorY + (GyroY / 131.0);
    GyroErrorZ = GyroErrorZ + (GyroZ / 131.0);
    c++;
  }
  //Divide the sum by 200 to get the error value
  GyroErrorX = GyroErrorX / 200;
  GyroErrorY = GyroErrorY / 200;
  GyroErrorZ = GyroErrorZ / 200;
  // Print the error values on the Serial Monitor
  Serial.print("AccErrorX: ");
  Serial.println(AccErrorX);
  Serial.print("AccErrorY: ");
  Serial.println(AccErrorY);
  Serial.print("GyroErrorX: ");
  Serial.println(GyroErrorX);
  Serial.print("GyroErrorY: ");
  Serial.println(GyroErrorY);
  Serial.print("GyroErrorZ: ");
  Serial.println(GyroErrorZ);
}
Seri Monitör Çıktısı

Yukarıdaki koddan, Data Roll/pitch/Yaw’ı başarıyla aldık.

Yuvarlanma, eğim, sapma, MPU6050’nin jiroskopik açıları ile elde edilen manipüle edilmiş verilerdir. Temel ivmeölçer ve jiroskopik değerleri hesaplamak istiyorsanız bunları bazı adımlarda alabilirsiniz. Bunun için önce MPU6050_tockn.h kütüphanesini kurmanız gerekiyor.

Bu kütüphaneyi indirdikten sonra aşağıdaki yol ile kütüphaneyi kurunuz.

Kütüphane Ekleme

Arduino IDE’ye MPU-6050 kütüphaneyi eklendikten sonra, aralarından seçim yapabileceğiniz bir örnek listemiz var:

  • GetAllData
  • GetAngle
MPU6050 Kütüphanesi Örnek Kod Seçimi

GetAllData kodunu açın.

#include <MPU6050_tockn.h>
#include <Wire.h>

MPU6050 mpu6050(Wire);

long timer = 0;

void setup() {
  Serial.begin(9600);
  Wire.begin();
  mpu6050.begin();
  mpu6050.calcGyroOffsets(true);
}

void loop() {
  mpu6050.update();

  if(millis() - timer > 1000){
    
    Serial.println("=======================================================");
    Serial.print("temp : ");Serial.println(mpu6050.getTemp());
    Serial.print("accX : ");Serial.print(mpu6050.getAccX());
    Serial.print("\taccY : ");Serial.print(mpu6050.getAccY());
    Serial.print("\taccZ : ");Serial.println(mpu6050.getAccZ());
  
    Serial.print("gyroX : ");Serial.print(mpu6050.getGyroX());
    Serial.print("\tgyroY : ");Serial.print(mpu6050.getGyroY());
    Serial.print("\tgyroZ : ");Serial.println(mpu6050.getGyroZ());
  
    Serial.print("accAngleX : ");Serial.print(mpu6050.getAccAngleX());
    Serial.print("\taccAngleY : ");Serial.println(mpu6050.getAccAngleY());
  
    Serial.print("gyroAngleX : ");Serial.print(mpu6050.getGyroAngleX());
    Serial.print("\tgyroAngleY : ");Serial.print(mpu6050.getGyroAngleY());
    Serial.print("\tgyroAngleZ : ");Serial.println(mpu6050.getGyroAngleZ());
    
    Serial.print("angleX : ");Serial.print(mpu6050.getAngleX());
    Serial.print("\tangleY : ");Serial.print(mpu6050.getAngleY());
    Serial.print("\tangleZ : ");Serial.println(mpu6050.getAngleZ());
    Serial.println("=======================================================\n");
    timer = millis();
    
  }

}

Kodu yükledikten sonra aşağıdaki çıktıyı alacaksınız:

Kod Çıktısı

MPU6050 Sensörünün Kullanıldığı Alanlar

  • 3D uzaktan kumanda
  • 3D fare denetleyicisinde
  • Giyilebilir sağlık cihazları, fitness izleme cihazlarında
  • Drone ve quadcopter’larda konum kontrolü için MPU6050 kullanılır.
  • Robotik Kolun kontrolünde kullanılır
  • El hareketi kontrol cihazları
  • Kendi kendini dengeleyen robotta
  • Eğme, döndürme ve dengeleme için İnsansı robotta
  • Çerçeveyi ayarlamak için akıllı telefonlarda
  • Drone’larda stabilizasyon için gimbal sisteminde kullanılır