Cara Menggunakan MPU-6050 GY-521 Pada Arduino

Posted on
Cara Menggunakan MPU-6050 GY-521 Arduino – MPU 6050 merupakan chip yang memiliki fungsi sebagai gyroscope dan accelerometer. Namun, apa perbedaaan gyroscope dan accelerometer tersebut?
Gyroscope adalah perangkat yang menggunakan gravitasi bumi yang berfungsi untuk menentukan rotasi (perputaran). Contoh penggunaan pada smartphone adalah kompas.
Accelerometer adalah perangkat yang tidak menggunakan gravitasi bumi yang berfungsi untuk menentukan orientasi (arah). Contoh penggunaan pada smartphone adalah mengganti wallpaper hanya dengan gerakan.
Berdasarkan datasheet dari chip MPU-6050, sensor terdiri dari 6 axis perangkat pelacakan gerakan.
3 axis untuk gyroscope dan 3 axis untuk accelerometer. Sensor menggunakan protokol I2C untuk berkomunikasi dengan mikrokontroller, namun berbeda dengan keluarganya MPU-6000 menggunakan I2C dan SPI.
Sensor menggunakan 16-bit ADC untuk mendigitalkan sinyal dari gyroscope dan accelerometer. Tegangan operasi chip hanya 2.375V hingga 3.46V.
GY-521 merupakan modul yang berisikan chip MPU-6050 yang telah terintegrasi ic regulator 5V, sehingga dapat menggunakan tegangan 5V.

Library MPU6050 GY521

Untuk dapat menggunakan modul MPU-6050 GY-521 Arduino , kita butuh tiga library. Namanya I2Cdev, MPU6050 dan Average. Silahkan teman-teman download ketiga library berikut:
dan
dan
Jika sudah di download, masukkan library tersebut kedalam arduino IDE dengan cara:
– Buka Arduino IDE
– Klik Sketch > Include Library > Add .ZIP Library
– Pilih library yang telah didownload.
– Kik Ok

Rangkaian MPU6050 GY521

Silahkan teman-teman mengikuti rangkaian MPU-6050 GY-521 Arduino pada gambar berikut:
Cara Menggunakan MPU-6050 GY-521 Pada Arduino

Program MPU6050 GY521

Dibawah sudah saya siapkan program dengan kalibrasi otomatis.

// I2C device class (I2Cdev) demonstrasi sketsa Arduino untuk chip MPU6050
// 10/7/2011 oleh Jeff Rowberg <jeff@rowberg.net>
// Pembaruan harus (semoga) selalu tersedia di https://github.com/jrowberg/i2cdevlib
//
// Changelog:
// 2013-05-08 - menambahkan beberapa format output
// - menambahkan dukungan Fastwire tanpa batas
// 2011-10-07 - rilis awal

/* ==========================================
Kode pustaka perangkat I2Cdev dibawah lisensi MIT
Hak Cipta (c) 2011 Jeff Rowberg

Izin dengan diberikan, gratis, kepada siapa pun yang mendapatkan salinannya
perangkat lunak dan file-file dokumentasi terkait ("Perangkat Lunak"), untuk ditangani
dalam Perangkat Lunak tanpa batasan, termasuk tanpa batasan hak
untuk menggunakan, menyalin, memodifikasi, menggabungkan, menerbitkan, mendistribusikan, mensublisensikan, dan / atau menjual
salinan Perangkat Lunak, dan untuk mengizinkan orang kepada siapa Perangkat Lunak berada
diperlengkapi untuk melakukannya, tunduk pada ketentuan berikut:

Pemberitahuan hak cipta di atas dan pemberitahuan izin harus disertakan dalam
semua salinan atau bagian substansial Perangkat Lunak.

PERANGKAT LUNAK INI DISEDIAKAN "SEBAGAIMANA ADANYA", TANPA JAMINAN APA PUN, BAIK TERSURAT MAUPUN
DITERAPKAN, TAPI TIDAK TERBATAS PADA JAMINAN DAGANG,
KESESUAIAN UNTUK TUJUAN TERTENTU DAN NONINFRINGEMENT. DALAM HAL TIDAK AKAN
PENULIS ATAU PEMEGANG HAK CIPTA BERTANGGUNG JAWAB ATAS KLAIM, KERUSAKAN ATAU LAINNYA
KEWAJIBAN, APAKAH DALAM TINDAKAN KONTRAK, TORT ATAU LAINNYA,
DI LUAR ATAU DALAM HUBUNGAN DENGAN PERANGKAT LUNAK ATAU PENGGUNAAN ATAU HUBUNGAN LAIN DI
PERANGKAT LUNAK.
===============================================
*/

// ================================================
// ========== Cara menyempurnakan nilai============
// ================================================
// Jika ingin kalibrasi lebih akurat, nilai kalibrasi
// harus mendekati nol maka 2 perubahan harus dilakukan di bagian #define di bawah .
// AccStepSize atau GyroStepSize harus dikurangi. misalnya AccStepSize
// secara default 0.2 dapat diubah ke 0.1.
// perubahan kedua harus menjadi nilai "AllowRange" harus diturunkan ke rentang yang dapat diterima
// seperti 50 atau 10.

// ===============================================================
// ================= Format Output Dipilih di s ===============
// ===============================================================
// batalkan komentar "OUTPUT_READABLE_QUATERNION" jika Anda ingin melihat nilai yang sebenarnya
// komponen angka empat dalam format [w, x, y, z] (bukan yang terbaik untuk parsing
// pada remote host seperti Processing atau apalah)
//#define OUTPUT_READABLE_QUATERNION

// batalkan komentar "OUTPUT_READABLE_EULER" jika Anda ingin melihat sudut Euler
// (dalam derajat) dihitung dari angka empat yang berasal dari FIFO.
// Perhatikan bahwa sudut Euler contohnya ada pada gimbal (untuk info lebih lanjut, lihat
// http://en.wikipedia.org/wiki/Gimbal_lock)
//#define OUTPUT_READABLE_EULER

// batalkan komentar "OUTPUT_READABLE_YAWPITCHROLL" jika Anda ingin melihat yaw /
// sudut pitch / roll (dalam derajat) dihitung dari angka empat yang datang
// dari FIFO. Catatan juga membutuhkan perhitungan vektor gravitasi.
// Perhatikan juga bahwa sudut yaw / pitch / roll yang ada pada gimbal (untuk
// info lebih lanjut, lihat: http://en.wikipedia.org/wiki/Gimbal_lock)
#define OUTPUT_READABLE_YAWPITCHROLL

// batalkan komentar "OUTPUT_READABLE_REALACCEL" jika Anda ingin melihat akselerasi
// Kerangka referensi percepatan adalah
// tidak dikompensasi untuk orientasi, jadi + X selalu + X sesuai dengan
// sensor, hanya saja tanpa efek gravitasi. Jika Anda menginginkan akselerasi
// dikompensasi untuk orientasi, pilihlah OUTPUT_READABLE_WORLDACCEL.
//#define OUTPUT_READABLE_REALACCEL

// batalkan komentar "OUTPUT_READABLE_WORLDACCEL" jika Anda ingin melihat akselerasi
// komponen dengan gravitasi dihapus dan disesuaikan untuk kerangka dunia
// referensi (relatif terhadap orientasi awal, karena tidak ada magnetometer
// hadir dalam kasus ). Bisa sangat berguna dalam beberapa kasus.
//#define OUTPUT_READABLE_WORLDACCEL
//=================================================================

// ================================================================
// ============================== Sertakan File ===================
// ================================================================
// I2Cdev dan MPU6050 harus diinstal sebagai pustaka, atau file .cpp / .h yang lain
// untuk kedua kelas harus berada di jalur sertakan proyek Anda
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#include "MPU6050.h"
#include "Average.h"
//=================================================================

// ===============================================================
// =============== I2c komunikasi serial Tentukan ================
// ===============================================================
// Pustaka Arduino Wire diperlukan jika implementasi I2Cdev I2CDEV_ARDUINO_WIRE
// digunakan di I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
//================================================================

//===============================================================
//== Umum + Defsi terkait kalibrasi ===
//===============================================================
#define ModeRange 100
#define StabilityTime 25000 //25 seconds, could be 40secs, only for dmp
#define LED_PIN 13
#define LED_PIN2 8
#define AllowedRange 150 // adalah nilai dalam rentang nol putaran yang dapat diterima dan tidak ada kalibrasi sumbu yang dilakukan.
#define GyroStepSize 1
#define AccStepSize 0.2 // nilai bisa lebih rendah ke 0,1 untuk mendapatkan data yang dikalibrasi lebih dekat ke nol tetapi kemudian kalibrasi akan membutuhkan lebih banyak waktu
#define MaxIncVal 10
//=================================================================

//===============================================================
//== Deklarasi objek MPU6050 ===
//===============================================================
// alamat I2C standar adalah 0x68
// alamat I2C tertentu dapat diteruskan sebagai parameter di s
// Jika tegangan pada AD0 rendah = 0x68 (default untuk papan evaluasi InvenSense)
// Jika tegangan pada AD0 tinggi = 0x69
MPU6050 mpu;
//MPU6050 accelgyro(0x69); // <-- Digunakan tegangan AD0 tingg i
//==============================================================

//==============================================================
//===== Variabel terkait DMP =====
//==============================================================
bool dmpReady = false; // tetapkan true jika DMP t berhasil
uint8_t mpuIntStatus; // memegang byte status interupsi aktual dari MPU
uint8_t devStatus; // mengembalikan status setelah setiap operasi perangkat (0 = berhasil,!0 = jika ada kesalahan)
uint16_t packetSize; // ukuran paket DMP yang diharapkan (standarnya adalah 42 byte)
uint16_t fifoCount; // hitung semua byte saat di FIFO
uint8_t fifoBuffer[64]; // Buffer penyimpanan FIFO
//===============================================================

//===============================================================
//== Variabel terkait keluaran data ===
//===============================================================
// orientasi / gerakan vars
Quaternion q; // [w, x, y, z] wadah quaternion
#if defined(OUTPUT_READABLE_WORLDACCEL) || defined(OUTPUT_READABLE_REALACCEL)
VectorInt16 aa; // [x, y, z] accel pengukuran sensor
#endif

#if defined(OUTPUT_READABLE_WORLDACCEL) || defined(OUTPUT_READABLE_REALACCEL)
VectorInt16 aaReal; // [x, y, z] pengukuran sensor accel bebas gravitasi
#endif

#ifdef OUTPUT_READABLE_WORLDACCEL
VectorInt16 aaWorld; // [x, y, z] pengukuran sensor accel dunia-frame
#endif

#if defined(OUTPUT_READABLE_WORLDACCEL) || defined(OUTPUT_READABLE_REALACCEL) || defined(OUTPUT_READABLE_YAWPITCHROLL)
VectorFloat gravity; // [x, y, z] vektor grafitasi
#endif

#ifdef OUTPUT_READABLE_EULER
float euler[3]; // [psi, theta, phi] Wadah sudut Euler
#endif

#ifdef OUTPUT_READABLE_YAWPITCHROLL
float ypr[3]; // [yaw, pitch, roll] wadah yaw / pitch / roll dan vektor gravitasi
#endif
//===============================================================
//===============================================================
//===== Prototipe fungsi =====
//===============================================================

int16_t getValue(char , char, MPU6050); //lihat defsi fungsi untuk detailnya
bool autocalibrate(char , char, MPU6050);
void SetXAccelOffset(MPU6050, int16_t);
void SetYAccelOffset(MPU6050, int16_t);
void SetZAccelOffset(MPU6050, int16_t);
void SetXGyroOffset(MPU6050, int16_t);
void SetYGyroOffset(MPU6050, int16_t);
void SetZGyroOffset(MPU6050, int16_t);
//================================================================
// ===============================================================
// ====== ROUTINE DETEKSI INTERRUPT =====
// ===============================================================

volatile bool mpuInterrupt = false; //menunjukkan apakah pin interupsi MPU sudah tinggi
void dmpDataReady() {
mpuInterrupt = true;
}

// ================================================================

// ================================================================
// ====== Variabel Umum =====
// ================================================================
char DataFlowBreak;
int16_t CurTempM; //untuk pembacaan suhu sensor
unsigned long currentMillis;
bool waitstatus = false;
Average<int16_t> Mode(ModeRange);
bool blinkState = false;
//=====================================================================

void setup() {
// bergabung dengan bus I2C (perpustakaan I2Cdev tidak melakukan secara otomatis)
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif

Serial.begin(115200);

// sialisasi perangkat
Serial.println("Inisialisasi perangkat I2C...");
mpu.tialize();

// verifikasi koneksi
Serial.println("Mencoba koneksi ke perangkat...");
Serial.println(mpu.testConnection() ? "Koneksi MPU6050 sukses" : "Koneksi MPU6050 gagal");
Serial.println("Kalibrari dimulai...");
Serial.println("Kalibrasi Gyroscope");

if (autocalibrate('g', 'X', mpu)) {
Serial.println("Gyro X axis OK");
} else {
Serial.println("Gyro X axis GAGAL");
}

if (autocalibrate('G', 'y', mpu)) {
Serial.println("Gyro Y axis OK");
} else {
Serial.println("Gyro Y axis GAGAL");
}

if (autocalibrate('g', 'Z', mpu)) {
Serial.println("Gyro Z axis OK");
} else {
Serial.println("Gyro Z axis GAGAL");
}

Serial.println("Kalibrasi Accelerometer");

if (autocalibrate('a', 'x', mpu)) {
Serial.println("Accel X axis OK");
} else {
Serial.println("Accel X axis GAGAL");
}

if (autocalibrate('A', 'Y', mpu)) {
Serial.println("Accel Y axis OK");
} else {
Serial.println("Accel Y axis GAGAL");
}

if (autocalibrate('A', 'Z', mpu)) {
Serial.println("Accel Z axis OK");
} else {
Serial.println("Accel Z axis GAGAL");
}

Serial.println(F("Inisialisasi DMP...")); //Digital Motion Processor
devStatus = mpu.dmpInitialize();

// pastikan itu bekerja (kembalikan 0 jika demikian)
if (devStatus == 0) {
Serial.println(F("Aktifkan DMP..."));
mpu.setDMPEnabled(true);
currentMillis = millis();
Serial.println(F("Aktifkan deteksi interrupt (Arduino external interrupt 0)..."));
attachInterrupt(0, dmpDataReady, RISING);
mpuIntStatus = mpu.getIntStatus();

Serial.println(F("DMP siap! menunggu untuk interrupt pertama..."));
dmpReady = true;

packetSize = mpu.dmpGetFIFOPacketSize();
} else {
Serial.print(F("DMP Initialization failed (code "));
Serial.print(devStatus);
Serial.println(F(")"));
}

pinMode(LED_PIN, OUTPUT);
}

void loop() {
while (1) {
if (!dmpReady) {
continue;

}

mpuInterrupt = false;
mpuIntStatus = mpu.getIntStatus();

// dapatkan hitungan FIFO saat
fifoCount = mpu.getFIFOCount();

// periksa overflow ( seharusnya tidak pernah terjadi kecuali kode kami terlalu tidak efisien)
if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
// reset agar kita bisa melanjutkan dengan bersih
mpu.resetFIFO();
Serial.println(F("FIFO melimpah!"));

// jika tidak, periksa data DMP siap interupsi ( harus sering terjadi)
} else if (mpuIntStatus & 0x02) {
// tunggu panjang data yang tersedia benar, harus menunggu SANGAT singkat
while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();

// baca paket dari FIFO
mpu.getFIFOBytes(fifoBuffer, packetSize);

// lacak jumlah FIFO di s jika ada> 1 paket yang tersedia
// memungkinkan kita segera membaca lebih banyak tanpa harus menunggu interupsi
fifoCount -= packetSize;

#ifdef OUTPUT_READABLE_QUATERNION
// tampilkan nilai angka empat dalam bentuk matriks mudah: w x y z
mpu.dmpGetQuaternion(&q, fifoBuffer);
if ((millis() - currentMillis) <= StabilityTime)
{
if (waitstatus == false) {
Serial.println("Mengunggu untuk stabilitas...");
waitStatus = true;
} else {

}

} else {
Serial.print(millis() - currentMillis); Serial.print("t");
Serial.print("quatt");
Serial.print(q.w);
Serial.print("t");
Serial.print(q.x);
Serial.print("t");
Serial.print(q.y);
Serial.print("t");
Serial.println(q.z);
}

#endif

#ifdef OUTPUT_READABLE_EULER
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetEuler(euler, &q);
if ((millis() - currentMillis) <= StabilityTime)
{
if (waitstatus == false) {
Serial.println("Menunggu untuk stabilitas...");
waitStatus = true;
} else {

}

} else {
Serial.print(millis() - currentMillis); Serial.print("t");
Serial.print("eulert");
Serial.print(euler[0] * 180 / M_PI);
Serial.print("t");
Serial.print(euler[1] * 180 / M_PI);
Serial.print("t");
Serial.println(euler[2] * 180 / M_PI);
}
#endif

#ifdef OUTPUT_READABLE_YAWPITCHROLL
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
if ((millis() - currentMillis) <= StabilityTime)
{
if (waitstatus == false) {
Serial.println("Menunggu untuk stabilitas...");
waitstatus = true;
} else {

}

} else {
Serial.print(millis() - currentMillis); Serial.print("t");
Serial.print("t");
Serial.print("yprt");
Serial.print(ypr[0] * 180 / M_PI);
Serial.print("t");
Serial.print(ypr[1] * 180 / M_PI);
Serial.print("t");
Serial.println(ypr[2] * 180 / M_PI);
}
#endif

#ifdef OUTPUT_READABLE_REALACCEL
// tampilkan akselerasi nyata, disesuaikan untuk menghilangkan gravitasi
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetAccel(&aa, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
if ((millis() - currentMillis) <= StabilityTime)
{
if (waitstatus == false) {
Serial.println("Menunggu untuk stabilitas...");
waitstatus = true;
} else {

}

} else {
Serial.print(millis() - currentMillis); Serial.print("t");
Serial.print("arealt");
Serial.print(aaReal.x);
Serial.print("t");
Serial.print(aaReal.y);
Serial.print("t");
Serial.println(aaReal.z);
}
#endif

#ifdef OUTPUT_READABLE_WORLDACCEL
// tampilkan akselerasi frame-dunia awal, disesuaikan untuk menghilangkan gravitasi
// dan diputar berdasarkan orientasi yang diketahui dari quaternion
mpu.dmpGetQuaternion(&q, fifoBuffer);
mpu.dmpGetAccel(&aa, fifoBuffer);
mpu.dmpGetGravity(&gravity, &q);
mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q);

if ((millis() - currentMillis) <= StabilityTime)
{
if (waitstatus == false) {
Serial.println("Menunggu untuk stabilitas...");
waitstatus = true;
} else {

}

} else {
Serial.print(millis() - currentMillis); Serial.print("t");
Serial.print("aworldt");
Serial.print(aaWorld.x);
Serial.print("t");
Serial.print(aaWorld.y);
Serial.print("t");
Serial.println(aaWorld.z);
}
#endif

if (Serial.available()) {
DataFlowBreak = Serial.read();
if (DataFlowBreak == 'x' || DataFlowBreak == 'X' ) // jika pengguna memasukkan x X loop keluar dan Arduino berhenti mengekstraksi menampilkan data dari mpu.
break;
}

blinkState = !blinkState;
digitalWrite(LED_PIN2, blinkState);
} //stopping the loop here

}
while (1); // berhenti mengirim data dan masuk ke loop tak terbatas
}

// Tujuan dari fungsi adalah untuk mendapatkan nilai dari aliran data yang sangat variabel. Fungsi digunakan
// teknik mode untuk mendapatkan nilai yang sangat akurat. ModeRange didefsikan sebagai jumlah maksimum nilai pada mode mana yang akan diterapkan
// di s pengguna harus melewati a atau g untuk menunjukkan sensor, sumbu yang diperlukan yaitu xy z dan akhirnya objek mpu
// akan mengembalikan 0 jika argumen salah
int16_t getValue(char sensor, char axis, MPU6050 mpu ) {

int ii;
int16_t dummy1, dummy2, dummy3, dummy4, dummy5; //mengabaikan nilai-nilai
int16_t Final;

if (sensor != 'a' && sensor != 'A' && sensor != 'g' && sensor != 'G') { // jika pengguna memasukkan sesuatu kecuali A g atau G menghasilkan false
return 0;
} else if (axis != 'x' && axis != 'X' && axis != 'y' && axis != 'Y' && axis != 'z' && axis != 'Z') { // jika pengguna memasukkan sesuatu kecuali x X y Y z atau Z mengembalikan false
return 0;
}

for (ii = 0; ii <= ModeRange; ii++) {

switch (sensor) { // sensor bisa berupa accelerometer atau giroskop.
case 'a'://acceleormeter adalah a or A
case 'A':
switch (axis) {

case 'x': //axis x
case 'X': //axis x
mpu.getMotion6(&Final, &dummy1, &dummy2, &dummy3, &dummy4, &dummy5);
break;
case 'y': //axis y
case 'Y': //axis Y
mpu.getMotion6(&dummy1, &Final, &dummy2, &dummy3, &dummy4, &dummy5);
break;

case'z': //axis z
case'Z': //axis Z
mpu.getMotion6(&dummy1, &dummy2, &Final, &dummy3, &dummy4, &dummy5);
break;
}
break;
case 'g': //gyrometer adalah g atau G
case 'G':
switch (axis) {

case 'x':
case 'X':
mpu.getMotion6(&dummy3, &dummy4, &dummy5, &Final, &dummy1, &dummy2);
break;
case 'y':
case 'Y':
mpu.getMotion6(&dummy3, &dummy4, &dummy5, &dummy1, &Final, &dummy2);
break;

case'z':
case'Z':
mpu.getMotion6(&dummy3, &dummy4, &dummy5, &dummy1, &dummy2, &Final);
break;
}

break;
}
//delay(1);
delayMicroseconds(500);// alasan utama untuk menggunakan mikrodetik di s adalah untuk mengurangi waktu yang dibutuhkan untuk kalibrasi
Mode.push(Final);

}
Final = Mode.mode();

return Final;
}

// Fungsi mencoba mengkalibrasi Accelerometer dan Giroskop secara otomatis dan mengembalikan true jika operasi berhasil
// Fungsi mengambil dalam 3 argumen 1 adalah sensor ('a' / 'A' = Accelerometer dan 'g' / 'G' = Giroskop), maka argumen ke-2 adalah sumbu untuk claibrate ('X' / 'x', 'Y' / 'y', 'Z' / 'z')
// dan argumen terakhir yang digunakan fungsi adalah objek mpu6050 yang dibuat.
bool autocalibrate(char sensor, char axis, MPU6050 mpu) {
float n = 1;
int16_t talvalue;
int16_t calibrateValue;
int16_t firstoutput, secondoutput;
void (*FuncPointerToSetOffset)(MPU6050, int16_t);
float stepsize = 0.5;
if (sensor != 'a' && sensor != 'A' && sensor != 'g' && sensor != 'G') { //if user enters anything except a A g or G return false
return false;
} else if (axis != 'x' && axis != 'X' && axis != 'y' && axis != 'Y' && axis != 'z' && axis != 'Z') { //if user enters anything except x X y Y z or Z return false
return false;
}

switch (sensor) { //sensor dapat menjadi accelerometer atau gyroscope.
case 'a'://acceleormeter adalah a atau A
case 'A':
stepsize = AccStepSize;
switch (axis)
{ case 'x': //axis x
case 'X': //axis x

FuncPointerToSetOffset = SetXAccelOffset;
break;
case 'y':
case 'Y':

FuncPointerToSetOffset = SetYAccelOffset;
break;

case'z':
case'Z':

FuncPointerToSetOffset = SetZAccelOffset;
break;
}
break;
case 'g': //gyrometer is g or G
case 'G':
stepsize = GyroStepSize;
switch (axis)
{ case 'x': //axis x
case 'X': //axis x

FuncPointerToSetOffset = SetXGyroOffset;
break;
case 'y':
case 'Y':
FuncPointerToSetOffset = SetYGyroOffset;
break;

case'z':
case'Z':
FuncPointerToSetOffset = SetZGyroOffset;
break;
}

break;
}
calibrateValue = getValue(sensor, axis, mpu); // sensor (gyro / accl), sumbu (x y z) dan objek mpu

if (abs(calibrateValue) <= AllowedRange ) // ketika Anda tidak perlu melakukan kalibrasi setelah semua. ketika data mendekati nol dalam rentang yang diijinkan (default 150)
return true;


talvalue = calibrateValue * (-1); // inversi itu penting di s.
calibrateValue = talvalue / n;
FuncPointerToSetOffset(mpu, calibrateValue); // function pointer dengan argumen fungsi
firstoutput = getValue(sensor, axis, mpu); // sensor (gyro / accl), sumbu (x y z) dan objek mpu

while (n < 10) { // di s 10 adalah pilihan acak dan 10 akan memastikan loop tidak berjalan selama lebih dari 50 loop (jika ukuran langkah adalah 0,2)
n += stepsize;
calibrateValue = talvalue / n;
FuncPointerToSetOffset(mpu, calibrateValue);
secondoutput = getValue(sensor, axis, mpu); // sensor (gyro/accl), axis(x y z) and objek mpu
// di s kita periksa apakah nilai karena offset sebelumnya lebih dekat ke nol atau nilai akibat offset saat lebih dekat ke nol
// Selain itu tanda nilai juga diperiksa yaitu saat perubahan kita berhenti (misalnya nilai beralih dari + ve ke -ve)
if ( abs(firstoutput) < abs(secondoutput) && (firstoutput / abs(firstoutput) * secondoutput / abs(secondoutput)) != -1 ) {
n = n - stepsize;
FuncPointerToSetOffset(mpu , talvalue / n); // kita atur nilai sebelumnya karena nilai saat lebih jauh dari tanda nol
break;
} else {
firstoutput = secondoutput; // jika nilai saat lebih rendah dari nilai sebelumnya daripada kami memeriksa nilai berikutnya.
}
}

return true;
} //end of function


// alasan pembuatan fungsi adalah bahwa fungsi pointer digunakan untuk menunjuk ke fungsi .
// function pointer tidak dapat menunjuk ke fungsi anggota statis dari suatu objek yang saya pikir. jadi fungsi harus digunakan.
// selain itu kita dapat menggunakan fungsi-fungsi untuk menambahkan pengurangan konstanta lain untuk kalibrasi offset seperti +16384 untuk Az dapat dimasukkan di s.

void SetXAccelOffset(MPU6050 mpu , int16_t value) {

mpu.setXAccelOffset(value);
}

void SetYAccelOffset(MPU6050 mpu , int16_t value) {

mpu.setYAccelOffset(value);
}

void SetZAccelOffset(MPU6050 mpu , int16_t value) {

mpu.setZAccelOffset(value);
}

void SetXGyroOffset(MPU6050 mpu , int16_t value) {

mpu.setXGyroOffset(value);
}


void SetYGyroOffset(MPU6050 mpu , int16_t value) {

mpu.setYGyroOffset(value);
}


void SetZGyroOffset(MPU6050 mpu , int16_t value) {

mpu.setZGyroOffset(value);
}

Dari program di atas mendapatkan hasil seperti pada gambar dibawah.

Cara Menggunakan MPU-6050 GY-521 Pada Arduino

Semoga bermanfaat.