Parçalar · 7 dk okuma

MPU6050 Arduino: İvmeölçer, Jiroskop ve Eğim Açısı Hesaplama

MPU6050 Arduino bağlantısı, I2C adresi, ham değerler, kalibrasyon, atan2 ile eğim açısı ve tamamlayıcı filtre; Adafruit kütüphanesi, ESP32 ve Pico örnekleri.

MPU6050, tek bir küçük yongada 3 eksenli ivmeölçer ile 3 eksenli jiroskopu birleştiren ve Arduino projelerinde en çok kullanılan hareket sensörüdür. Kartın ne kadar eğildiğini, hangi yöne ne hızla döndüğünü, sarsılıp sarsılmadığını ya da düşüp düşmediğini ölçer. Kendi kendini dengeleyen robotlar, drone'lar, kamera sabitleyiciler (gimbal), adım sayarlar ve hareketle kontrol edilen oyunlar bu sensörle yapılır. MPU6050, Arduino'ya yalnızca dört kabloyla, I2C üzerinden bağlanır.

Bu yazıda MPU6050'nin nasıl çalıştığını, eksenleri ve ham değerleri, I2C bağlantısını, kütüphaneyle ve kütüphanesiz okumayı, kalibrasyonu, atan2 ile eğim açısı hesabını ve iki sensörün güçlü yanlarını birleştiren tamamlayıcı filtreyi adım adım öğreneceksin. Ardından ESP32 ile düşmeyi algılayan bir alarm kuracak ve Raspberry Pi Pico için MicroPython kodu yazacağız.

MPU6050 GY-521 ivmeölçer ve jiroskop modülü
GY-521 kartındaki MPU6050: VCC, GND, SCL, SDA, XDA, XCL, AD0 ve INT pinleri; X ve Y eksenlerinin yönü kartın üzerine çizilidir.

MPU6050 nedir, nasıl çalışır?

MPU6050, InvenSense'in (bugün TDK) ürettiği bir IMU, yani ataletsel ölçüm birimidir. İçinde silikondan yapılmış minik mekanik yapılar (MEMS) bulunur. İvmeölçer, yaylarla asılı küçük bir kütlenin ivme altında ne kadar yer değiştirdiğini ölçer; durağan hâldeyken bile yerçekimini algıladığı için masada düz duran sensör Z ekseninde yaklaşık 1 g (9,81 m/s²) gösterir ve bu sayede sensörün yere göre eğimini bulabilirsin. Jiroskop ise titreşen yapılara etki eden Coriolis kuvvetinden açısal hızı, yani sensörün saniyede kaç derece döndüğünü ölçer. Ölçümler yonganın içindeki 16 bitlik ADC'lerle sayıya çevrilir ve I2C üzerinden okunur. Yonga ayrıca bir sıcaklık sensörü ve hareket hesaplarını üstlenebilen bir dijital hareket işlemcisi (DMP) barındırır.

ÖzellikDeğer
Sensörler3 eksen ivmeölçer + 3 eksen jiroskop + sıcaklık
İvmeölçer aralığı±2, ±4, ±8, ±16 g
Jiroskop aralığı±250, ±500, ±1000, ±2000 °/s
Çözünürlük16 bit (her eksen için -32768 ile 32767 arası)
HaberleşmeI2C, 400 kHz'e kadar
I2C adresi0x68 (AD0 GND'de) ya da 0x69 (AD0 3,3 V'ta)
Yonga gerilimi2,375–3,46 V (GY-521 kartı 3,3–5 V ile beslenir)
AkımYaklaşık 3,9 mA (uykuda 5 µA)
Ek özelliklerDMP, 1024 baytlık FIFO, hareket kesmesi, harici sensör için yardımcı I2C

Eksenler, ham değerler ve hassasiyet

Kartın üzerindeki oklar X ve Y eksenlerini gösterir; Z ekseni kartın yüzeyine diktir ve yukarı bakar. Sensör her eksen için işaretli 16 bitlik bir sayı verir. Bu ham sayıyı fiziksel birime çevirmek için seçtiğin ölçüm aralığına karşılık gelen hassasiyete bölersin. Örneğin varsayılan ±2 g aralığında 16384 ham değer 1 g demektir; masada duran sensörden az ≈ 16384, ax ve ay ≈ 0 okursun. Jiroskopta ±250 °/s aralığında 131 ham değer, saniyede 1 derecelik dönüşe karşılık gelir. Geniş aralık daha sert hareketleri ölçer ama küçük değişimleri daha kaba gösterir; bu yüzden projene yetecek en dar aralığı seç.

Ayar değeriİvmeölçer aralığıLSB/gJiroskop aralığıLSB/(°/s)
0±2 g16384±250 °/s131
1±4 g8192±500 °/s65,5
2±8 g4096±1000 °/s32,8
3±16 g2048±2000 °/s16,4

Yonga sıcaklığı da ölçer: °C = ham değer / 340 + 36,53. Bu değer ortam sıcaklığından çok yonganın kendi sıcaklığını gösterir; ama jiroskobun sıfır noktası sıcaklıkla değiştiği için ileri seviye düzeltmelerde işe yarar.

MPU6050 bağlantısı: Arduino Uno, ESP32 ve Pico

MPU6050 piniArduino UnoESP32Raspberry Pi Pico
VCC5V3V33V3(OUT)
GNDGNDGNDGND
SCLA5GPIO 22GP5
SDAA4GPIO 21GP4
AD0Boş (adres 0x68)Boş (adres 0x68)Boş (adres 0x68)
INTD2 (isteğe bağlı)Herhangi bir GPIO (isteğe bağlı)Herhangi bir GP pini (isteğe bağlı)
XDA, XCLBağlanmazBağlanmazBağlanmaz

GY-521 kartında 3,3 V regülatörü bulunduğu için VCC'yi Uno'nun 5V pinine bağlayabilirsin. AD0 pini kartta 4,7 kΩ'luk bir dirençle GND'ye çekildiği için boş bırakıldığında adres 0x68 olur; aynı hatta iki MPU6050 kullanmak istersen birinin AD0 pinini 3,3 V'a bağlayıp adresini 0x69 yaparsın. INT pini, yeni veri hazır olduğunda ya da hareket algılandığında sinyal verir; basit projelerde bağlamana gerek yoktur. Bağlantıdan sonra sensörün görünüp görünmediğini bir I2C tarayıcı koduyla kontrol etmek iyi bir alışkanlıktır; nasıl yapıldığını I2C LCD Ekran yazısında bulabilirsin.

SDA ve SCL'yi XDA ve XCL ile karıştırma. XDA ve XCL, MPU6050'nin kendisine harici bir pusula sensörü bağlamak için kullandığı yardımcı I2C hattıdır; Arduino'yu oraya bağlarsan sensör hiç bulunamaz. Ayrıca bazı çıplak MPU6050 kartlarında regülatör yoktur ve bunlar yalnızca 3,3 V ile beslenmelidir; kartının üzerinde küçük regülatör yongasını göremiyorsan 5 V verme.

Kütüphaneyle hızlı başlangıç: Adafruit MPU6050

  1. Arduino IDE'de Kütüphane Yöneticisi'ni aç ve Adafruit MPU6050 ara.
  2. Kurarken bağımlılıkları sorduğunda Install all seç; böylece Adafruit Unified Sensor ve Adafruit BusIO da kurulur.
  3. Sensörü tablodaki gibi bağla, aşağıdaki kodu yükle ve Seri Monitör'ü 115200 baud'da aç.
  4. Araçlar menüsünden Seri Çizici'yi (Serial Plotter) açarak altı ekseni canlı grafik olarak izle; kartı eğdikçe ivme, döndürdükçe jiroskop eğrileri değişir.
Arduino (C++)
1#include <Wire.h>
2#include <Adafruit_MPU6050.h>
3#include <Adafruit_Sensor.h>
4
5Adafruit_MPU6050 mpu;
6
7void setup() {
8  Serial.begin(115200);
9  if (!mpu.begin()) {                             // varsayılan adres 0x68 / default address 0x68
10    Serial.println("MPU6050 bulunamadi / not found");
11    while (true) delay(10);
12  }
13  mpu.setAccelerometerRange(MPU6050_RANGE_4_G);   // ±4 g
14  mpu.setGyroRange(MPU6050_RANGE_500_DEG);        // ±500 °/s
15  mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);     // titreşimi süz / filter out vibration
16}
17
18void loop() {
19  sensors_event_t a, g, t;
20  mpu.getEvent(&a, &g, &t);
21  Serial.print("ax:");  Serial.print(a.acceleration.x);   // m/s²
22  Serial.print(" ay:"); Serial.print(a.acceleration.y);
23  Serial.print(" az:"); Serial.print(a.acceleration.z);
24  Serial.print(" gx:"); Serial.print(g.gyro.x);           // rad/s
25  Serial.print(" gy:"); Serial.print(g.gyro.y);
26  Serial.print(" gz:"); Serial.print(g.gyro.z);
27  Serial.print(" T:");  Serial.println(t.temperature);    // °C
28  delay(100);
29}

Adafruit kütüphanesi sonuçları doğrudan fiziksel birimlerle verir: ivme m/s², açısal hız rad/s, sıcaklık °C. Jiroskop değerini derece/saniyeye çevirmek için 57,3 ile çarpman yeterlidir. setFilterBandwidth ile seçilen dahili alçak geçiren filtre titreşim gürültüsünü azaltır: 21 Hz el hareketleri için iyi bir başlangıçtır, kısa darbeleri yakalamak istiyorsan 94 ya da 260 Hz seç. Kütüphane açılışta yonganın kimlik register'ını (WHO_AM_I) okur ve 0x68 değilse begin() false döndürür.

Kütüphanesiz okuma, kalibrasyon ve eğim açısı

Kütüphaneler işi kolaylaştırır, ama sensörün içini anlamak için register'ları doğrudan okumak çok öğreticidir. MPU6050 açıldığında uyku modundadır; önce 0x6B (PWR_MGMT_1) register'ına 0 yazarak uyandırman gerekir. Ardından 0x3B adresinden başlayarak 14 bayt okursun: 6 bayt ivme, 2 bayt sıcaklık ve 6 bayt jiroskop. Her değer, önce yüksek bayt gelmek üzere iki bayttır. Kodda kullandığımız ve bilmen gereken başlıca register'lar şunlar:

RegisterAdresGörevi
SMPLRT_DIV0x19Örnekleme hızı bölücüsü
CONFIG0x1ADahili alçak geçiren filtre (DLPF)
GYRO_CONFIG0x1BJiroskop aralığı (±250 … ±2000 °/s)
ACCEL_CONFIG0x1Cİvmeölçer aralığı (±2 … ±16 g)
ACCEL_XOUT_H0x3BÖlçümlerin başladığı adres (14 bayt)
PWR_MGMT_10x6BUyku ve saat kaynağı; 0 yazınca uyanır
WHO_AM_I0x75Kimlik; gerçek MPU6050'de 0x68 döner

Durağan bir sensörde ivmeölçerin gördüğü tek kuvvet yerçekimidir. Yerçekiminin eksenlere nasıl dağıldığına bakarak iki açıyı bulursun: X ekseni etrafındaki yatma açısı roll = atan2(ay, az), Y ekseni etrafındaki yunuslama açısı ise pitch = atan2(−ax, √(ay² + az²)). atan2 fonksiyonu, normal arktanjanttan farklı olarak dört bölgenin hepsinde doğru işareti verir ve az sıfıra yaklaştığında sıfıra bölme hatası yaşamaz. Örneğin ay = 8192 ve az = 14189 okursan roll = atan2(8192, 14189) ≈ 30° olur. Z ekseni etrafındaki dönüşü (yaw) ise ivmeölçer göremez, çünkü bu dönüşte yerçekiminin eksenlere dağılımı değişmez.

İki sensörün de zayıf yanı vardır. İvmeölçer uzun vadede doğrudur, ama hareket ve titreşim sırasında çok gürültülüdür; çünkü yerçekiminin yanında hareketin kendi ivmesini de ölçer. Jiroskop kısa vadede pürüzsüzdür, ama açıyı bulmak için açısal hızı zamanla toplarsın (açı += hız × dt) ve küçük bir sapma bile birikerek açıyı yavaş yavaş kaydırır. Tamamlayıcı filtre ikisini birleştirir: açı = 0,98 × (açı + jiroskop × dt) + 0,02 × ivmeölçer açısı. Kısa sürede jiroskoba, uzun sürede ivmeölçere güvenir. 100 Hz'te (dt = 0,01 s) bu katsayılar yaklaşık yarım saniyelik bir zaman sabiti verir: τ = 0,98 × 0,01 / 0,02 = 0,49 s.

Kalibrasyon da en az filtre kadar önemlidir. Hiç hareket etmeyen bir jiroskop bile birkaç °/s'lik sabit bir sapma (offset) gösterebilir; düzeltmezsen hesapladığın açı saniyeler içinde onlarca derece kayar. Aşağıdaki kod açılışta, sensör hareketsizken 500 ölçümün ortalamasını alır ve bunu sonraki her okumadan çıkarır. Kalibrasyon sırasında kartı düz bir zemine koy ve dokunma; ardından Seri Çizici'de roll, pitch ve yaw eğrilerini izle.

Arduino (C++)
1#include <Wire.h>
2
3const int MPU_ADDR = 0x68;           // AD0 GND'de ya da boşta / AD0 to GND or floating
4const float GYRO_LSB = 131.0;        // ±250 °/s aralığında 1 °/s / 1 °/s at the ±250 °/s range
5const float ALPHA = 0.98;            // tamamlayıcı filtre katsayısı / complementary filter weight
6
7int16_t ax, ay, az, tempRaw, gx, gy, gz;
8float gxOff = 0, gyOff = 0, gzOff = 0;   // jiroskop sapmaları / gyro offsets
9float roll = 0, pitch = 0, yaw = 0;
10unsigned long lastMicros;
11
12void writeReg(uint8_t reg, uint8_t val) {
13  Wire.beginTransmission(MPU_ADDR);
14  Wire.write(reg);
15  Wire.write(val);
16  Wire.endTransmission();
17}
18
19int16_t read16() {
20  uint8_t hi = Wire.read();          // önce yüksek bayt / high byte first
21  uint8_t lo = Wire.read();
22  return (int16_t)(((uint16_t)hi << 8) | lo);
23}
24
25void readMPU() {
26  Wire.beginTransmission(MPU_ADDR);
27  Wire.write(0x3B);                  // ACCEL_XOUT_H
28  Wire.endTransmission(false);       // hattı bırakma, tekrar başlat / repeated start
29  Wire.requestFrom(MPU_ADDR, 14);    // ivme 6 + sıcaklık 2 + jiroskop 6 bayt / accel 6 + temp 2 + gyro 6 bytes
30  ax = read16(); ay = read16(); az = read16();
31  tempRaw = read16();
32  gx = read16(); gy = read16(); gz = read16();
33}
34
35void calibrateGyro() {
36  const int N = 500;
37  long sx = 0, sy = 0, sz = 0;
38  for (int i = 0; i < N; i++) {
39    readMPU();
40    sx += gx; sy += gy; sz += gz;
41    delay(3);
42  }
43  gxOff = sx / (float)N;
44  gyOff = sy / (float)N;
45  gzOff = sz / (float)N;
46}
47
48void setup() {
49  Serial.begin(115200);
50  Wire.begin();
51  Wire.setClock(400000);             // 400 kHz hızlı mod / 400 kHz fast mode
52  writeReg(0x6B, 0x00);              // PWR_MGMT_1: uykudan uyandır / wake up
53  writeReg(0x1A, 0x03);              // CONFIG: alçak geçiren filtre ~44 Hz / low-pass ~44 Hz
54  writeReg(0x1B, 0x00);              // GYRO_CONFIG: ±250 °/s
55  writeReg(0x1C, 0x00);              // ACCEL_CONFIG: ±2 g
56  delay(100);
57  Serial.println("Kalibrasyon: sensoru oynatma / calibrating: keep still");
58  calibrateGyro();
59  readMPU();
60  roll  = atan2(ay, az) * RAD_TO_DEG;                                    // başlangıç açıları / initial angles
61  pitch = atan2(-ax, sqrt((float)ay * ay + (float)az * az)) * RAD_TO_DEG;
62  lastMicros = micros();
63}
64
65void loop() {
66  readMPU();
67  unsigned long now = micros();
68  float dt = (now - lastMicros) / 1000000.0;   // saniye / seconds
69  lastMicros = now;
70
71  float accRoll  = atan2(ay, az) * RAD_TO_DEG;                           // ivmeölçerden açı / angle from accelerometer
72  float accPitch = atan2(-ax, sqrt((float)ay * ay + (float)az * az)) * RAD_TO_DEG;
73  float gxRate = (gx - gxOff) / GYRO_LSB;      // °/s
74  float gyRate = (gy - gyOff) / GYRO_LSB;
75  float gzRate = (gz - gzOff) / GYRO_LSB;
76
77  roll  = ALPHA * (roll  + gxRate * dt) + (1 - ALPHA) * accRoll;        // tamamlayıcı filtre / complementary filter
78  pitch = ALPHA * (pitch + gyRate * dt) + (1 - ALPHA) * accPitch;
79  yaw  += gzRate * dt;                         // yalnız jiroskop: zamanla kayar / gyro only: drifts over time
80
81  Serial.print("roll:");   Serial.print(roll, 1);
82  Serial.print(" pitch:"); Serial.print(pitch, 1);
83  Serial.print(" yaw:");   Serial.println(yaw, 1);
84  delay(10);                                   // yaklaşık 100 Hz / about 100 Hz
85}
Kod satırıNe yapar?
writeReg(0x6B, 0x00)Sensörü uyku modundan çıkarır
writeReg(0x1A, 0x03)Yaklaşık 44 Hz'lik dahili filtreyi açar
Wire.requestFrom(MPU_ADDR, 14)İvme, sıcaklık ve jiroskop verisini tek seferde okur
calibrateGyro()500 ölçümün ortalamasıyla jiroskop sapmasını bulur
atan2(ay, az) * RAD_TO_DEGİvmeölçerden roll açısını derece olarak hesaplar
ALPHA * (...) + (1 - ALPHA) * ...Tamamlayıcı filtre: jiroskop ve ivmeölçeri birleştirir
yaw += gzRate * dtYaw'u yalnız jiroskopla hesaplar; zamanla kaydığını gözlemlersin
Seri Çizici'de kartı hafifçe sars: ham ivmeölçer açısı zıplarken filtrelenmiş açı sakin kalır. Daha hızlı tepki istiyorsan ALPHA'yı 0,95'e düşür, daha az titreşim istiyorsan 0,99'a çıkar. Daha da kararlı sonuç için Electronic Cats'in MPU6050 kütüphanesindeki DMP örneği, açıları sensörün kendi işlemcisinde hesaplanan dördey (quaternion) verisinden çıkarır.

ESP32 ile MPU6050: düşme algılayan alarm

ESP32'de bağlantı Uno ile aynıdır; yalnız I2C pinleri GPIO 21 (SDA) ve GPIO 22 (SCL)'dir ve modül 3V3'ten beslenir. Yukarıdaki kodların hepsi ESP32'de değişmeden çalışır; istersen Wire.begin(21, 22) ile pinleri açıkça belirtebilirsin. Aşağıdaki örnek bir düşme dedektörüdür. Serbest düşen bir cisimde ivmeölçer neredeyse 0 g okur, çünkü sensörün gövdesi ile içindeki kütle birlikte düşer; ardından gelen çarpma ise birkaç g'lik bir tepe üretir. Kod, en az 100 ms süren bir serbest düşüşün ardından yarım saniye içinde 2,5 g'yi aşan bir darbe görürse GPIO 25'e bağlı aktif buzzer'ı bir saniye öttürür. 100 ms'lik serbest düşüş, yaklaşık 5 cm yükseklikten düşmeye karşılık gelir (h = ½ × g × t²).

Arduino (C++)
1#include <Wire.h>
2#include <Adafruit_MPU6050.h>
3#include <Adafruit_Sensor.h>
4
5Adafruit_MPU6050 mpu;
6const int BUZZER_PIN = 25;           // aktif buzzer / active buzzer
7const float FREE_FALL_G = 0.4;       // serbest düşüş eşiği / free-fall threshold
8const float IMPACT_G = 2.5;          // darbe eşiği / impact threshold
9unsigned long fallStart = 0, fallEnd = 0;
10
11void setup() {
12  Serial.begin(115200);
13  pinMode(BUZZER_PIN, OUTPUT);
14  Wire.begin(21, 22);                // SDA, SCL
15  if (!mpu.begin(0x68, &Wire)) {
16    Serial.println("MPU6050 bulunamadi / not found");
17    while (true) delay(10);
18  }
19  mpu.setAccelerometerRange(MPU6050_RANGE_8_G);   // darbeler için geniş aralık / wide range for impacts
20  mpu.setFilterBandwidth(MPU6050_BAND_94_HZ);     // kısa darbeleri kaçırma / keep short peaks
21}
22
23void loop() {
24  sensors_event_t a, g, t;
25  mpu.getEvent(&a, &g, &t);
26  float x = a.acceleration.x, y = a.acceleration.y, z = a.acceleration.z;
27  float total = sqrt(x * x + y * y + z * z) / SENSORS_GRAVITY_STANDARD;   // toplam ivme, g / total acceleration in g
28  unsigned long now = millis();
29
30  if (total < FREE_FALL_G) {
31    if (fallStart == 0) fallStart = now;             // düşüş başladı / fall started
32  } else if (fallStart != 0) {
33    if (now - fallStart > 100) fallEnd = now;        // en az 100 ms süren düşüş / fall of at least 100 ms
34    fallStart = 0;
35  }
36
37  if (fallEnd != 0 && now - fallEnd < 500 && total > IMPACT_G) {   // düşüşten sonra 0,5 s içinde darbe / impact within 0.5 s
38    Serial.println("DUSME ALGILANDI / FALL DETECTED");
39    digitalWrite(BUZZER_PIN, HIGH);
40    delay(1000);
41    digitalWrite(BUZZER_PIN, LOW);
42    fallEnd = 0;
43  }
44  if (fallEnd != 0 && now - fallEnd >= 500) fallEnd = 0;   // darbe gelmedi, sıfırla / no impact, reset
45  delay(5);
46}

Bu temel üzerine ESP32'nin Wi-Fi'sini ekleyerek, örneğin yaşlı bir yakının düşmesi hâlinde telefona Telegram bildirimi gönderebilir ya da açıları bir web sayfasında canlı gösterebilirsin. Eşikleri kendi denemelerine göre ayarla: masadan düşen bir kutu ile bileğe takılan bir sensörün verdiği tepeler farklıdır. Buzzer seçimi ve bağlantısı için Buzzer Nedir? yazısına bakabilirsin.

Raspberry Pi Pico ile MPU6050 (MicroPython)

Pico'da ek kütüphane gerekmez; MicroPython'un yerleşik I2C sınıfı register'ları doğrudan okuyabilir. Sensörü I2C0 hattına, SDA'yı GP4'e ve SCL'yi GP5'e bağla. struct.unpack ile 14 baytı işaretli 16 bitlik yedi sayıya çeviririz; ">" büyük endian (önce yüksek bayt), "h" ise işaretli 16 bit anlamına gelir. Kod önce bulunan I2C adreslerini yazdırır; listede 0x68 görmüyorsan bağlantıyı kontrol et. Basit tutmak için kalibrasyon eklemedik; gerekirse Arduino kodundaki ortalama alma yöntemini aynen uygulayabilirsin.

MicroPython
1from machine import Pin, I2C
2import math, struct, time
3
4MPU = 0x68
5i2c = I2C(0, sda=Pin(4), scl=Pin(5), freq=400000)
6print("Bulunan adresler / found addresses:", [hex(a) for a in i2c.scan()])
7
8i2c.writeto_mem(MPU, 0x6B, b"\x00")     # uykudan uyandır / wake up
9i2c.writeto_mem(MPU, 0x1A, b"\x03")     # alçak geçiren filtre ~44 Hz / low-pass ~44 Hz
10i2c.writeto_mem(MPU, 0x1B, b"\x00")     # jiroskop ±250 °/s / gyro ±250 °/s
11i2c.writeto_mem(MPU, 0x1C, b"\x00")     # ivmeölçer ±2 g / accelerometer ±2 g
12roll = pitch = 0.0
13last = time.ticks_us()
14
15while True:
16    data = i2c.readfrom_mem(MPU, 0x3B, 14)
17    ax, ay, az, t, gx, gy, gz = struct.unpack(">hhhhhhh", data)   # büyük endian, işaretli / big-endian, signed
18    now = time.ticks_us()
19    dt = time.ticks_diff(now, last) / 1000000
20    last = now
21    acc_roll = math.degrees(math.atan2(ay, az))
22    acc_pitch = math.degrees(math.atan2(-ax, math.sqrt(ay * ay + az * az)))
23    roll = 0.98 * (roll + gx / 131 * dt) + 0.02 * acc_roll        # tamamlayıcı filtre / complementary filter
24    pitch = 0.98 * (pitch + gy / 131 * dt) + 0.02 * acc_pitch
25    temp = t / 340 + 36.53                                        # °C
26    print("roll {:.1f}  pitch {:.1f}  T {:.1f}".format(roll, pitch, temp))
27    time.sleep_ms(10)

MPU6050 ile proje fikirleri

  • Dijital su terazisi: Roll ve pitch açılarını bir OLED ekranda hareket eden bir kabarcıkla göster.
  • Hareketle servo kontrolü: Elindeki sensörü eğdikçe bir servo motor aynı açıya dönsün; robot kol ya da kamera başlığı için idealdir.
  • Eğerek oynanan oyun: Joystick yerine kartı eğerek Pong ya da labirent oyunu oyna.
  • Kendi kendini dengeleyen robot: Pitch açısını PID ile işleyip L298N ile sürülen DC motorlarla robotu dik tut.
  • Adım sayar: Toplam ivmedeki düzenli tepeleri sayarak yürüyüşü ölç.
  • Titreşim kaydedici: Bir makinenin ya da çamaşır makinesinin sarsıntısını ölç, eşik aşıldığında uyarı ver.

Sık yapılan hatalar ve çözümleri

BelirtiOlası sebepÇözüm
begin() false döndürüyor ("MPU6050 bulunamadi")Kablo hatası, yanlış adres ya da klon yongaI2C tarayıcıyla adresi bul; WHO_AM_I 0x68 değilse (örneğin 0x70) kütüphanesiz kodu kullan
Tüm değerler 0Sensör uyku modunda0x6B register'ına 0 yaz
Değerler -1 ya da donuyorGevşek kablo, uzun I2C hattıKabloları kısalt, pinleri lehimle
Açı durduğu yerde kayıyorJiroskop sapması düzeltilmemişAçılışta hareketsiz kalibrasyon yap
Hareket edince açı zıplıyorYalnız ivmeölçer kullanılıyorTamamlayıcı filtre ekle
Yaw sürekli kayıyorMPU6050'de pusula yokQMC5883L gibi bir manyetometre ekle ya da 9 eksenli sensör kullan
Pitch ±90°'ye yaklaşınca roll bozuluyorEuler açılarının tekil noktasıBu bölgeden kaçın ya da DMP'nin dördey çıktısını kullan
Sensörü projene sabitlerken kartı vidayla ya da çift taraflı bantla sıkıca tuttur; gevşek bir kart kendi titreşimini ölçer. Kalibrasyonu, sensörün projede çalışacağı sıcaklıkta yapmak da sapmayı azaltır.

MPU6050, düşük fiyatına rağmen hareketi ölçmenin kapısını açar: önce ham değerleri tanı, sonra açıları hesapla, en sonunda filtreyle pürüzsüzleştir. I2C ile bağlanan diğer sensörleri ve kullanım alanlarını görmek için Arduino Sensörleri Rehberi'ne göz atabilirsin. BlueGrays uygulamasında servo kontrolü, I2C ekran, joystick ve robot projelerini adım adım devre şeması ve koduyla bulup MPU6050 ile birleştirebilirsin.

Sıkça sorulan sorular

MPU6050 ne işe yarar?

MPU6050 bir cismin eğimini, dönme hızını ve ivmesini ölçer. Kendi kendini dengeleyen robotlarda, drone ve gimbal'larda, adım sayarlarda, düşme ve sarsıntı algılamada ya da hareketle kontrol edilen oyunlarda kullanılır.

MPU6050 adresi 0x68 mi 0x69 mu?

AD0 pini boşta ya da GND'ye bağlıyken adres 0x68, 3,3 V'a bağlıyken 0x69'dur. GY-521 kartında AD0 dirençle GND'ye çekili olduğu için varsayılan adres 0x68'dir. Emin olmak için bir I2C tarayıcı kodu çalıştırabilirsin.

MPU6050 5 V ile çalışır mı?

MPU6050 yongası en fazla 3,46 V ile çalışır, ama GY-521 kartındaki regülatör sayesinde VCC pini 5 V ile beslenebilir. I2C hatları 3,3 V seviyesinde kalır ve Arduino Uno bu seviyeyi sorunsuz okur. Regülatörü olmayan çıplak kartlara ise 5 V verilmemelidir.

MPU6050 ile açı nasıl hesaplanır?

Sensör durağanken ivmeölçerden roll = atan2(ay, az) ve pitch = atan2(−ax, √(ay² + az²)) formülleriyle açı bulunur. Hareket hâlinde doğru sonuç için jiroskobun açısal hızı zamanla toplanır ve tamamlayıcı ya da Kalman filtresiyle ivmeölçer açısıyla birleştirilir.

MPU6050 yaw açısını ölçebilir mi?

Kısa süreler için evet: Z eksenindeki açısal hız zamanla toplanarak yaw hesaplanabilir. Ancak MPU6050'de manyetometre olmadığı için yaw zamanla kayar ve mutlak yönü (kuzeyi) bilemez. Kararlı bir yön için QMC5883L gibi bir pusula sensörü ya da 9 eksenli bir IMU gerekir.

MPU6050 ile MPU9250 arasındaki fark nedir?

MPU6050 6 eksenlidir: ivmeölçer ve jiroskop içerir. MPU9250 bunlara ek olarak 3 eksenli bir manyetometre barındırdığı için 9 eksenlidir ve yaw açısını kaymadan ölçebilir; ayrıca SPI desteği vardır. MPU9250 üretimden kalktığı için yeni projelerde ICM-20948 gibi halefleri tercih edilir.

Tüm projeleri gör
Servo Motor Kullanım
#35Başlangıç
Premium

Servo Motor Kullanım

Servo motoru 0°, 90° ve 180° açılarına sırayla konumlandıran temel kullanım projesi. Servo kütüphanesi ve açı kontrol mantığını öğretir.

4.7(48)
66
Pot ile SG90 Servo Açı Kontrolü
#99Başlangıç
Premium

Pot ile SG90 Servo Açı Kontrolü

Potansiyometre ile Servo Motor (SG90) Kontrolü Bu projenin temel amacı, analog bir giriş birimi olan potansiyometreyi kullanarak, bir servo motorun açısal konumunu gerçek zamanlı ve hassas bir şekilde kontrol etmektir. Proje, analog-dijital dönüşüm (ADC) ve sinyal haritalama mantığını kavramak için temel bir mühendislik örneğidir. Çalışma Mantığı: Analog Veri Okuma: Kullanıcı potansiyometreyi çevirdiğinde, direnç değişimi sonucunda Arduino'nun A0 analog pinine 0V ile 5V arasında bir voltaj siny

4.5(24)
38
Joystick İle Servo Kontrol
#60Orta
Premium

Joystick İle Servo Kontrol

Joystick modülü ile iki servo motoru X ve Y eksenlerinde bağımsız olarak kontrol eden pan-tilt projesi. Joystick-servo entegrasyonu ve konum takibi mantığını öğretir.

4.7(42)
58
ESP32 Servo Motor (Potansiyometre Kontrolü)
#118Orta
Premium

ESP32 Servo Motor (Potansiyometre Kontrolü)

Bu projede potansiyometre ile SG90 servo motoru kontrol ediyoruz. Potansiyometreden okunan analog değeri 0-180 derece aralığına map'leyerek servo açısını ayarlıyoruz. ESP32Servo kütüphanesi sayesinde ESP32'nin herhangi bir GPIO'su PWM sinyali üretebiliyor. Bu, robotik kollar, kamera gimbal'ları ve otomatik kapı mekanizmaları için temel bir kontrol yöntemidir.

4.3(29)
42
Pong Oyunu - SSD1306
#86Orta
Premium

Pong Oyunu - SSD1306

Arduino ve SSD1306 OLED ekran kullanılarak hazırlanmış; topun hareketlerini anlık olarak takip edip yörüngesine göre tepki veren otonom yapay zeka (CPU) rakibiyle donatılmış ve ses efektleriyle zengin

4.5(47)
65
I2C İle LCD Ekran Kullanımı
#32Başlangıç
Premium

I2C İle LCD Ekran Kullanımı

I2C modülü sayesinde sadece 2 kablo (SDA, SCL) ile LCD ekranı kontrol ederek mesaj yazdıran proje. I2C protokolü ile pin tasarrufu sağlamayı öğretir.

4.8(53)
69
ESP32 I2C LCD Ekran (16x2)
#119Orta
Premium

ESP32 I2C LCD Ekran (16x2)

Bu projede 16x2 karakter LCD ekranı I2C protokolü üzerinden ESP32'ye bağlayarak metin görüntülüyoruz. I2C sayesinde sadece 2 data pini (SDA ve SCL) ile ekranı kontrol edebiliyoruz; klasik paralel bağlantıdaki 6+ pin israfı ortadan kalkıyor. Kod ilk satıra sabit bir mesaj, ikinci satıra ise her saniye artan bir sayaç yazdırıyor. Ayrıca başlangıçta I2C tarayıcı çalıştırarak ekranın adresini Serial Monitor'a yazdırıyoruz (genelde 0x27 veya 0x3F).

4.9(22)
39
Engelden Kaçan Robot
#81İleri
Premium

Engelden Kaçan Robot

Kendi yolunu bulan akıllı bir araç yapmaya ne dersin? Engelden Kaçan Robot, önündeki ultrasonik sensör sayesinde çevresini sürekli tarar. Bir engelle karşılaştığında durur, servo motoruyla sağına ve s

5.0(38)
49

MPU6050 ivmeölçer ve jiroskobu Arduino'ya bağlamayı, ham değerleri okumayı, sensörü kalibre etmeyi, eğim açısını hesaplamayı ve tamamlayıcı filtreyle titreşimden arındırmayı öğren; ESP32 düşme alarmı ve Pico kodu da var.

MPU6050 Arduino: İvmeölçer, Jiroskop ve Eğim Açısı Hesaplama | BlueGrays