Bu yazımda bitirme projemde uğraştığımız bir konuya değineceğim. MPU 6050 IMU sensörünü Arduino cihazınıza bağladığınızda karşınıza -2000, 15000, 4000 gibi ham veriler okunduğunu görebilirsiniz. Bu değerleri -180 ile +180 aralığına çekmek için ham verilerin filtreden geçirilmesi gerekmektedir. Filtre olarak Arduino‘da kullanılmasına imkan sağlayan Kalman Filtresi’ni kullandık. Ben sizlerle internetten bulduğumuz ve hatalı çalışan bir kodun düzeltilmiş halini paylaşacağım.
Kodlamaya geçmeden önce bağlantıları doğru bir şekilde yapmak gerekiyor. Biz projemizde Arduino Mega kullanmıştık, bağlantıları aşağıdaki tablodan ve şekilden rahatlıkla görebilirsiniz:
Arduino Mega pinleri | MPU6050 pinleri |
GND | GND |
3.3V | VCC |
20(communication) | SDA |
21(communication) | SCL |
Öncelikle bazı kütüphaneleri eklememiz gerekiyor:
#include <MPU6050_6Axis_MotionApps20.h>
#include <Kalman.h>
Kütüphaneleri ekledikten sonra bazı değişkenler tanımlamamız gerekiyor
, isimlerinden ne için kullanıldığını anlayabilirsiniz:
int16_t HamIvmeX, HamIvmeY, HamIvmeZ, HamGyroX, HamGyroY;double IvmeXaci, IvmeYaci, IvmeZaci;double IvmeX, IvmeY, IvmeZ;double GyroXaci = 0, GyroYaci = 0;// Kalman filtresinden gelen değer
double GyroX, GyroY;double OncekiGyroX = 0, OncekiGyroY = 0;uint32_t timer;
MPU6050 mpu;uint8_t mpuDurum;
uint8_t devStatus;
uint16_t PaketBoyutu;
uint16_t Sayac;
uint8_t Bellek[64];
Quaternion q;
VectorFloat YerCekimi;
volatile bool mpuKesme = false;
OncekiGyroX ve OncekiGyroY değişkenleri dikkatinizi çekmiş olabilir. Denemelerimiz sırasında sensörden bazı sapan veriler okunduğunu gördük. Mesela 2-3 derece civarında açı bilgisi geldiğinde birden 50 derece açı bilgisi okunduğunu gördük. Bunun üzerinde okuduğumuz her bir değeri “OncekiGyro” değişkenlerine atadık ve aradaki fark 15 derece ise önemseme dedik. Sonrasında aşağıdaki fonksiyonları kullanarak açı bilgilerini okuduk:
{
uint8_t* veri = i2cRead(0x3B,14);
HamIvmeX = ((veri[0] << 8) | veri[1]);
HamIvmeY = ((veri[2] << 8) | veri[3]);
HamIvmeZ = ((veri[4] << 8) | veri[5]);
HamSicaklik = ((veri[6] << 8) | veri[7]);
HamGyroX = ((veri[8] << 8) | veri[9]);
HamGyroY = ((veri[10] << 8) | veri[11]);IvmeYaci = (atan2(HamIvmeX,HamIvmeZ)+PI)*RAD_TO_DEG;
IvmeXaci = (atan2(HamIvmeY,HamIvmeZ)+PI)*RAD_TO_DEG;
IvmeZaci = (atan2(HamIvmeZ,HamIvmeZ)+PI)*RAD_TO_DEG;double GyroHassasiyetX = (double)HamGyroX/131.0;
double GyroHassasiyetY = -((double)HamGyroY/131.0);GyroX = KalmanX.getAngle(IvmeXaci, GyroHassasiyetX, (double)(micros()-timer)/1000000);
GyroY = KalmanY.getAngle(IvmeYaci, GyroHassasiyetY, (double)(micros()-timer)/1000000);
timer = micros();
GyroX -= 180;
GyroY -= 180;if(abs(GyroX – OncekiGyroX) > 15)
GyroX = OncekiGyroX;
if(abs(GyroY – OncekiGyroY) > 15)
GyroY = OncekiGyroY;OncekiGyroX = GyroX;
OncekiGyroY = GyroY;Sicaklik = ((double)HamSicaklik + 12412.0) / 340.0;//veri madenciliği
IvmeX = (double)((double)(HamIvmeX – 630)/16384.0);
IvmeY = (double)((double)(HamIvmeY – 340)/16384.0);
IvmeZ = (double)((double)(HamIvmeZ – 1720)/16384.0);mpuKesme = false;
mpuDurum = mpu.getIntStatus();
Sayac = mpu.getFIFOCount();
if((mpuDurum & 0x10) || Sayac >= 1024)
{
mpu.resetFIFO();
}
else if(mpuDurum & 0x02)
{
while (Sayac < PaketBoyutu)
Sayac = mpu.getFIFOCount();
mpu.getFIFOBytes(Bellek, PaketBoyutu);
Sayac -= PaketBoyutu;
mpu.dmpGetQuaternion(&q, Bellek);
mpu.dmpGetGravity(&YerCekimi, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &YerCekimi);
ypr[0] = (double)(ypr[0]*1000.0);
GyroZ = map(ypr[0], -3000,3000,-180,180);
}
}
void dmpAktif()
{
mpuKesme = true;
}
void MPUbaslat()
{
Wire.begin();
mpu.initialize();
devStatus = mpu.dmpInitialize();
if(devStatus == 0)
{
mpu.setDMPEnabled(true);
attachInterrupt(0, dmpAktif, RISING);
mpuDurum = mpu.getIntStatus();
PaketBoyutu = mpu.dmpGetFIFOPacketSize();
}
}
void i2cWrite(uint8_t registerAddress, uint8_t data){
Wire.beginTransmission(IMUAddress);
Wire.write(registerAddress);
Wire.write(data);
Wire.endTransmission(); // Send stop
}
uint8_t* i2cRead(uint8_t registerAddress, uint8_t nbytes) {
uint8_t data[nbytes];
Wire.beginTransmission(IMUAddress);
Wire.write(registerAddress);
Wire.endTransmission(false);
Wire.requestFrom(IMUAddress, nbytes);
for(uint8_t i = 0; i < nbytes; i++)
data[i] = Wire.read();
return data;
}
Bu kod sonucunda Arduino’dan okuduğumuz örnek açı ve ivme bilgilerinin ekran görüntüsü:
How to read data from mpu6050, arduino, read angle data from mpu 6050, code example
merhaba kütüphaneler için link verebilir misiniz lütfen
Merhaba,
I2C kütüphanesi: http://www.findthatcode.com/search-309587-hCODE/source-code-download-i2o-dev.h.htm
MPU6050 kütüphanesi: https://github.com/jrowberg/i2cdevlib/blob/master/Arduino/MPU6050/MPU6050_6Axis_MotionApps20.h
Kalman kütüphanesi: https://github.com/Mrjohns42/RSL/blob/master/arduino-1.0.3/libraries/Kalman/Kalman.h
bu kütüphanelerin hepsini yüklemiş olmama rağmen hata alıyorum:
stray ‘\’ in program
diye
hata sebebi olarak da şu satırı gösteriyor
const uint8_t IMUAddress = 0×68;
Aldığınız hatanın kütüphanelerle ilgili olduğunu sanmıyorum. Şu anda arduino yüklü olmadığından ve malzemelerim yanımda olmadığı için maalesef kontrol edemiyorum. Fakat bu kodların doğru çalıştığından eminim 🙂
kodda “ypr” değişkeni girilmemiş.
birde loop ve setup hataları veriyor
Haklısınız, proje birkaç class’tan oluştuğu için, değişkeni burada belirtmeyi unutmuşum, teşekkürler.
biz bu hataları nasıl düzeltebiliriz peki. ya da doğru kodu paylaşabilir misiniz rica etsek
Dediğim gibi bunlar çalışıyordu zaten, kendim bizzat denedim. Şu anda elimde malzemeler olmadığından tekrar kontrol etme şansım yok maalesef, arkadaşın dediği gibi ypr değişkenini dizi olarak tanımlayın kendiniz, öyle deneyin bir de
bir türlü yapamadım arkadaş neden hep hata veriyor sorun bendemi anlamadım gitti
Merhaba,
Bu mükemmel paylaşım için teşekkür ederim.Bu tarz yazılarınızı daha sıklıkla bekliyoruz.