티스토리 뷰
MPU6050
드론에는 위와 같은 가속도 자이로 센서가 필요합니다. 제가 사용하는 드론에서는 GY-521 MPU6050 모듈이 장착되어 있습니다.
이 센서를 이용하는 목적을 한번 알아보도록 하겠습니다.
센서 이용 목적
드론의 기울어진 정도
회전한 정도
MPU6050에 포함되어 있는 센서
가속도 3축
자이로 3축
온도센서
- 하나의 칩 안에 MEMS 가속도 센서 + MEMS 자이로 센서 포함
- 각 채널에 대해 16Bit 크기의 값을 출력해 주는 ADC 모듈을 가지고 있다. -> 따라서 아주 정확함
- 3축(X, Y, Z축) 채널 값을 동시에 잡을 수 있다.
- Arduino(아두이노)와는 I2C 버스 인터페이스를 통해 연결이 가능
출처 : 이곳
위 블럭도를 보면 각 값들이 ADC 모듈을 거쳐서 센서 레지스터에 저장이 됩니다. 그러면 그 값은 I2C 통신을 통해 아두이노로 전달이 됩니다.
드론이건 자동차건 배이건 무언가가 움직이는 물체이는 Roll, Pitch, Yaw 가 아주 중요한 요소로 작용이 됩니다.
출처 : mythinkg.blogspot.com
자동차의 경우 Roll을 보면 좌로 기울어지든 우로 기우러지는지를 나타내고 Pitch는 차체 앞면이 앞으로 기울어거나 위로 뜨거나를 나타내고 가장 중요한 Yaw는 좌로 갈건지 우로 갈건지를 나타냅니다.
출처 : flit.kr
비행기에서도 마찬가지입니다. Roll은 비행체의 좌,우 기울어짐의 정도를 나타내며 Pitch는 전,후 기울어짐의 정도, Yaw는 수평 회전 정도를 나타냅니다.
이 값들은 모두 MPU-6050 센서를 이용해서 얻을 수 있는 값들 입니다.
아래 그림은 MPU6050 센서를 보여주고 있습니다.
출처 : Meka Wiki
직선축 가속도 센서 이해하기
위 그림을 보면 곡선이 있고 직선이 있습니다. 곡선은 자이로 센서이며 직선은 가속도 센서가 사용합니다.
여기서 직선 3축은 각 축에 대해 중력 방향을 기준으로 잡고 센서의 기울어진 정도를 측정할 수 있으며 중력 방향과 반대방향으로 바라보게 될때 양수(+)값을 얻게 됩니다.
곡선 3축은 직선 3축에 대한 회전 정도를 측정할때 사용이 됩니다. 곡선은 직선축을 중심으로 위에 보여지는 곡선 방향으로 회전을 하게 될때 양수(+)값을 얻게 됩니다.
----------2016.09.10 Update----------
현재 제가 사용하고 있는 드론의 MPU-6050은 전방이 +Y축, 우측이 +X축 입니다.
이해를 하실때 위에서도 설명을 하였다 싶이 직선축은 각 축이 기울어진 정도에 따라서 출력값을 내보내며 곡선축(자이로 센서)는 기울어진 정도에서 얼마나 회전을 하였는지에 대해서 출력값이 보여지게 됩니다.
[Roll, Pitch, Yaw는 가속도, 자이로 센서가 모두 가지고 있는 값 입니다.]
쉽게 예시를 들어보겠습니다. 전투기가 영공에서 비행을 하고 있다고 상상을 해봅시다. 직선 +X가 중력가 반대방향을 보게 되면 가속도 센서 X_Accel(블럭도에서 확인 가능)는 양수 값을 얻게 됩니다. 이 말을 즉 전투기 오른쪽 날개가 중력가 반대방향인 하늘을 바라보게 되면 양수의 값을 가지게 된다는 의미 입니다. 또 전투기가 수직 상승을 하게 되면 직선 +Y가 중력가 반대방향이 되게 됩니다. 그러면 직선 +Y도 양수의 값을 가지게 됩니다.
가속도 센서 값이 계산되는 원리는 센서를 움직이는 방향으로 가속도와 중력 가속도가 더해진 값이 가속도 센서에 표시가 되게 됩니다.
곡선 자이로 센서 이해하기
우리가 중,고등학교 과학시간때 '오른손 법칙'을 배운적이 있을 것 입니다. 이에 관련된 시험문제가 나올때 우리는 시험시간에 다들 오른손을 쫙 피고 이리저리 돌려가며 푼 기억이 있습니다.
자이로 센서와 가속도 센서도 이 방법을 이용하게 됩니다.
그림을 보고 따라해보시면 이해가 될거에요
이제 실제로 아두이노 IDE를 통해서 MPU6050 가속도 자이로 값을 읽어보도록 하겠습니다.
소스코드
Arduino MPU-6050 예제 로 들어가셔서 소스코드를 복사하시면 됩니다.
#include//I2C 통신을 위한 라이브러리 include const int MPU_addr=0x68; // I2C address of the MPU-6050 --> mpu 6050의 i2c 기본주소 int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ; //AC : 가속도 / GY : 자이로 void setup(){ Wire.begin(); //Wire 라이브러리 초기화 Wire.beginTransmission(MPU_addr); Wire.write(0x6B); // PWR_MGMT_1 register Wire.write(0); // set to zero (wakes up the MPU-6050) Wire.endTransmission(true); Serial.begin(9600); } void loop(){ Wire.beginTransmission(MPU_addr); Wire.write(0x3B); // starting with register 0x3B (ACCEL_XOUT_H) Wire.endTransmission(false); Wire.requestFrom(MPU_addr,14,true); // request a total of 14 registers AcX=Wire.read()<<8|Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L) AcY=Wire.read()<<8|Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L) AcZ=Wire.read()<<8|Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L) Tmp=Wire.read()<<8|Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L) GyX=Wire.read()<<8|Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L) GyY=Wire.read()<<8|Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L) GyZ=Wire.read()<<8|Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L) Serial.print("AcX = "); Serial.print(AcX); Serial.print(" | AcY = "); Serial.print(AcY); Serial.print(" | AcZ = "); Serial.print(AcZ); Serial.print(" | Tmp = "); Serial.print(Tmp/340.00+36.53); //equation for temperature in degrees C from datasheet Serial.print(" | GyX = "); Serial.print(GyX); Serial.print(" | GyY = "); Serial.print(GyY); Serial.print(" | GyZ = "); Serial.println(GyZ); delay(333); }
소스코드 해석
아두이노 기본 Wire 라이브러리를 사용했습니다. I2C 통신을 사용하라면 위와 같은 라이브러리를 include를 시켜주어야 합니다. Kocoafab에서 자세하게 설명을 해둔 내용이 있으니 참고하시면 될거 같습니다.
I2C 통신을 하는 모듈은 주소를 가지게 됩니다. 여기서는 MPU_addr을 0x68로 설정을 해주었습니다. MPU-6050의 내부 0x6B번지에는 PWR-MGMT_! 레지스터가 존재합니다.
int16_t 라는 데이터 타입이 나왔습니다. 이는 C++ 내용의 고정 크기 변수 타입인데요 간단하게 정리를 하고 넘어가겠습니다.
- int8_t : 8비트형 정수형
- int16_t : 16비트형 정수형
- int32_t : 32비트형 정수형
- int64_t : 64비트형 정수형
위 변수타입을 왜 16bit로 해주었냐면 제가 맨 위에서 MPU6050 특징을 정리해 둘때 "각 채널에 대한 16bit 크기의 값을 출력해 주는 ADC 모듈을 가지고 있다." 라고 설명을 해두었습니다. 그 이유 떄문에 int16_t로 설정을 해준 것 입니다.
아두이노 IDE에서 setup 함수는 센서 값 등을 초기화 시켜주는 역할을 한다고 이전 포스팅에서 정리를 해두었습니다.
7번째 줄 : begin 즉, I2C 통신을 시작하겠다!(활성화 하겠다) 라는 의미입니다.
8번째 줄 :
kocoafab에 보게 되면 위와 같이 설명이 되어있습니다. 즉, 인자로 주어진(MPU_addr : 0x6B) I2C 슬레이브 모듈과 통신을 시작할 때 호출을 하게 됩니다. 여기서는 0x6B번지 값을 가지는 MPU-6050과 I2C통신을 시작한다는 의미 입니다.
9~10번째 줄 : MPU-6050으로 0x6B, 0을 보내고 있습니다. 이것은 0x6B번지를 0으로 설정해서 MPU-6050을 잠에서 깨운다(?)라는 의미입니다.
또한 Wire.write() 함수를 사용하고 있는데요 이 함수는 전송하고자 하는 1Byte 데이터를 메모리 큐에 저장하는 역할을 합니다.
11번째 줄 : kocoafab
Wire.write() 함수에 의해 큐에 저장된 하나 이상의 바이트 데이터를 슬레이브 모듈로 보내지면서 전송을 끝내는 것 입니다 여기서는 인자값이 true 입니다. 인자값으로 true가 넘어오게 되면 데이터 전송 후 정지 메세지를 보내고 I2C 버스의 제어권을 손뗍니다.
그리고 시리얼 통신 속도를 9600 baud rate로 설정을 해주고 초기 설정을 끝내주었습니다.
이 부분부터는 loop() 부분입니다.
beginTransmission은 제가 위에서 설명을 드렸습니다. 즉, 여기서는 MPU_addr(0x6B)번지로[MPU-6050] 0x3B와 14를 보내고 있습니다. 0x3B 번지는 가속도 자이로 센서 레지스터의 시작 주소를 나타내는 번지입니다. 여기에는 ACCEL_XOUT_H라는 레지스터가 있으며 가속도 센서 X_Accel값의 속도 자이로 센서 값과 온도 센서 값이 저장됩니다.
또한 18번째 줄을 보시게 되면 인자 값이 false로 되어있습니다. 인자값이 false로 넘어오게 되면 true와는 또 다릅니다.
이 경우에는 데이터 전송 후 통신 재시작 메시지를 보내게 됩니다. 그리고 I2C 버스에 대한 제어권을 놓지 않습니다.
따라서 위와 같은 코드로 인해서 19번째 줄에서 Wire.requestFrom()함수를 호출해서 추가적인 데이터를 요구를 하는데요 여기서는 MPY-6050에다가 14byte의 데이터를 요구하고 있습니다.
kocoafab
이렇게 설명이 되어있습니다. 따라서 여기서는 true니까 1의 값 입니다. 즉, 요청완료 후 정지메세지의 전송하라는 뜻 입니다.
그리고 나머지는 데이터를 받고 받은 데이터의 센서 값을 출력하는 내용입니다.
마지막으로 333밀리초동안 지연 시간을 주고 있습니다. 이유는 지연 시간이 매우 짧으면 메세지를 보기가 불편해서 이렇게 넣어주었다고 하는데요. 14바이트의 센서 값을 읽는데 걸리는 시간은 2ms(밀리초)라고 합니다. 센서를 정밀하게 측정하기를 원할 경우 이 코드부분을 주석처리 해주면 됩니다.
'드론' 카테고리의 다른 글
[드론] 프로세싱을 이용해서 Roll, Pitch 테스트하기 (0) | 2016.07.27 |
---|---|
[드론] MPU-6050 가속도 센서 값 해석하기 (0) | 2016.07.12 |
[드론] 프로세싱과 esp8266을 이용해서 드론 모터속도 조절하기_2 (4) | 2016.06.28 |
[드론] 프로세싱과 esp8266을 이용해서 드론 모터속도 조절하기_1 (0) | 2016.06.27 |
[드론] 드론용 모터 소개 및 테스트 (1) | 2016.06.27 |