blog

MPU-6050 Arduino-opas: kytkentä, koodi ja kallistuskulmat

MPU-6050 Arduino -yhdistelmä on yksi harrastajaelektroniikan suosituimmista anturiprojekteista – ja hyvästä syystä. Haluatko rakentaa itsetasapainottavan robotin, digitaalisen vesivaa’an tai eleohjatun laitteen? Kaikki alkaa tästä pienestä, edullisesta moduulista. MPU-6050 yhdistää kolmiakselisen kiihtyvyysanturin ja kolmiakselisen gyroskoopin samalle piirille, ja se kommunikoi Arduinon kanssa yksinkertaisella I2C-väylällä. Tässä oppaassa käymme läpi MPU-6050:n kytkennän Arduino Nanoon, luemme raakadataa rekisteritasolla ja rakennamme komplementaarifiltterin kallistuskulmien laskemiseen. Lopuksi esittelemme yksinkertaisen PID-pohjaisen tasapainotuskonseptin servolla.

Kaikki tarvittavat komponentit saat alle 20 eurolla, ja projekti sopii erinomaisesti I2C-anturin ja anturitekniikan opiskeluun.

MPU-6050 kiihtyvyysanturi- ja gyroskooppimoduuli
MPU-6050 kiihtyvyysanturi- ja gyroskooppimoduuli – 6-akselinen IMU I2C-väylällä

Mikä on MPU-6050?

MPU-6050 on InvenSensen (nykyisin TDK) valmistama 6-akselinen IMU (Inertial Measurement Unit) eli inertiamittausyksikkö. Se sisältää:

  • Kiihtyvyysanturi (3 akselia) – mittaa lineaarista kiihtyvyyttä X-, Y- ja Z-suunnissa. Oletusalue ±2g, ohjelmoitavissa ±4g, ±8g tai ±16g asti.
  • Gyroskooppi (3 akselia) – mittaa kulmanopeutta. Oletusalue ±250 °/s, ohjelmoitavissa ±500, ±1000 tai ±2000 °/s asti.
  • Lämpötila-anturi – sisäänrakennettu, mittausalue -40 °C … +85 °C.
  • DMP (Digital Motion Processor) – piirin sisäinen prosessori, joka voi laskea sensori­fuusiota itsenäisesti.

Kaikki kanavat käyttävät 16-bittistä AD-muunninta, joten resoluutio on erinomainen. I2C-väylän ansiosta tarvitset vain neljä johtoa: VCC, GND, SDA ja SCL. MPU-6050:n oletusosoite on 0x68, mutta sen voi vaihtaa osoitteeksi 0x69 vetämällä AD0-pinnin ylös. Juuri tämä helppous tekee MPU-6050 Arduino -projekteista niin suosittuja aloittelijoiden keskuudessa.

Kiihtyvyysanturi vs. gyroskooppi – miksi molempia tarvitaan?

Kiihtyvyysanturi mittaa painovoimaa ja liikekiihtyvyyttä. Kun anturi on paikallaan, voit laskea kallistuskulman trigonometrialla, koska painovoima osoittaa aina alaspäin. Ongelmana on, että lukemat ovat kohinaisia ja häiriintyvät tärinästä tai liikkeestä.

Gyroskooppi Arduino -käytössä mittaa kulmanopeutta (°/s). Integroimalla kulmanopeutta ajan suhteen saat kulman muutoksen. Gyro reagoi nopeasti ja on immuuni tärinälle, mutta se ajautuu (drift) ajan myötä, koska pienetkin mittausvirheet kertautuvat integroinnissa.

Ratkaisu on yhdistää molemmat anturit komplementaarifiltterillä tai Kalman-filtterillä. Näin saat gyroskoopin nopeuden ja kiihtyvyysanturin pitkän aikavälin vakauden.

Tarvittavat komponentit

Tähän projektiin tarvitset vain kolme komponenttia:

ATmega328P Nano ohjain
ATmega328P ’Nano’ ohjain – Arduino Nano -yhteensopiva ohjain USB-C-liitännällä
  1. MPU-6050 kiihtyvyysanturi- ja gyroskooppimoduuli – 4,90 €. Moduulissa on valmiiksi juotetut piikkirimat ja sisäänrakennetut ylösvetovastukset SDA/SCL-linjoille.
  2. ATmega328P ’Nano’ ohjain – 9,90 €. Arduino Nano -yhteensopiva ohjain USB-C-liitännällä. I2C-pinnit: A4 (SDA) ja A5 (SCL).
  3. Dupont-hyppylanka 10cm (20kpl) uros-naaras – 3,90 €. Värikoodatut hyppylangat helpottavat kytkentää.

Kokonaishinta: 18,70 € – edullinen tapa päästä alkuun anturitekniikan ja I2C-väylän opiskelussa.

Tasapainotusprojektia (Koodi 3) varten tarvitset lisäksi servon, esimerkiksi MG996R metallivaihteisen servon (11,90 €).

Kytkentä Arduino Nanoon

MPU-6050:n peruskytkentä vaatii vain neljä johtoa. Moduulissa on sisäänrakennettu 3,3 V:n regulaattori, joten voit syöttää siihen 5 V suoraan Arduinon 5V-pinnistä.

MPU-6050 Arduino Nano Huomio
VCC 5V Moduulin oma regulaattori hoitaa jännitteen
GND GND Yhteinen maa
SCL A5 I2C-kellosignaali
SDA A4 I2C-datasignaali
INT D2 (valinnainen) Keskeytyspinni DMP:lle
AD0 GND tai NC Low = osoite 0x68
XDA, XCL NC Ulkoisille antureille, ei tarvita

Varmista, että GND-yhteys on kunnossa – se on yleisin syy I2C-ongelmiin. Moduulin valmiit ylösvetovastukset hoitavat SDA- ja SCL-linjojen vetämisen, joten erillisiä vastuksia ei tarvita.

Koodi 1: Raakadatan lukeminen Wire.h-kirjastolla

Aloitetaan yksinkertaisimmasta esimerkistä: luetaan MPU-6050:n kiihtyvyys-, gyroskooppi- ja lämpötiladata suoraan rekistereistä. Käytämme Arduinon sisäänrakennettua Wire.h-kirjastoa, joka hoitaa I2C-protokollan.

Tärkeä huomio: MPU-6050 käynnistyy lepotilassa! Rekisteriin 0x6B (PWR_MGMT_1) täytyy kirjoittaa arvo 0x00, jotta anturi herää. Tämä on yleisin aloittelijan virhe.

/*
 * MPU-6050 raakadatan lukeminen Arduinolla
 * Kytkentä: VCC->5V, GND->GND, SCL->A5, SDA->A4
 */
#include <Wire.h>

const int MPU_ADDR = 0x68;  // MPU-6050 I2C-osoite

int16_t accX, accY, accZ;
int16_t gyroX, gyroY, gyroZ;
int16_t temp;

void setup() {
  Serial.begin(115200);
  Wire.begin();
  
  // Herätä MPU-6050 lepotilasta
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x6B);  // PWR_MGMT_1 rekisteri
  Wire.write(0x00);  // Kirjoita 0 -> herätys
  Wire.endTransmission(true);
  
  Serial.println("MPU-6050 alustettu!");
}

void loop() {
  // Lue 14 tavua alkaen rekisteristä 0x3B
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x3B);  // ACCEL_XOUT_H
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_ADDR, 14, true);
  
  // Yhdistä kaksi tavua 16-bittiseksi arvoksi
  accX  = Wire.read() << 8 | Wire.read();
  accY  = Wire.read() << 8 | Wire.read();
  accZ  = Wire.read() << 8 | Wire.read();
  temp  = Wire.read() << 8 | Wire.read();
  gyroX = Wire.read() << 8 | Wire.read();
  gyroY = Wire.read() << 8 | Wire.read();
  gyroZ = Wire.read() << 8 | Wire.read();
  
  // Muunna fysikaalisiksi arvoiksi (oletus ±2g ja ±250°/s)
  float ax = accX / 16384.0;   // g-voimaksi
  float ay = accY / 16384.0;
  float az = accZ / 16384.0;
  float gx = gyroX / 131.0;    // °/s
  float gy = gyroY / 131.0;
  float gz = gyroZ / 131.0;
  float tempC = temp / 340.0 + 36.53;  // °C
  
  Serial.print("aX="); Serial.print(ax, 2);
  Serial.print(" aY="); Serial.print(ay, 2);
  Serial.print(" aZ="); Serial.print(az, 2);
  Serial.print(" | gX="); Serial.print(gx, 1);
  Serial.print(" gY="); Serial.print(gy, 1);
  Serial.print(" gZ="); Serial.print(gz, 1);
  Serial.print(" | T="); Serial.print(tempC, 1);
  Serial.println("°C");
  
  delay(100);
}

Raakadatan tulkinta

Anturi palauttaa 16-bittisiä etumerkillisiä kokonaislukuja (-32768 … +32767). Jotta saat fysikaaliset arvot, jaa raakadata herkkyys­kertoimella:

  • Kiihtyvyys (±2g): jaa luvulla 16384 → tulos g-voimana. Paikallaan Z-akselin pitäisi näyttää ~1,0 g (painovoima).
  • Gyroskooppi (±250 °/s): jaa luvulla 131 → tulos asteina sekunnissa. Paikallaan kaikkien akselien pitäisi olla lähellä nollaa.
  • Lämpötila: kaava on raaka / 340.0 + 36.53 → tulos celsiusasteina.

Jos vaihdat mittausaluetta (esim. ±4g tai ±500 °/s), muista päivittää myös jakoluku koodissa!

Koodi 2: Kallistuskulmat komplementaarifiltterillä

Pelkkä raakadata ei vielä kerro, missä asennossa anturi on. Tarvitsemme sensori­fuusion, joka yhdistää kiihtyvyysanturin ja gyroskoopin tiedot luotettavaksi kulma-arvioksi.

Komplementaarifiltterin periaate

Komplementaarifiltteri on yksinkertainen mutta tehokas tapa yhdistää kaksi anturitietoa:

kulma = α × (kulma + gyro × dt) + (1 - α) × kiihtyvyyskulma

Kerroin α = 0,96 tarkoittaa, että 96 % painosta tulee gyroskoopin integraalista (nopea, tarkka lyhyellä aikavälillä) ja 4 % kiihtyvyysanturin kulmasta (vakaa pitkällä aikavälillä, korjaa gyroskoopin ajautumisen). Tämä on laskennallisesti kevyt ja riittävän tarkka useimpiin harrasteprojekteihin.

/*
 * MPU-6050 kallistuskulmat komplementaarifiltterillä
 * Laskee pitch ja roll -kulmat asteina
 */
#include <Wire.h>

const int MPU_ADDR = 0x68;
float pitch = 0, roll = 0;
unsigned long prevTime = 0;
const float alpha = 0.96;  // Komplementaarifiltterin kerroin

void setup() {
  Serial.begin(115200);
  Wire.begin();
  
  // Herätä MPU-6050
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x6B);
  Wire.write(0x00);
  Wire.endTransmission(true);
  
  // Aseta DLPF (Digital Low Pass Filter) taajuudeksi ~44 Hz
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x1A);  // CONFIG rekisteri
  Wire.write(0x03);  // DLPF_CFG = 3
  Wire.endTransmission(true);
  
  prevTime = millis();
  delay(100);
}

void loop() {
  // Lue raakadata
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x3B);
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_ADDR, 14, true);
  
  int16_t accX  = Wire.read() << 8 | Wire.read();
  int16_t accY  = Wire.read() << 8 | Wire.read();
  int16_t accZ  = Wire.read() << 8 | Wire.read();
  int16_t temp  = Wire.read() << 8 | Wire.read();  // ohitetaan
  int16_t gyroX = Wire.read() << 8 | Wire.read();
  int16_t gyroY = Wire.read() << 8 | Wire.read();
  int16_t gyroZ = Wire.read() << 8 | Wire.read();
  
  // Muunna kiihtyvyys g-voimaksi
  float ax = accX / 16384.0;
  float ay = accY / 16384.0;
  float az = accZ / 16384.0;
  
  // Muunna gyro asteiksi/sekunti
  float gx = gyroX / 131.0;
  float gy = gyroY / 131.0;
  
  // Laske aika-askel
  unsigned long now = millis();
  float dt = (now - prevTime) / 1000.0;
  prevTime = now;
  
  // Kiihtyvyysanturin kulmat (trigonometria)
  float accPitch = atan2(ay, sqrt(ax * ax + az * az)) * 180.0 / PI;
  float accRoll  = atan2(-ax, sqrt(ay * ay + az * az)) * 180.0 / PI;
  
  // Komplementaarifiltteri
  pitch = alpha * (pitch + gx * dt) + (1.0 - alpha) * accPitch;
  roll  = alpha * (roll  + gy * dt) + (1.0 - alpha) * accRoll;
  
  Serial.print("Pitch: "); Serial.print(pitch, 1);
  Serial.print("°  Roll: "); Serial.print(roll, 1);
  Serial.println("°");
  
  delay(10);  // ~100 Hz näytteenottotaajuus
}

Huomaa, että koodissa otetaan käyttöön myös DLPF (Digital Low Pass Filter) kirjoittamalla rekisteriin 0x1A. Tämä suodattaa korkeataajuista kohinaa pois jo anturin sisällä, mikä parantaa lukemien laatua merkittävästi.

Koodi 3: Tasapainotusalusta servolla ja PID-säädöllä

Seuraava esimerkki demonstroi, miten MPU-6050 Arduino -ympäristössä voidaan hyödyntää aktiiviseen tasapainotukseen. Käytämme servoa, joka korjaa alustan kallistusta pitch-akselin mukaan. Tämä on yksinkertaistettu versio itsetasapainottavan robotin periaatteesta.

PID-säätimen perusteet

PID-säädin koostuu kolmesta osasta:

  • P (Proportional) – korjaa nykyisen virheen suhteessa. Mitä suurempi kallistus, sitä voimakkaampi korjaus.
  • I (Integral) – korjaa kertynyttä virhettä ajan myötä. Poistaa pysyvän poikkeaman.
  • D (Derivative) – ennakoi tulevaa virhettä muutosnopeuden perusteella. Vaimentaa värähtelyä.
/*
 * Yksinkertainen tasapainotusalusta
 * MPU-6050 + servo – demonstroi tasapainotuksen periaatteen
 * Servo korjaa kallistusta pitch-akselin mukaan
 */
#include <Wire.h>
#include <Servo.h>

const int MPU_ADDR = 0x68;
Servo balanceServo;

float pitch = 0;
unsigned long prevTime = 0;
const float alpha = 0.96;

// PID-kertoimet (vaativat viritystä projektikohtaisesti)
float Kp = 2.0;
float Ki = 0.05;
float Kd = 1.0;
float prevError = 0;
float integral = 0;
float setpoint = 0;  // Tavoitekulma (0° = vaakasuora)

void setup() {
  Serial.begin(115200);
  Wire.begin();
  
  // Herätä MPU-6050
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x6B);
  Wire.write(0x00);
  Wire.endTransmission(true);
  
  balanceServo.attach(9);  // Servo pinniin D9
  balanceServo.write(90);  // Keskiasento
  
  prevTime = millis();
  delay(500);
}

void loop() {
  // Lue anturidata
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(0x3B);
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_ADDR, 14, true);
  
  int16_t accX  = Wire.read() << 8 | Wire.read();
  int16_t accY  = Wire.read() << 8 | Wire.read();
  int16_t accZ  = Wire.read() << 8 | Wire.read();
  int16_t temp  = Wire.read() << 8 | Wire.read();
  int16_t gyroX = Wire.read() << 8 | Wire.read();
  int16_t gyroY = Wire.read() << 8 | Wire.read();
  int16_t gyroZ = Wire.read() << 8 | Wire.read();
  
  float ax = accX / 16384.0;
  float ay = accY / 16384.0;
  float az = accZ / 16384.0;
  float gx = gyroX / 131.0;
  
  unsigned long now = millis();
  float dt = (now - prevTime) / 1000.0;
  prevTime = now;
  
  // Komplementaarifiltteri pitch-kulmalle
  float accPitch = atan2(ay, sqrt(ax * ax + az * az)) * 180.0 / PI;
  pitch = alpha * (pitch + gx * dt) + (1.0 - alpha) * accPitch;
  
  // PID-säätö
  float error = setpoint - pitch;
  integral += error * dt;
  integral = constrain(integral, -50, 50);  // Anti-windup
  float derivative = (error - prevError) / dt;
  float output = Kp * error + Ki * integral + Kd * derivative;
  prevError = error;
  
  // Muunna servokulmaksi (90° = keskiasento)
  int servoAngle = constrain(90 + (int)output, 0, 180);
  balanceServo.write(servoAngle);
  
  Serial.print("Pitch: "); Serial.print(pitch, 1);
  Serial.print("° Servo: "); Serial.println(servoAngle);
  
  delay(10);
}

PID-kertoimet (Kp, Ki, Kd) vaativat aina projektikohtaista viritystä. Hyvä aloitustapa on asettaa ensin vain P-kerroin ja kasvattaa sitä, kunnes järjestelmä alkaa värähdellä. Pienennä sitten hieman ja lisää D-kerroin vaimentamaan värähtelyä. I-kerroin lisätään viimeisenä poistamaan mahdollinen pysyvä poikkeama.

Vianetsintä ja vinkit

MPU-6050 on luotettava I2C-anturi, mutta muutama asia kannattaa tarkistaa, jos jokin ei toimi:

Yleisimmät ongelmat

  1. Kaikki lukemat ovat nollia: Unohdit herättää anturin lepotilasta. Varmista, että kirjoitat arvon 0x00 rekisteriin 0x6B setup()-funktiossa.
  2. I2C-laitetta ei löydy: Tarkista johdotus ja käytä Arduino I2C Scanner -esimerkkisketsaa. Varmista myös AD0-pinnin tila (GND = osoite 0x68).
  3. Kohinaiset lukemat: Ota käyttöön DLPF kirjoittamalla rekisteriin 0x1A (esim. arvo 0x03 = ~44 Hz suodatus). Varmista myös, että johdot ovat kunnolla kiinni.
  4. Gyroskooppi ajautuu: Tämä on normaalia! Käytä komplementaarifiltteriä tai Kalman-filtteriä kompensoimaan ajautumista.
  5. Arvot vaikuttavat vääriltä: Tarkista, että jakoluku vastaa asetettua mittausaluetta. Oletusalueella ±2g jakoluku on 16384, ja ±250 °/s jakoluku on 131.

Kalibrointi parantaa tarkkuutta

Jokainen MPU-6050-moduuli on hieman erilainen. Kalibroimalla saat tarkempia tuloksia:

  1. Aseta anturi tasaiselle, vakaalle pinnalle.
  2. Lue noin 200 näytettä ja laske keskiarvo jokaiselle akselille.
  3. Kiihtyvyysanturin X ja Y pitäisi olla ~0, Z pitäisi olla ~16384 (1g). Gyroskoopin kaikkien akselien pitäisi olla ~0.
  4. Vähennä lasketut offset-arvot tulevista lukemista koodissa.

MPU-6050 Arduino -jatkoprojektit ja ideat

Kun MPU-6050 Arduino -perusteet ovat hallussa, voit laajentaa projektia moneen suuntaan:

  • Itsetasapainottava robotti – klassinen MPU-6050-projekti. Vaatii DC-moottorit, moottoriohjaimen (esim. L298N) ja huolellisesti viritetyn PID-säätimen.
  • Dronen lennonvakautus – MPU-6050 on monien DIY-lennokkien ytimessä. Tehokkaampiin projekteihin voit harkita ESP32 DevKitC -ohjainta, joka tarjoaa Wi-Fi-yhteyden telemetriadatalle.
  • Eleohjaus – tunnista käden liikkeitä ja ohjaa niillä LED-valoja, servoja tai muita laitteita.
  • Kallistusmittari – rakenna digitaalinen vesivaaka tai inklinometri.
  • Kameran gimbaali – stabiloi kamera kahdella tai kolmella servolla kiihtyvyysanturin datan perusteella.
  • Tärinämonitorointi – seuraa koneiden tai rakenteiden tärinää kiihtyvyysdatan avulla.

Yhteenveto

MPU-6050 on erinomainen I2C-anturi harrasteprojekteihin ja oppimiseen. Tässä oppaassa kävimme läpi kolme esimerkkiä: raakadatan lukemisen rekisteritasolla, kallistuskulmien laskemisen komplementaarifiltterillä ja PID-pohjaisen tasapainotuksen servolla. Nämä esimerkit antavat vankan pohjan MPU-6050 Arduino -projekteihin ja sensori­fuusion ymmärtämiseen.

Sen edullinen hinta, helppo kytkentä ja laaja yhteisötuki tekevät MPU-6050:stä täydellisen valinnan ensimmäiseksi IMU-anturiksi. Hanki kaikki tarvittavat komponentit Protocachesta ja aloita kokeileminen!

👉 Tilaa MPU-6050-moduuli Protocachesta ja rakenna oma anturiprojektisi jo tänään!

Vastaa

Sähköpostiosoitettasi ei julkaista. Pakolliset kentät on merkitty *