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 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.
| Özellik | Değer |
|---|---|
| Sensörler | 3 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ük | 16 bit (her eksen için -32768 ile 32767 arası) |
| Haberleşme | I2C, 400 kHz'e kadar |
| I2C adresi | 0x68 (AD0 GND'de) ya da 0x69 (AD0 3,3 V'ta) |
| Yonga gerilimi | 2,375–3,46 V (GY-521 kartı 3,3–5 V ile beslenir) |
| Akım | Yaklaşık 3,9 mA (uykuda 5 µA) |
| Ek özellikler | DMP, 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/g | Jiroskop aralığı | LSB/(°/s) |
|---|---|---|---|---|
| 0 | ±2 g | 16384 | ±250 °/s | 131 |
| 1 | ±4 g | 8192 | ±500 °/s | 65,5 |
| 2 | ±8 g | 4096 | ±1000 °/s | 32,8 |
| 3 | ±16 g | 2048 | ±2000 °/s | 16,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 pini | Arduino Uno | ESP32 | Raspberry Pi Pico |
|---|---|---|---|
| VCC | 5V | 3V3 | 3V3(OUT) |
| GND | GND | GND | GND |
| SCL | A5 | GPIO 22 | GP5 |
| SDA | A4 | GPIO 21 | GP4 |
| AD0 | Boş (adres 0x68) | Boş (adres 0x68) | Boş (adres 0x68) |
| INT | D2 (isteğe bağlı) | Herhangi bir GPIO (isteğe bağlı) | Herhangi bir GP pini (isteğe bağlı) |
| XDA, XCL | Bağlanmaz | Bağlanmaz | Bağ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.
Kütüphaneyle hızlı başlangıç: Adafruit MPU6050
- Arduino IDE'de Kütüphane Yöneticisi'ni aç ve Adafruit MPU6050 ara.
- Kurarken bağımlılıkları sorduğunda Install all seç; böylece Adafruit Unified Sensor ve Adafruit BusIO da kurulur.
- Sensörü tablodaki gibi bağla, aşağıdaki kodu yükle ve Seri Monitör'ü 115200 baud'da aç.
- 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.
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:
| Register | Adres | Görevi |
|---|---|---|
| SMPLRT_DIV | 0x19 | Örnekleme hızı bölücüsü |
| CONFIG | 0x1A | Dahili alçak geçiren filtre (DLPF) |
| GYRO_CONFIG | 0x1B | Jiroskop aralığı (±250 … ±2000 °/s) |
| ACCEL_CONFIG | 0x1C | İvmeölçer aralığı (±2 … ±16 g) |
| ACCEL_XOUT_H | 0x3B | Ölçümlerin başladığı adres (14 bayt) |
| PWR_MGMT_1 | 0x6B | Uyku ve saat kaynağı; 0 yazınca uyanır |
| WHO_AM_I | 0x75 | Kimlik; 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.
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 * dt | Yaw'u yalnız jiroskopla hesaplar; zamanla kaydığını gözlemlersin |
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²).
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.
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
| Belirti | Olası sebep | Çözüm |
|---|---|---|
| begin() false döndürüyor ("MPU6050 bulunamadi") | Kablo hatası, yanlış adres ya da klon yonga | I2C tarayıcıyla adresi bul; WHO_AM_I 0x68 değilse (örneğin 0x70) kütüphanesiz kodu kullan |
| Tüm değerler 0 | Sensör uyku modunda | 0x6B register'ına 0 yaz |
| Değerler -1 ya da donuyor | Gevşek kablo, uzun I2C hattı | Kabloları kısalt, pinleri lehimle |
| Açı durduğu yerde kayıyor | Jiroskop sapması düzeltilmemiş | Açılışta hareketsiz kalibrasyon yap |
| Hareket edince açı zıplıyor | Yalnız ivmeölçer kullanılıyor | Tamamlayıcı filtre ekle |
| Yaw sürekli kayıyor | MPU6050'de pusula yok | QMC5883L gibi bir manyetometre ekle ya da 9 eksenli sensör kullan |
| Pitch ±90°'ye yaklaşınca roll bozuluyor | Euler açılarının tekil noktası | Bu bölgeden kaçın ya da DMP'nin dördey çıktısını kullan |
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.
Bu yazıdan sonra yapabileceğin projeler
Tüm projeleri gör
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.

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

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.

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.

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

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.

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).

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
Diğer yazılar
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.

