아두이노 MPU6050 사용법 정리! / DMP기능 사용해보기 / MPU6050 사용법 알아보기 / 가속도센서 / 자이로센서 / MPU6050 / 아두이노 IIC 센서 통합 / i2cdevlib / 라이브러리 다운로드

용가리치킨 2017-02-25 (토) 01:20 1년전 7091  

안녕하세요 메카솔루션입니다. 


이번에는 아두이노 가속도 / 자이로 센서 중에 가장 유명한 센서인 MPU6050의 사용법을 알아보고자 합니다.

 

어째선지 가장 유명하면서도 관련 콘텐츠나 정리되어있는 자료도 많지 않아 제가 접해보면서 알게 된 내용을 조금이나마 정리해보고자 합니다.


pick_manager-30



MPU6050이란?



 

MP6050은 인벤센스(invensense) 사에서 개발한 자이로, 가속도 센서 중의 하나입니다. 쓰기도 간편하고 가격도 저렴한 편이어서 인기가 정말 많은데 다음과 같은 특징을 가지고 있습니다.


특징

내용

단위

부가 설명 

동작전압

5V ~ 3.3V

 

ic 자체는 1.7~ 3.3V이지만 센서 모듈에 레귤레이터가 있습니다.

통신 방식

I²C(I2C,IIC) , SPI


기본 I2C입니다.

자이로 최대 측정값

±(250/500/1000/2000)

(*/sec)

자이로는 각속도입니다.(1초에 몇 도를 회전하는가)

자이로 센서 감도

(131/65.5/32.8/16.4)

(LSB/*/sec)

얼마나 미세하게 측정하느냐입니다.

값이 클수록 감도가 높습니다.

자이로 잡음(오차)

0.01

(dps/√Hz)

자이로 센서에서 발생할 수 있는 오차입니다.

가속도 센서 최대값

±(2/4/8/16)

(g)

가속도 센서 값입니다. 단위는 중력가속도 기준입니다.

자이로 센서 감도

(16384/8192/4096/2048)

(LSB/g)

얼마나 미세하게 측정하느냐입니다.

값이 클수록 감도가 높습니다.


데이터 시트 바로 가기 -> 다운로드


특징으로 정리되어있는 표를 보면 약간의 의문점이 있을 것입니다.


pick_manager-5 

왜 가속도 센서나 자이로 센서의 최댓값 최솟값이 있는 것일까요?


그 이유는 레지스터를 통해 저희가 설정한 대로 자유롭게 최대 측정값들을 변경할 수 있습니다. 그리고 감도들은 최대 측정값들이 변경되면 이에 따라 자동으로 감도가 변경되게 됩니다. 미세한 움직임을 정확히 측정하고 싶다면 최대 측정값을 가장 낮게 설정하고, 크고 빠른 움직임을 측정한다면 최대 측정값을 크게 설정하면 되는 것입니다.




기본적인 회로도 알아보기


우선 아두이노의 회로도를 알아보도록 하겠습니다. 아두이노 보드마다 다른 경우가 있는데 이런 경우에는 다음 블로그의 예제를 참고할 수 있습니다.

http://blog.naver.com/roboholic84/220583168600


 


아두이노의 A4, A5(SDA, SCL) 핀은 I2C 통진 핀으로 아두이노와 MPU6050이 통신하기 위해 연결할 수 있습니다.

레오나르도나 메가 보드와 같이 I2C통신핀이 다른 보드들은 위 링크에서 맞게 연결하는 법을 찾을 수 있습니다.


번외! MPU6050보드를 2개 연결 하고 싶다면??


MPU6050센서를 두 개를 사용하고자 하면 어디에 연결을 해야 하나 당황할 수도 있겠지만 다행히도 방법이 있습니다. MPU6050 의 AD0 핀에 5v를 연결해주면 MPU6050의 I2C 통신 주소를 변경할 수 있습니다.(0x68 -> 0x69)


번외! MPU6050을 납땜을 하지 않고 사용해도 될까?


꼭! 납땜을 하고 사용하는 것을 추천합니다. 납땜을 하지 않아 접촉이 불안정해지면 아두이노 보드와 MPU6050간의 통신에 불량이 생겨 정상적으로 동작하지 않을 수 있습니다.




소스 코드와 라이브러리 알아보기


MPU6050은 라이브러리 없이 간단한 데이터 통신을 통해 원시 값(RAW)을 받아보아서 테스트를 해볼 수도 있고, 라이브러리를 통해 실제 값을 측정해 볼 수도 있습니다.


라이브러리 없이 RAW 값 읽어보기


#include<Wire.h>

const int MPU=0x68;//MPU6050 I2C주소

int AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;

void get6050();


void setup()

{

  Wire.begin();

  Wire.beginTransmission(MPU);

  Wire.write(0x6B);

  Wire.write(0);//MPU6050 을 동작 대기 모드로 변경

  Wire.endTransmission(true);

  Serial.begin(9600);

}

void loop()

{

  get6050();//센서값 갱신

  //받아온 센서값을 출력합니다.

  Serial.print(AcX);

  Serial.print("");

  Serial.print(AcY);

  Serial.print("");

  Serial.print(AcZ);

  Serial.println();

  delay(15);

}

void get6050(){

  Wire.beginTransmission(MPU);//MPU6050 호출

  Wire.write(0x3B);//AcX 레지스터 위치 요청

  Wire.endTransmission(false);

  Wire.requestFrom(MPU,14,true);//14byte의 데이터를 요청

  AcX=Wire.read()<<8|Wire.read();//두개의 나뉘어진 바이트를 하나로 이어붙입니다.

  AcY=Wire.read()<<8|Wire.read();

  AcZ=Wire.read()<<8|Wire.read();

  Tmp=Wire.read()<<8|Wire.read();

  GyX=Wire.read()<<8|Wire.read();

  GyY=Wire.read()<<8|Wire.read();

  GyZ=Wire.read()<<8|Wire.read();

}



소스 코드에 대한 설명은 주석을 참고하면 더 좋습니다.


간단히 요약을 하자면  I2C 통신으로 MPU6050의 모드를 설정하고 MPU6050의 레지스터에 저장된 센서 값을 가져옵니다.


pick_manager-4

(이게 뭐지...)


MPU6050의 데이터시트를 읽고 레지스터 맵을 읽는다 한들 저 레지스터를 어떻게 설정을 해주어야 할지 직접 감이 잡히지 않습니다. 그렇기 때문에 더더욱 라이브러리를 사용해보고 이해를 해보아야 합니다. 




라이브러리 설치하기


우선 라이브러리의 설치가 필요하지요 MPU6050의 라이브러리는 제가 아는 것 중에서는 i2c 통신을 사용하는 센서의 라이브러리 등을 정리하는 개발자 그룹인 i2cDev 의 MPU6050 라이브러리가 가장 완성도가 높습니다.(더 좋은 것이 있다면 덧글에서 추천해주세요~) 


우선 라이브러리를 먼저 다운로드하도록 하겠습니다.

https://github.com/jrowberg/i2cdevlib


위 링크에 찾아가면 초록색 버튼으로 Clone or Download 라 적혀있는 것을 클릭하여 다운로드해줍니다. i2cdevlib-master.zip 이라는 파일을 찾아 볼 수 있는데, 압축을 풀어주면 [Arduino, EFM32 ....]으로 여러 가지 폴더들을 볼 수 있습니다. 이 중에서 우리가 사용하는 개발 보드는 아두이노이기 때문에 바로 아두이노 폴더에 들어가 줍니다. 일단 들어가고 보면 라이브러리가 아주 많은데 다양한 센서들의 라이브러리가 있기 때문에 전부 가져오는 것도 좋지만 중요한 파일들만 챙겨가도록 합시다.



두개의 폴더를 가져와야 하는데 [MPU6050] 과 [I2Cdev] 폴더를 \문서\아두이노\libraries 폴더에 넣어주어야 합니다. 그러면 라이브러리 설치는 완료 됩니다.




라이브러리 예제 실행하기 & 약간의 함수 설명


라이브러리의 설치가 완료되었다면 라이브러리 예제를 실행합니다.


MPU6050의 MPU6050_RAW 예제를 실행해 보도록 합니다. 라이브러리의 예제가 조금 길기 때문에 본문에 함께 적지는 못하지만 소스 코드에 들어있는 함수나 변수들에 대해 간단하게 설명하도록 하겠습니다.


MPU6050 accelgyro;

예제 49번 줄에서 확인이 가능합니다. MPU6050을 제어하기 위해 MPU6050의 객체를 accelgyro 라고 이름을 붙여서 사용하기 시작합니다. 회로도에서 설명한 내용과 같이 I2C 주소를 변경하여 사용한다면 MPU6050 accelgyro(0x69); 를 대신 입력해서 사용이 가능합니다.


accelgyro.initialize();

예제 87번 줄에서 확인이 가능합니다. MPU6050을 사용하기 위해 모드를 설정하는등의 동작을 합니다. 라이브러리 없이 값을 읽어보았을 때 0x6B 를 보내는 등의 동작을 하였는데 이러한 내용이 해당 함수에서 실행됩니다.


accelgyro.testConnection();

예제 91번 줄에서 확인이 가능합니다. MPU6050와 아두이노 보드가 정상적으로 연결이 되었는지 확인을 하기 위해 사용됩니다. 회로도에서 설명한 내용과 같이 납땜을 하지 않고 사용할 경우 이곳에서 동작에 문제가 생길 수 있습니다.


accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

예제 122번 줄에서 확인이 가능합니다. MPU6050에서 가속도 센서 값과 자이로 센서 값의 정보를 받아와서 소스 코드 윗부분에 정의된 ax.... 변수들에 저장을 합니다. 여기서 다른 변수를 넣고자 할 때 앞에 &을 적지 않으면 변수값이 변경되지 않습니다.(이유가 궁금하다면 포인터에 대해 찾아봅시다.)


여기까지가 예제에 사용되었던 중요한 부분들을 정리하였는데 이것저것 아쉬운 감이 있습니다. 초반에 설명해드렸던 최대 측정값에 대한 설정들이 있는데 이에 대한 설명이 없어 아쉬웠을 거라 생각합니다. 그래서 그 부분에 대한 함수와 알면 유용한 함수들을 정리해서 소개해 드리도록 하겠습니다.


accelgyro.setFullScaleGyroRange(MPU6050_GYRO_FS_250);

자이로 센서의 풀스케일 (최대 측정값) 을 설정하는 함수입니다. accelgyro.initialize(); 함수에서 초기화되기 때문에 그다음에 실행되어야 합니다.

MPU6050_GYRO_FS_250

MPU6050_GYRO_FS_500

MPU6050_GYRO_FS_1000

MPU6050_GYRO_FS_2000

의 값을 넣어 변경할 수 있습니다.


accelgyro.setFullScaleAccelRange(MPU6050_ACCEL_FS_2);

가속도 센서의 풀스케일 (최대 측정값) 을 설정하는 함수입니다. accelgyro.initialize(); 함수에서 초기화되기 때문에 그다음에 실행되어야 합니다.

MPU6050_ACCEL_FS_2

MPU6050_ACCEL_FS_4

MPU6050_ACCEL_FS_8

MPU6050_ACCEL_FS_16

의 값을 넣어 변경할 수 있습니다.


accelgyro.setDLPFMode(MPU6050_DLPF_BW_256);

MPU6050의 센서 값의 잡음을 줄이는 방법 중 LOW PASS FILTER 을 적용할 수 있습니다. 

MPU6050_DLPF_BW_256

MPU6050_DLPF_BW_188

MPU6050_DLPF_BW_98

MPU6050_DLPF_BW_42

MPU6050_DLPF_BW_20

MPU6050_DLPF_BW_10

MPU6050_DLPF_BW_5

의 값을 넣어 변경할 수 있습니다. 라이브러리를 읽다가 발견했는데 이런 게 있은 줄은 처음 알았네요!




DMP 사용해 보기


다음은 DMP 예제를 실행해 보도록 하겠습니다.

DMP는 Digital Motion Processor 의 약자로 MPU6050에서 자체적으로 제공하는 자이로 가속도 연산 프로그램입니다.

이를 통해 pitch roll yaw 값을 얻어내거나 쿼터니안, 오일러값을 계산해 낼 수 있습니다.


예제코드는 MPU6050_DMP6 를 실행해 줍니다.


DMP기능을 위해 인터럽트 핀을 사용합니다. MPU6050의 INT 핀을 아두이노 디지털 2번핀에 연결해주세요

실행한 다음, 시리얼 모니터에서 아무 키나 눌러 데이터를 보내주면 동작합니다.


여기서도 간단한 함수만 정리해 보도록 하겠습니다.


mpu.setDMPEnabled(true);

212 번줄 , DMP기능을 활성화합니다.


attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING);

인터럽트가 발생할때마다 실행할 함수를 정해줍니다.


mpu.getFIFOBytes(fifoBuffer, packetSize);

fifoBuffer에 DMP 패킷을 저장합니다. 받아온 패킷의 길이가 부족하거나 넘치게 되어 손실이 생길 경우 정상적인 값을 못 받습니다.


mpu.dmpGetQuaternion(&q, fifoBuffer);

DMP 패킷을 쿼터니언으로 변환합니다.


mpu.dmpGetEuler(euler, &q);

그 쿼터니언을 오일러로 바꿉니다.


mpu.dmpGetGravity(&gravity, &q);

mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);

쿼터니언을 중력계수로 변환하고 쿼터니언과 중력계수로 (pitch roll yaw)를


모바일 버전으로 보기