라이브러리는 아래 링크에서 다운로드하고 아두이노 프로그램 메뉴에서 스케치->라이브러리 포함하기->.ZIP 라이브러리 추가를 누르고, 파일선택창이 나오면 다운받은 라이브러리 파일을 선택하시면 됩니다.

라이브러리

소스코드

아래는 소스코드입니다. 아두이노 IDE에 붙여넣기 하여 컴파일하고 업로드합니다.

#include <LiquidCrystal.h>
#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"

#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
#endif

LiquidCrystal lcd(7,8,9,10,11,12);//RS,E,DB4,DB5,DB6,DB7

MPU6050 mpu;

#define INTERRUPT_PIN 2  // 인터럽트 핀
#define LED_PIN 13 // 아두이노 내장 LED
bool blinkState = false;

// MPU6050 제어 및 상태표시 변수
bool dmpReady = false;  // set true if DMP init was successful
uint8_t mpuIntStatus;   // holds actual interrupt status byte from MPU
uint8_t devStatus;      // return status after each device operation (0 = success, !0 = error)
uint16_t packetSize;    // expected DMP packet size (default is 42 bytes)
uint16_t fifoCount;     // count of all bytes currently in FIFO
uint8_t fifoBuffer[64]; // FIFO storage buffer

// 요롤피치 계산용
Quaternion q;           // [w, x, y, z]         4원법 변수
VectorFloat gravity;    // [x, y, z]            중력 벡터
float ypr[3];           // [yaw, pitch, roll]   요롤피치 변수

int intCount;

volatile bool mpuInterrupt = false;     // MPU6050 인터럽트 발생유무 확인용
// 인터럽트 루틴
void dmpDataReady() {
    mpuInterrupt = true;
}


void setup() {

    #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
        Wire.begin();
        Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
    #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
        Fastwire::setup(400, true);
    #endif

    lcd.begin(16,2);
    intCount = 0;

    Serial.begin(9600);
    while (!Serial);

    //초기화
    Serial.println(F("Initializing I2C devices..."));
    mpu.initialize();
    pinMode(INTERRUPT_PIN, INPUT);

    //MPU6050과 연결상태 확인
    Serial.println(F("Testing device connections..."));
    Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));

    //요롤피치 산출을 위한 DMP(Digital Motion Processor) 초기화
    Serial.println(F("Initializing DMP..."));
    devStatus = mpu.dmpInitialize();

    //옵셋 설정
    mpu.setXGyroOffset(220);
    mpu.setYGyroOffset(76);
    mpu.setZGyroOffset(-85);
    mpu.setZAccelOffset(1688);

    //정상동작여부 확인 0이면 정상
    if (devStatus == 0) {
        //DMP 활성화
        Serial.println(F("Enabling DMP..."));
        mpu.setDMPEnabled(true);

        //아두이노 인터럽트 활성화
        Serial.print(F("Enabling interrupt detection (Arduino external interrupt "));
        Serial.print(digitalPinToInterrupt(INTERRUPT_PIN));
        Serial.println(F(")..."));
        attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);
        mpuIntStatus = mpu.getIntStatus();

        //DMP 대기상태
        Serial.println(F("DMP ready! Waiting for first interrupt..."));
        dmpReady = true;

        // DMP패킷 크기 비교
        packetSize = mpu.dmpGetFIFOPacketSize();
    } else {
        // ERROR!
        // 1 = initial memory load failed
        // 2 = DMP configuration updates failed
        // (if it's going to break, usually the code will be 1)
        Serial.print(F("DMP Initialization failed (code "));
        Serial.print(devStatus);
        Serial.println(F(")"));
    }

    //LED 포트 출력으로 설정
    pinMode(LED_PIN, OUTPUT);
}

void loop() {
    // 오류시 종료
    if (!dmpReady) return;

    //MPU6050 데이터 대기
    while (!mpuInterrupt && fifoCount < packetSize) {
        if (mpuInterrupt && fifoCount < packetSize) {
          // try to get out of the infinite loop 
          fifoCount = mpu.getFIFOCount();
        }  
        // 사용자 프로그램은 여기에 작성
        // .

    }

    // 인터럽트 플래그를 리셋
    mpuInterrupt = false;
    mpuIntStatus = mpu.getIntStatus();

    // get current FIFO count
    fifoCount = mpu.getFIFOCount();

    // check for overflow (this should never happen unless our code is too inefficient)
    if ((mpuIntStatus & _BV(MPU6050_INTERRUPT_FIFO_OFLOW_BIT)) || fifoCount >= 1024) {
        // reset so we can continue cleanly
        mpu.resetFIFO();
        fifoCount = mpu.getFIFOCount();
        Serial.println(F("FIFO overflow!"));

    // otherwise, check for DMP data ready interrupt (this should happen frequently)
    } else if (mpuIntStatus & _BV(MPU6050_INTERRUPT_DMP_INT_BIT)) {
        // wait for correct available data length, should be a VERY short wait
        while (fifoCount < packetSize) fifoCount = mpu.getFIFOCount();

        // read a packet from FIFO
        mpu.getFIFOBytes(fifoBuffer, packetSize);
        
        // track FIFO count here in case there is > 1 packet available
        // (this lets us immediately read more without waiting for an interrupt)
        fifoCount -= packetSize;

        if(intCount++ > 20) //LCD표시 주기 조절용
        {
          intCount = 0;
          showYPR();
        }

    }
}

void showYPR()
{
  
        mpu.dmpGetQuaternion(&q, fifoBuffer);
        mpu.dmpGetGravity(&gravity, &q);
        mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
        lcd.clear();
        lcd.print(" Y     P     R");
        lcd.setCursor(0,1);
        lcd.print(ypr[0] * 180/M_PI,0);
        lcd.setCursor(6,1);
        lcd.print(ypr[1] * 180/M_PI,0);
        lcd.setCursor(12,1);
        lcd.print(ypr[2] * 180/M_PI,0);
        Serial.print("ypr\t");
        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);

        // 데이터 1번 표시할 때마다 LED 상태를 바꿈
        blinkState = !blinkState;
        digitalWrite(LED_PIN, blinkState);
}