Mpu6050 아두 이노 | 【 아두이노 완공 #29 】 Mpu6050 자이로 가속도 센서 , 바로 이 영상으로 시작하세요~! 14 개의 정답

당신은 주제를 찾고 있습니까 “mpu6050 아두 이노 – 【 아두이노 완공 #29 】 MPU6050 자이로 가속도 센서 , 바로 이 영상으로 시작하세요~!“? 다음 카테고리의 웹사이트 https://ppa.giaohangso1.vn 에서 귀하의 모든 질문에 답변해 드립니다: ppa.giaohangso1.vn/blog. 바로 아래에서 답을 찾을 수 있습니다. 작성자 라즈이노 IOT 이(가) 작성한 기사에는 조회수 9,407회 및 좋아요 84개 개의 좋아요가 있습니다.

Table of Contents

mpu6050 아두 이노 주제에 대한 동영상 보기

여기에서 이 주제에 대한 비디오를 시청하십시오. 주의 깊게 살펴보고 읽고 있는 내용에 대한 피드백을 제공하세요!

d여기에서 【 아두이노 완공 #29 】 MPU6050 자이로 가속도 센서 , 바로 이 영상으로 시작하세요~! – mpu6050 아두 이노 주제에 대한 세부정보를 참조하세요

【 영상주요 내용 】
– 기울기 센서(MPU6050) 실습 #1
( RAW 데이터 출력하기 : 00:10 )
– 기울기 센서(MPU6050) 실습 #2
( 가속도센서로 Roll \u0026 Pitch 각도값 얻기 : 02:40 )
– 기울기 센서(MPU6050) 실습 #3
( 자이로센서로 Roll \u0026 Pitch \u0026 Yaw값 얻기 : 06:25 )
– 기울기 센서(MPU6050) 실습 #4
( 상보필터 적용한 각도값 얻기 : 08:25 )
【 추가 설명 자료 및 영상에 포함된 아두이노 code 다운로드 받기 】
https://rasino.tistory.com/325

– Music by –––––––––––––––––––––––––––––––––––
On the Way by Vlad Gluschenko https://soundcloud.com/vgl9
Creative Commons — Attribution 3.0 Unported — CC BY 3.0
Free Download / Stream: http://bit.ly/_OntheWay
Music promoted by Audio Library https://youtu.be/QwwuuvnfBlA
––––––––––––––––––––––––––––––––––––––––––
Music: Hey Now – MK2 https://youtu.be/rioyc5xeYuQ

mpu6050 아두 이노 주제에 대한 자세한 내용은 여기를 참조하세요.

[아두이노 강좌] MPU-6050 6축 기울기 센서 알아보기

3. MPU-6050 6축 기울기 센서로 기울기 측정하기 ▷ 아두이노와 MPU6050을 연결하여 센서를 움직였을 때 변화하는 가속도와 자이로 센서 값을

+ 여기에 표시

Source: blog.naver.com

Date Published: 12/25/2021

View: 9187

MPU-6050 가속도/자이로 센서 제어 (아두이노) – Steemit

MPU-6050 가속도/자이로 센서 제어 (아두이노) 온라인 가상시뮬레이터 : 참고 출처 : 오일러의 각 : 상보필터 : 필만필터 : MPU-6050 데이터시트 : 포스트… by …

+ 여기에 더 보기

Source: steemit.com

Date Published: 11/9/2022

View: 9437

아두이노 MPU6050 사용법 정리 by makeshare.org – N2 정보기술

안녕하세요 메카솔루션입니다. 이번에는 아두이노 가속도 / 자이로 센서 중에 가장 유명한 센서인 MPU6050의 사용법을 알아보고자 …

+ 여기에 자세히 보기

Source: n2infotech.co.kr

Date Published: 10/30/2022

View: 4089

아두이노 MPU6050 자이로 가속도센서 실습 – 싸이피아SCIPIA

이 센서는 3축 자이로스코프와 3축 가속도계를 모두 포함하고 있으며 독립적으로 측정이 가능합니다. I2C 포트를 통해 아두이노 보드와 통신합니다. MPU6050 센서는 드론, …

+ 여기에 자세히 보기

Source: scipia.co.kr

Date Published: 7/26/2021

View: 1481

[아두이노]mpu6050 을 이용하여 2축 서보모터 제어하기

아두이노와 같은 마이크로 칩을 이용하여 무엇인가를 해보다 보면 정말 놀라운 경험들을 많이 하게 됩니다. 그 중 하나가 바로 mpu6050 같은 센서가 …

+ 더 읽기

Source: diy-dev-design.tistory.com

Date Published: 12/22/2021

View: 5011

[아두이노] MPU-6050 센서 + processing 연결 제어 – 코드다

[아두이노] MPU-6050 센서 + processing 연결 제어 온라인 가상시뮬레이터 : https://www.tinkercad.com 참고 출처 : 오일러의 각 …

+ 자세한 내용은 여기를 클릭하십시오

Source: codeda.tistory.com

Date Published: 8/12/2022

View: 8056

티스토리 – 라즈이노 iOT

(GY-521/MPU6050 센서 실습 #1). 티스토리. 【 아두이노모듈#30】 #1.기울기 센서(6축 가속도& …

+ 여기에 자세히 보기

Source: rasino.tistory.com

Date Published: 10/4/2022

View: 5801

아두이노 자이로센서(MPU6050센서) 써보기

아두이노 가속도 / 자이로 센서 중에 가장 유명한 센서인 MPU6050을 가져와봤습니다. 동작전압: 2.375V~3.46V (수정) 통신방식: I²C(I2C,IIC) …

+ 여기에 더 보기

Source: blog.tomclansys.com

Date Published: 7/21/2021

View: 8016

MPU6050 가속도 센서, 자이로 센서로 측정값 읽어 보기

MPU6050에는 1024바이트 FIFO 버퍼가 있는데 만일 센서 값을 읽어서 버퍼에 저장하면 Arduino에 Interrupt 신호를 보내고 아두이노는 이 신호를 통해 …

+ 여기에 더 보기

Source: scribblinganything.tistory.com

Date Published: 6/23/2022

View: 9755

아두이노 기울기센서(6축 가속도+자이로) MPU-6050 MPU6050

아두이노 전문 교육쇼핑몰 에듀이노, 아두이노보드, 쉴드, 모듈, 키트, 로봇, 전자부품 등 판매.

+ 여기를 클릭

Source: eduino.kr

Date Published: 3/29/2022

View: 8894

주제와 관련된 이미지 mpu6050 아두 이노

주제와 관련된 더 많은 사진을 참조하십시오 【 아두이노 완공 #29 】 MPU6050 자이로 가속도 센서 , 바로 이 영상으로 시작하세요~!. 댓글에서 더 많은 관련 이미지를 보거나 필요한 경우 더 많은 관련 기사를 볼 수 있습니다.

【 아두이노 완공 #29 】 MPU6050 자이로 가속도 센서 , 바로 이 영상으로 시작하세요~!
【 아두이노 완공 #29 】 MPU6050 자이로 가속도 센서 , 바로 이 영상으로 시작하세요~!

주제에 대한 기사 평가 mpu6050 아두 이노

  • Author: 라즈이노 IOT
  • Views: 조회수 9,407회
  • Likes: 좋아요 84개
  • Date Published: 2021. 1. 15.
  • Video Url link: https://www.youtube.com/watch?v=BTpwAFfeg0I

[아두이노 강좌] MPU-6050 6축 기울기 센서 알아보기

▶ 가속도는 시간에 대한 속도 변화의 비율을 뜻 합니다. 가속도센서는 가속도 자체를 측정하는 것이 아닌 중력가속도를 이용하여 가속도를 측정하게 됩니다. 중력 가속도가 3축으로

얼만큼의 영향을 주었는가를 측정하여 센서의 기울어진 정도를 확인할 수 있습니다.

가속도센서의 민감도는 매우 높아 정적인 상태에서만 정확한 기울기를 측정할 수 있다는

한계를 가지고 있습니다.

▶ 자이로 센서는 각속도를 측정 할 수 있는 센서로서 3축의 물리 량을 측정하여 센서의 움직임을 감지하고 기울기를 측정할 수 있습니다. 가속도 센서의 비해 비교적 안정적인 값이 출력되지만

각도를 계산하는 과정에서 사용되는 적분에 의해 시간이 지날수록 누적된 오차가 발생하게

됩니다. 따라서 가속도 센서와 자이로 센서의 장점을 적절히 혼합하여 센서를 사용하는 것이

중요합니다.

MPU-6050 가속도/자이로 센서 제어 (아두이노) — Steemit

MPU-6050 가속도/자이로 센서 제어 (아두이노)

오늘은 MPU-6050 가속도/자이로 센서를 이용하여 실험하는 시간을 갖도록 하겠습니다. 자이로 센서를 사용하려면 오일러의 공식을 알아야 하고 오일러의 공식 이해하셔야 하고 각속도와 오일러의 변화율 공식과 오일러의 각을 이해하기 위해서 피치, 롤, 요와 같은 용어적 의미와 공식을 알아야 합니다. 그리고 회전각을 구할 때 대표적인 2개의 필터가 있는데 상보필터와 칼만필터 중 하나 정도는 공식을 알아야 합니다. 이처럼 수학적인 공식을 알아야 제대로 사용할 수 있습니다. 나중에 깊게 공부할 때는 모두 알아야 할 내용인데 입문자에게는 버거운 내용입니다. 하지만 이 모든것을 몰라도 사용할 수 있습니다. MPU-6050라이브러리르 사용하면 쉽게 회전각을 구할 수 있습니다. 바로 라이브러리를 사용하는 것보다 먼저 간단히 어떤 값들이 MPU-6050 모듈을 통해 측정되는지 살펴봐야 겠지요. 우선, 간단히 MPU-6050에 대해서 살펴보고 실험해보도록 하죠.

1. MPU-6050 가속도/자이로 센서

MPU-6050 모듈은 가속도/자이로를 측정할 수 있는 센서입니다. 가속도는 지구 중력을 기준으로 x, y, z 축의 가속도 크기를 구할 수 있으면 자이로(각속도)는 시간당 x, y, z 축의 회전속도 속도를 구할 수 있습니다.

MPU-6050 모듈에서 측정된 값은 바로 회전각으로 이해하기 힘듭니다. 그래서 계산이 필요하는 데 오일러의 각 공식을 알아야 합니다. 아래 링크된 위키백과사전에서 한번 읽어주시기 바랍니다.

오일러의 각 : https://ko.wikipedia.org/wiki/%EC%98%A4%EC%9D%BC%EB%9F%AC_%EA%B0%81

3차원 회전 좌표계로 X축 회전을 롤, Y축 회전을 피치, Z축 회전을 요라고 합니다. 롤,피치,요에 대한 계산 공식이 따로 있습니다.

상보필터과 칼만필터는 회전각을 구할때 필요한 필터입니다.

아래는 상보필터의 공식입니다.

angle = 0.98*(angle+자이로값*dt)+0.02*(가속도값) [angle-출력각, dt-적분할 시간]

출처 : http://mechasolutionwiki.com/index.php?title=%EC%83%81%EB%B3%B4%ED%95%84%ED%84%B0

칼만필터은 아래 위키백과에 가셔서 공식을 살펴보시기 바랍니다.

https://ko.wikipedia.org/wiki/%EC%B9%BC%EB%A7%8C_%ED%95%84%ED%84%B0

대표적으로 이 두개의 필터로 회전각을 구하게 되는데 나중에 실험에서는 상보필터로 된 라이브러리를 이용할 예정입니다.

아래 MPU-6050 데이터 시트에 가셔서 MPU-6050에 대해서 알아두시기 바랍니다.

https://www.invensense.com/wp-content/uploads/2015/02/MPU-6000-Datasheet1.pdf

2. MPU-6050 가속도/자이로 센서 구조

MPU-6050 모듈은 가속도 (x,y,z)와 자이로(각속도) (x,y,z)의 값과 온도 값을 얻을 수 있습니다.

MPU-6050 모듈은 I2C 통신으로 14개의 레지지스터 값을 아두이노로 보내고 데이터는 16bit로 구성된 총 7개의 데이터를 얻게 됩니다.

MPU-6050 모듈의 핀에 대해서 위표를 잘 살펴보시고 인터럽트핀은 아두이노우노의 경우는 인터럽트 핀이 2번이기에 사용하실 경우 2번 핀에 연결하시면 되고 사용하는 아두이노보드에 따라 해당 I2C핀과 인터럽트 핀에 맞게 연결하시면 됩니다.

3. MPU-6050 가속도/자이로 회로도

준비물 : MPU-6050 모듈, 아두이노우노

내용 : I2C 통신을 위해 A4(SDA), A5(SCL)핀에 연결하시오

I2C핀만 주의해서 연결하시면 됩니다.

4. 코딩

참고 소스 출처 : https://playground.arduino.cc/Main/MPU-6050

우선 기본 라이브러리 없이 순수 MPU-6050 모듈에서 측정되는 값이 어떤 값들이 출력되는지 살펴보도록 하겟습니다.

위 링크된 MPU-6050소스에 대해 간단히 살펴보겠습니다.

[소스]

// By Arduino User JohnChi

#include const int MPU_addr=0x68; // I2C address of the MPU-6050 int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ; void setup(){ Wire.begin(); 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); } MPU-6050의 I2C 주소는 '0x6B'입니다. int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ; 16bit int형 자료형으로 가속도 3개, 온도 1개, 자이로 3개의 변수를 선언합니다. 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); beginTransmission()함수로 '0x6B'주소로 I2C 슬레이브 디바이스로 전송을 시작합니다. 그리고 버스가 연결되면 '0x6B' 보내고 다시 '0'을 보내고 나서 endTransmission(true)함수로 버스를 해제하는 메세지를 보냅니다. 초기화 수행합니다. Wire.beginTransmission(MPU_addr); //MPU-6050 '0x6B'주소 시작 Wire.write(0x3B); // 0x3B 읽을 rigister주소 Wire.endTransmission(false) //버스를 연결 활성화 Wire.requestFrom(MPU_addr,14,true) //데이터 요청하는데 14 레지스터 값을 요청 이렇게 해서, Wire.read()함수를 이용해서 실제로 MPU-6050에서 값을 읽게 됩니다. 0x3B~0x48의 레지스터값을 읽어와서 가속도, 온도, 자이로 값을 만들어 내게 됩니다. Wire.read()<<8|Wire.read(); '0x3B' 레지스터 값을 왼쪽으로 8bit 이동시키고 '0x3C' 레지스터 값을 비트OR 연산을 수행합니다. 이 식을 통해서 2개의 레지스터 값을 합치게 됩니다. 예를 들어 임의의 값 A, B가 있을때 위 식으로 계산한다면 더 쉽게 살펴보면은, 비트OR 연산은 둘중 하나가 1이면 결과가 1이 나오는 연산입니다. 이렇게 14개의 레지스트값을 2개씩 이 수식을 통해서 가속도(x,y,z), 온도, 자이로(x,y,z)값을 순차적으로 Wire.read()함수를 14번 읽어서 연산을 수행하여 값을 얻게 됩니다. 그 값을 시리얼모니터로 출력하기 때문에 순수 MPU-6050 모듈에서 추출한 값입니다. [결과] 5. 결과 실제 영상으로 살펴보면 MPU-6050 가속도/자이로센서를 움직일 때마다 가속도 AcX, AcY, AcZ 값과 자이로 GyX, GyY, GyZ 값이 나옵니다. 추가로 Tmp(온도)값은 온도를 계산식이 간단해서 값으로 나오고 가속도와 자이로는 우리가 각도로 느끼기에는 다소 어려운 수치로 출력이 이뤄집니다. 이 값으로 나중에 계산해서 회전각을 구하게 되는데 우선 어떤 값들이 찍히는지는 알아야 계산을 할 수 있겠죠. 나중에 위 링크된 곳에 가셔서 한번 공식에 대해서 자세히 배워보시기 바랍니다.

아두이노 MPU6050 사용법 정리 by makeshare.org

이번에는 아두이노 가속도 / 자이로 센서 중에 가장 유명한 센서인 MPU6050의 사용법을 알아보고자 합니다. 가장 저렴한 MPU6050와 기술 문의 바로가기 어째선지 가장 유명하면서도 관련 콘텐츠나 정리되어있는 자료도 많지 않아 제가 접해보면서 알게 된 내용을 조금이나마 정리해보고자 합니다. 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) 얼마나 미세하게 측정하느냐입니다. 값이 클수록 감도가 높습니다. 데이터 시트 바로 가기 -> 다운로드 특징으로 정리되어있는 표를 보면 약간의 의문점이 있을 것입니다. 왜 가속도 센서나 자이로 센서의 최댓값 최솟값이 있는 것일까요? 그 이유는 레지스터를 통해 저희가 설정한 대로 자유롭게 최대 측정값들을 변경할 수 있습니다. 그리고 감도들은 최대 측정값들이 변경되면 이에 따라 자동으로 감도가 변경되게 됩니다. 미세한 움직임을 정확히 측정하고 싶다면 최대 측정값을 가장 낮게 설정하고, 크고 빠른 움직임을 측정한다면 최대 측정값을 크게 설정하면 되는 것입니다. 기본적인 회로도 알아보기 우선 아두이노의 회로도를 알아보도록 하겠습니다. 아두이노 보드마다 다른 경우가 있는데 이런 경우에는 다음 블로그의 예제를 참고할 수 있습니다. 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 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의 레지스터에 저장된 센서 값을 가져옵니다. MPU6050의 데이터시트를 읽고 레지스터 맵을 읽는다 한들 저 레지스터를 어떻게 설정을 해주어야 할지 직접 감이 잡히지 않습니다. 그렇기 때문에 더더욱 라이브러리를 사용해보고 이해를 해보아야 합니다. 라이브러리 설치하기 우선 라이브러리의 설치가 필요하지요 MPU6050의 라이브러리는 제가 아는 것 중에서는 i2c 통신을 사용하는 센서의 라이브러리 등을 정리하는 개발자 그룹인 i2cDev 의 MPU6050 라이브러리가 가장 완성도가 높습니다.(더 좋은 것이 있다면 덧글에서 추천해주세요~) 우선 라이브러리를 먼저 다운로드하도록 하겠습 니다 위 링크에 찾아가면 초록색 버튼으로 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);

아두이노 MPU6050 자이로 가속도센서 실습

MPU6050 자이로 가속도센서는 단일 칩에 MEMS(마이크로 전자 기계 시스템) 가속계와 MEMS 자이로를 포함하고 있습니다. 이 센서는 3축 자이로스코프와 3축 가속도계를 모두 포함하고 있으며 독립적으로 측정이 가능합니다. I2C 포트를 통해 아두이노 보드와 통신합니다.

MPU6050 센서는 드론, RC비행기, 짐벌 등과 같이 주로 3차원 위치제어를 통해 균형을 잡을 필요가 있는 곳에 사용됩니다. 이를 제어하기 위한 3가지 요소가 요(Yaw), 롤(Roll), 피치(Pitch)입니다.

아래 그림은 비행기의 무게중심에서 직각으로 교차하는 세 개의 선을 그리고 여기에 요(Yaw), 롤(Roll), 피치(Pitch)의 개념을 표시하였습니다.

– 롤(Roll)은 앞뒤 축을 중심으로 회전하는 것을 말합니다.

– 피치(Pitch)는 측면 축 주변으로 회전하는 것을 말합니다. 주로 고도 변경을 위해 사용됩니다.

– 요(Yaw)는 수직축을 중심으로 회전하는 것을 말합니다.

아래는 아두이노 보드와 MPU6050을 사용하여 LCD에 요(Yaw), 롤(Roll), 피치(Pitch) 값을 표시하는 회로입니다.

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

라이브러리

소스코드

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

#include #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); }

[아두이노]mpu6050 을 이용하여 2축 서보모터 제어하기

반응형

아두이노와 같은 마이크로 칩을 이용하여 무엇인가를 해보다 보면 정말 놀라운 경험들을 많이 하게 됩니다. 그 중 하나가 바로 mpu6050 같은 센서가 될 수 있겠습니다.

요 조그만 칩을 이용하여 기울어진 정도나 각도, 나침반과 같은 방향 등을 알아낼 수 있다니 놀랍지 않으신가요?

요 조그만 칩이라고 했는데 이미지는 엄청 큰 mpu6050

오늘 소개해 드릴 내용은 RC Headtracking FPV 만들기의 두번째 스탭인 6축 자이로 센서를 이용한 움직임 신호 받기와 해당 신호를 이용 하여 2축 서보모터를 제어하는 내용 입니다.

헤드트래킹 무선 FPV 를 만들기 위하여 지난 포스트에서 2축 서보모터 마운트를 아주~ 아~~~주 간단하게 만드는 방법을 소개해 드렸었는데요, 해당 프레임에 부착한 서보모터를 이번 시간에 자이로 센서를 이용하여 제어를 해보도록 하겠습니다.

2022.01.31 – [DIY/Arduino] – 2축 서보모터 초간단 제어하기, 간단한 프레임 제작까지

먼저 라이브러리를 받아야 할텐데요, 아래 첨부된 라이브러리를 다운 받으셔서 바로 내문서- Arduino-libraries 폴더에 압축을 해제하여 넣으시면 됩니다.

MPU6050.zip 0.10MB I2Cdev.zip 0.01MB

요렇게 넣으면 됩니다.

혹시 Wire.h 라이브러리가 없으시면 아래 파일도 다운 받으시면 됩니다.

Wire.zip 0.01MB

반응형

mpu6050 라이브러리를 받으시면 예제 소스코드가 들어있을 텐데요, 저는 여기서 시작 이후 실제 회전하는 값, 즉 상대 회전 값만을 이용할 계획이고 아래의 코드를 이용하여 회전 값을 추출할 계획입니다. 본 포스트에서 소개해 드리는 예제 외에도 라이브러리가 제공하는 예제 코드를 실행해보시면 다른 창작품 제작에도 도움이 될 수 있을 것 같습니다. ^^

기존 조이스틱 대신 이번에는 mpu6050 보드를 연결해야 하는데요. I2C 방식으로 연결할 것이므로 선은 4가닥만 있으면 되며 vcc 는 3.3v 에 연결해 주시고, GND 는 아두이노의 GND 에 연결, SDA 는 아두이노의 A4 번에 SCL 은 아두이노의 A5에 연결하시면 됩니다. (다른 핀은 안됩니다. 정확히 A4, A5에 연결해 주셔야 합니다)

코딩을 해보자

mpu6050 에 대한 자세한 내용은 이미 여러분들께서 다루어 주시고 있으므로 저는 실제 이번 프로젝트에 사용한 코드만 보여드리도록 하겠습니다.

#include #include “I2Cdev.h” #include “MPU6050_6Axis_MotionApps_V6_12.h” #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE #include “Wire.h” #endif MPU6050 mpu; #define OUTPUT_READABLE_YAWPITCHROLL #define INTERRUPT_PIN 2 // use pin 2 on Arduino Uno & most boards #define LED_PIN 13 // (Arduino is 13, Teensy is 11, Teensy++ is 6) bool blinkState = false; // MPU control/status vars 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 // orientation/motion vars Quaternion q; // [w, x, y, z] quaternion container VectorInt16 aa; // [x, y, z] accel sensor measurements VectorInt16 gy; // [x, y, z] gyro sensor measurements VectorInt16 aaReal; // [x, y, z] gravity-free accel sensor measurements VectorInt16 aaWorld; // [x, y, z] world-frame accel sensor measurements VectorFloat gravity; // [x, y, z] gravity vector float euler[3]; // [psi, theta, phi] Euler angle container float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high void dmpDataReady() { mpuInterrupt = true; } Servo myservo_LR; // streering servo Servo myservo_UD; // 2speed gear box servo int pin_servo_LR = 9; int pin_servo_UD = 10; int pin_x = A3; int pin_y = A4; int angle_x = 512 ; int angle_y = 512 ; void setup() { // join I2C bus (I2Cdev library doesn’t do this automatically) #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 Serial.begin(115200); while (!Serial); // wait for Leonardo enumeration, others continue immediately // initialize device Serial.println(F(“Initializing I2C devices…”)); mpu.initialize(); pinMode(INTERRUPT_PIN, INPUT); // verify connection Serial.println(F(“Testing device connections…”)); Serial.println(mpu.testConnection() ? F(“MPU6050 connection successful”) : F(“MPU6050 connection failed”)); // wait for ready Serial.println(F(”

Send any character to begin DMP programming and demo: “)); //while (Serial.available() && Serial.read()); // empty buffer //while (!Serial.available()); // wait for data //while (Serial.available() && Serial.read()); // empty buffer again // load and configure the DMP Serial.println(F(“Initializing DMP…”)); devStatus = mpu.dmpInitialize(); // supply your own gyro offsets here, scaled for min sensitivity mpu.setXGyroOffset(51); mpu.setYGyroOffset(8); mpu.setZGyroOffset(21); mpu.setXAccelOffset(1150); mpu.setYAccelOffset(-50); mpu.setZAccelOffset(1060); // make sure it worked (returns 0 if so) if (devStatus == 0) { // Calibration Time: generate offsets and calibrate our MPU6050 mpu.CalibrateAccel(6); mpu.CalibrateGyro(6); Serial.println(); mpu.PrintActiveOffsets(); // turn on the DMP, now that it’s ready Serial.println(F(“Enabling DMP…”)); mpu.setDMPEnabled(true); // enable Arduino interrupt detection 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(); // set our DMP Ready flag so the main loop() function knows it’s okay to use it Serial.println(F(“DMP ready! Waiting for first interrupt…”)); dmpReady = true; // get expected DMP packet size for later comparison 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(“)”)); } myservo_LR.attach(pin_servo_LR); myservo_LR.write (90); myservo_UD.attach(pin_servo_UD); myservo_UD.write (90); } void loop() { // if programming failed, don’t try to do anything if (!dmpReady) return; // read a packet from FIFO if (mpu.dmpGetCurrentFIFOPacket(fifoBuffer)) { // Get the Latest packet #ifdef OUTPUT_READABLE_YAWPITCHROLL // display Euler angles in degrees mpu.dmpGetQuaternion(&q, fifoBuffer); mpu.dmpGetGravity(&gravity, &q); mpu.dmpGetYawPitchRoll(ypr, &q, &gravity); float angle_x = (ypr[0] * 180 / M_PI) * -1 + 90 ; //* -1 + 90; float angle_y = (ypr[1] * 180 / M_PI) + 90 ; //* -1 + 30; if (angle_y < 60) angle_y = 60; if (angle_y > 120) angle_y = 120; if (angle_x < 30) angle_x = 30; if (angle_x > 150) angle_x = 150; myservo_LR.write (angle_x); myservo_UD.write (angle_y); Serial.print(“ypr\tx:”); Serial.print(int(angle_x)); Serial.print(“\ty:”); Serial.print(int(angle_y)); Serial.print(“\t”); #endif } Serial.println(“.”); delay(10); }

코드가 조금 길어졌기는 하지만 기존 첫번째 과정에 mpu6050 관련 코드가 추가되었고 크게 달라진것은 없습니다. mpu6050 관련된 상세한 코드는 저도 잘 모르고요. 그냥 예제에서 긁어온 코드입니다. ^^;; (불필요한 내용이 들어 있을 수도 있고요… 어쨌든 위의 코드면 잘 실행됩니다.)

위 코드에서 아래 부분이 실제 회전 값을 받아서 내가 원하는 각도로 세팅하는 부분인데요. 입력 값이 최초 실행된 위치로부터의 상대 값이므로 가만히 있으면 0 이 들어오게 됩니다. 그러므로 기준이 되는 앵글을 더해주면 기준이 되는 앵글에 + – 로 각도가 변경되게 되며 저의 x 위치에 -1 이 들어있는 것은 서보 모터의 설치 방향 때문에 방향을 뒤집어 주기 위함입니다. Y 값 역시 서보모터의 방향이 저와 다른 방향으로 설치되어 반대로 움직인다면 센서의 값에 -1 을 곱해 주시면 됩니다.

float angle_x = (ypr[0] * 180 / M_PI) * -1 + 90 ; //* -1 + 90; float angle_y = (ypr[1] * 180 / M_PI) + 90 ; //* -1 + 30; if (angle_y < 60) angle_y = 60; if (angle_y > 120) angle_y = 120; if (angle_x < 30) angle_x = 30; if (angle_x > 150) angle_x = 150;

어쨌든 서보모터 제어를 위한 부분은 이전에 소개해 드린 코드 그대로 가져왔고요, 회전 정보를 받아 서보모터로 전달하는 과정에서 축의 기준위치, 방향 등을 변경해주기 위하여 위와 같이 약간의 코드가 추가되었습니다. if 구문을 이용하여 입력된 값 + 기준값이 모터의 최대 회전 범위 보다 크다면 최대 회전 범위의 값으로 설정을 해주면 됩니다.

저는 기준위치를 서보의 상하, 좌우 90도를 기준으로 설정하였고 상하로는 ±30도씩, 좌우로는 ±60도씩 움직일 수 있도록 하였습니다.

참 쉽죠?

이것은 동영상은 아닙니다. 

과연 잘 동작할런지??

자 구동 되는 모습은 아래와 같습니다.

아주 잘 되죠?

기존 조이스틱이 움직이는 범위에 비하여 출력되는 범위가 리니어 하지 않은지 휙휙 움직이던것에 비하면 아주 아주 잘 동작하는 것을 확인할 수 있습니다.

이렇게 mpu6050 6축 지자기센서를 이용하여 2축 서보모터를 제어하는 것까지 마쳤습니다.

생각보다 어렵지 않죠?

다음은 이제 대망의 무선 입니다.

다음 포스트를 기대해 주세요.

2022.01.31 – [DIY/Arduino] – [아두이노]NRF24L01을 이용하여 무선으로 mpu6050 신호 전달하기

2022.01.25 – [DIY/RC] – 20년된 엔진 RC 카 전동화 해보자 [kyosho inferno]

2022.01.31 – [DIY/Arduino] – 2축 서보모터 초간단 제어하기, 간단한 프레임 제작까지

2020.11.29 – [DIY/RC] – 1/24 완벽한 RC 카 RGT ADVENTURE

반응형

라즈이노 iOT :: 【 아두이노모듈#30】 #1.기울기 센서(6축 가속도&자이로)에 대해 알아봅시다.(GY-521/MPU6050 센서 실습 #1)

반응형

【 아두이노 모듈 #30 】 #1. 기울기 센서 ( 6축 가속도 & 자이로 ) 에 대해 알아봅시다.

【 기울기 센서 개요 】

자이로 센서(Gyro Sensor)의 원리는 자이로스코프가 내장된 물체가 회전 운동을 하면 생기는 회전 반발력을 측정하여 전기신호로 바꾸어 출력하고 이를 수치화하여 활용하게 됩니다. 그래서 기울기 센서는 가속도 센서와 자이로 센서의 기능을 통합하여 자세나 위치를 추정할 수 있는 장치를 말하며, 이를 활용한 항공기 및 배(Ship) 등에 사용되는 관성항법장치(INS)는 이동거리와 방향까지 추정할 수 있도록 되어 있습니다.

▶ 주요 활용분야 :

센서 주요활용분야: 드론/AR스마트안경/VR고글/나인봇/핏빗, 미밴드/스마트워치/전자수평계 등

– 드론 : 비행 중인 드론은 현재의 기울기나 위치 파악은 물론이며, 특정 위치에서의 고정 비행을 할 경우 바람 등으로 인하여 원래의 위치와 자세를 유지하는 기능이 필요한데, 가속도 센서와 자이로 센서가 각각 중력가속도와 각속도를 측정하여 얼마나 기울어졌는지를 파악하여 보정할 수 있도록 해줍니다.

– VR/AR : 대표적 VR제품인 오큘러스 고글이나 구글 스마트 안경과 같은 AR 제품의 경우 사용자의 머리(얼굴 방향) 움직임이 있을 경우 자이로 센서를 이용하여 회전을 인식하거나 물체와의 위치를 파악하게 해주는 등의 중요한 역할을 합니다.

– 세그웨이나 나인봇 : 사람의 몸이 기울이는 정도와 방향에 따라 세그웨이/나인봇을 제어할 수 있도록 하는 곳에 자이로(가속도) 센서가 사용됩니다.

– 운동 관련 웨어러블 기기인 핏빗이나 샤오미 밴드 , 스마트 워치 등에서 사람의 움직임 등을 파악하기 위해 사용됩니다.

이처럼, 기울기 센서(가속도/자이로 센서)는 다양한 곳에 활용되는데요, 대표적으로 많이 사용되는 GY-521(MPU6050) 모듈을 아두이노를 통하여 학습해 본다면, 이후 아두이노와 함께 다양한 응용 작품을 만드는데 좋은 기회가 될 것으로 생각됩니다 ^^.

라즈이노 IoT에서는 앞으로 몇 회차에 걸쳐 기울기 센서 모듈을 이용해서 흥미로운 학습과제를 진행할 예정입니다.

본 페이지에서는 GY-521 모듈의 스펙과 기본 사용법에 관련된 학습이 진행됩니다.

《 GY-521 모듈(MPU-6050 6축-자이로 가속도 센서) 》

GY-521 기울기 센서 앞·뒷면 모습

IMU-6040 기울기 센서 모듈의 동작원리에 대한, 간략한 설명을 드리면,

센서 이름에 있는 IMU의 뜻은 Inertial Measurement Unit의 약어로, 관성 측정 장치라는 뜻이 있으며,

IMU-6040 모듈에는 X, Y, Z의 3축 가속도 센서와, 3축 자이로 센서, 온도 센서로 구성되어 있습니다. 온도 센서는 가속도 자이로 값이 급격한 온도 변화에 영향을 받을 경우 적용하기 위해 있는 센서로 일반적인 환경하에서는 적용하지 않고 사용하게 됩니다.

기울기는, 자이로 스코프(Gyroscope)로 측정이 가능하며, 가속도 센서로도 측정 가능합니다. 두 가지가 함께 있는 이유는 서로의 단점이 존재하는데, 이를 보완하기 위함이라고 보시면 됩니다. “자이로 스코프”에는 MEMS Gyroscope 라는 칩, 시스템 혹은 센서라고 하는 것이 들어 있습니다.

MEMS 뜻은 “Micro Electro Mechanical System”의 약어로, MEMS 센서는 칩이 회전 또는 기울어질 때 전압을 출력 시킵니다. 기울어지는 정도에 따라 비례해서 전압값이 다르게 출력됩니다.

이 전압은 칩 내부에서 16bit ADC 컨버터(아날로그 전압을 디지털 숫자 값으로 변환하는)에 의해 16비트(0 ~ 2의 16승 값 범위)값으로 변환 되고, 이 값을 가지고 아두이노 라이브러리와 프로그래밍 코드에서 처리하여 각도 값으로 변환해서 보여주게 됩니다.

그리고 MPU-6050에는 Accelerometer(가속도 계)라는 측정 센서가 있습니다. 역시, X, Y, Z 3개의 축으로 구성 되어 있으며, 조금 설명하기 쉽게, 어떤 박스 안에 무게가 있는 둥근 공이 있을 때, -X ↔ 공 ↔ +X 예를 들어, X축을 기준으로 -X축 방향으로 박스를 빠르게 밀었을 때, 공은 제자리에 머물러 있게 되는데, 이는 관성에 의해 +X축 방향으로 이동한 것으로 볼 수 있습니다. 센서에서는 이런 움직임에 대해 각 축 별로 전압으로 측정해 내게 되고, 자이로 센서의 경우처럼, 이를 수치 값으로 변환하여 코드에서 기울기 값 등으로 처리 할 수 있게 됩니다.

MPU-6050은 위 이미지에서 가운데 정사각형의 IC칩 명칭이며, 이 칩을 이용해서 만든 모듈 이름이 GY-521입니다. 따라서 같은 MPU-6050 칩을 사용한 다른 모델 제품도 있을 수 있으며, 경우에 따라 핀 배열이 다를 수 있습니다.

하지만 GY-521 모듈이 대표적으로 많이 사용되고 있습니다.

MPU-6050은 6축의 자유도(DOF : Degree of Freedom)를 가지며, 3축(x, y, z) 가속도계와 3축(x,y,z) 자이로를 합하여 6 축이라고 하며, 또는 3축 가속도+자이로 2축+온도 1축을 합하여 6축이라고도 합니다. (온도 센서가 포함된 이유는 가속도와 자이로 값이 온도에도 영향을 받기 때문에 온도센서를 활용하면 온도 변화에도 대응하는 값을 얻을 수 있기 때문입니다) 여기에, 지자기(지구자기) 센서의 3축을 추가한 모델이 MPU-9060 , 9축 센서입니다. 9축 센서를 이용하면 3차원의 위치(지구 상 공간)와 3차원의 방향을 모두 파악할 수 있게 됩니다.

– 가속도 센서 는 시간에 대한 속도 변화의 비율을 말하는 데요, 중력가속도를 이용하여 가속도를 측정하게 됩니다.

중력 가속도가 3개의 축 각각에 얼마만큼의 영향을 주었는지를 측정하여 센서의 기울어진 정도를 파악할 수 있게 됩니다. 다만, 가속도 센서의 경우 움직이는 동적인 물체에서는 가속도와 중력이 섞여서 검출되기 때문에 정확한 데이터를 얻기가 힘듭니다, 따라서 정적인 상태에서만 정확한 기울기를 측정할 수 있는 한계가 있습니다.

– 자이로 센서 는 물체의 회전 속도인 ‘각속도’를 이용하는 센서이기 때문에 각속도 센서라고도 합니다. 역시 3축의 물리량을 측정하여 센서의 움직임을 감지하고 기울기를 측정할 수 있는데요, 동적인 상황에서 가속도 센서에 비해 비교적 안정적인 값이 출력되지만 각도를 계산하는 과정에서 적분 방식을 사용하기 때문에 시간이 지날수록 누적되는 오차가 발생합니다.

※ 따라서, 가속도 센서와 자이로 센서의 장점을 적절하게 적용하여 코드를 구성한다면 보다 정밀한 결과를 얻을 수 있습니다. 그러므로 센서를 적용하려는 형태와 방법에 따라 코드가 심플해지기도 하며, 외부 라이브러리 사용과 함께 아주 복잡해지기도 합니다.

바로 위 ‘6050칩 이미지’를 보면, 직선방향의 화살표가 향하는 방향이 x, y, z 축의 가속도 센서가 적용되는 방향입니다.

( 센서를 통해 얻을 수 있는 RAW 데이터 파일 값 중에서 화살표 방향이 +값으로 표시된다면, 화살표 반대방향으로 움직일 시, -(마이너스) 값으로 표시됩니다. 좀 더 정확히 얘기하자면, 중력의 방향을 기준으로 잡고, 중력의 방향은 – , 중력의 반대 방향이 +입니다. )

그리고 회전하는 모양의 화살표가 x, y, z 축의 자이로 센서가 적용되는 방향입니다.

(마찬가지로, 화살표 방향으로의 회전 일 때 +값이 얻어진다면, 반대 방향으로의 회전 시, -(마이너스) 값이 얻어집니다. 회전 방향에 대한 + 방향은 위 이미지를 참고하세요)

그리고, 이 회전 방향은 특히 드론과 같은 비행체나 배와 같은 곳에 필수적으로 적용이 되는데요, 이 센서가 있어야, 기울기/자세를 유지하거나 보정할 수 있기 때문입니다.

X축 회전 각도를 Roll (롤) , Y축 회전 각도를 Pitch(피치) , Z 축 회전 각도는 Yaw(야우)라고 불립니다.

★ 기억하기 쉽도록 : 사람 머리를 기준으로

– Roll 은 → 고개를 좌우로 갸우뚱갸우뚱

– Pitch는 → 고개를 앞뒤로 끄덕끄덕

– Yaw는 → 고개를 도리 도리

그럼, MPU6050 칩의 상세 스펙과 MPU6050을 내장한 GY-521 모듈에 대해 본격적으로 살펴볼게요.

【 기울기 센서 MPU6050 스팩 】

전원 사용은 일반적으로 5V를 입력하지만, 3V~5V 사이의 전원은 모두 동작하므로, 3.3V 전원을 사용하는 다른 모듈들과 함께 3.3V 전원 연결도 자주 이용됩니다.

보시는 바와 같이 MPU6050은 I2C 인터페이스를 이용한 통신으로 측정값을 얻어낼 수 있습니다. 일반적으로 모듈로부터 데이터를 얻기 위해 SCL과 SDA 핀을 이용(모듈이 슬레이브로 동작) 합니다. 좀더 구체적으로 설명하자면, I2C는 필립스에서 개발한 직렬 컴퓨터 버스이며, 임베디드시스템 혹은 저속의 주변기기와의 통신을 위해 사용된 직렬 통신 방식입니다. 기본적으로 하나의 마스터와 하나 혹은 여러 대의 슬레이브 연결 구조이며 SDA핀으로 데이터를 주고받고,핀의 클럭신호(동기화)에 맞추어 통신하게 됩니다. 아두이노에서는 라이브러리를 활용하면 손쉽게 I2C 통신을 할 수 있습니다.

XDA와 XCL은 추가적인 외부의 지자기 센서나 또 다른 센서 연결을 확장하는 시리얼 통신 단자입니다. External , XDA, XCL 연결 단자 입니다.

그리고, 하나의 회로에서 만약 동일한 GY521 모듈을 두 개 구성하여 사용할 경우, I2C 통신 주소를 다르게 하기 위해 AD0 핀에 풀업 저항을 달면 주소를 달리 할 수 있습니다. 모듈의 기본 Slave address 주소는 1101000 이며(0x68), +Vcc쪽으로 풀업 저항(1㏀~10㏀) 연결 시 1101001로(0x69) 변경됩니다.

【 기울기 센서 실습 #1 】

: 기울기 센서 기본 실습으로 센서로부터 기본적인 RAW 데이터 값을 얻어내 보도록 하겠습니다.

활용도와 정확도를 높이기 위해서는 라이브러리를 사용해야 하지만, 복잡하고 코드 내용 파악이 어려울 수 있기 때문에, 기초 실습 #1에서는 라이브러리 없이 진행됩니다.

– MPU6050센서는 16bit ADC가 내장되어 있습니다. 센서의 각축으로부터 가속도와 자이로에 대한 아날로그 데이터를 16bit 분해능을 가진 ADC(Analog Digital Converter)를 거치면서 디지털 수치값으로 얻을 수 있다는 말인데요, 16bit는 2^16 이니 65536의 값인데, -(마이너스)부분까지 반으로 나누어 표시하면 기본적으로는 ” -32768 ~ +32767 ” 사이값의 출력 범위를 가진다는 말이 됩니다.

실습 #1에서는 우선 원시 RAW 데이터를 각센서 축별로 출력해보고,

실습 #2는 가속도 센서를 통해 얻은 RAW 데이터로부터 X축과 Y축의 각도를 계산해 내는 실습으로 진행하고,

실습 #3에서는 자이로 센서를 통해 얻은 RAW 데이터로부터 X축과 Y축의 각도를 얻는 과정으로 진행합니다.

실습 #4 상보필터 적용 실습

각 실습별 방법에 대한 장단점 및 기본적인 설명이 안내해 드리며, 상호 보완필터(상보필터)를 적용한 실습 #4로 이어지니 차근차근 하나씩 실습해 보시기 바랍니다. 가급적 실습 #4까지는 외부라이브러리를 배제한 코드를 사용하여 코드 단순화를 통해 동작원리를 이해하는데 도움이 되도록 하였습니다.

아래 회로 연결도를 구성해 주고 PC와 연결합니다.

▶ 회로 연결도 (아두이노 나노와 GY521(MPU6050) 연결도)

아두이노 나노와 GY521(MPU6050) 연결도

▶ 아두이노 코드

(가속도 x, y, z 축 값과 자이로 x, y, z 축 값의 raw data를 시리얼 모니터로 출력해 보기)

/* 기울기 센서 GY-521(MPU6050) 기초 실습 #1 (RAW 데이터 얻기) */ /* 아래 코드관련 실습에 대한 설명과 회로도 및 자료는 https://rasino.tistory.com/ 에 있습니다 */ #include const int MPU_ADDR = 0x68; // I2C통신을 위한 MPU6050의 주소 int16_t AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ; // 가속도(Acceleration) 와 void getRawData(); // 센서값 얻는 서브함수의 프로토타입 선언 void setup() { initSensor(); Serial.begin(9600); delay(200); } void loop() { getRawData(); // 센서값 얻어오는 함수 호출 Serial.print(“AcX:”); Serial.print(AcX); Serial.print(” AcY:”); Serial.print(AcY); Serial.print(” AcZ:”); Serial.print(AcZ); Serial.print(” GyX:”); Serial.print(GyX); Serial.print(” GyY:”); Serial.print(GyY); Serial.print(” GyZ:”); Serial.print(GyZ); Serial.println(); delay(300); } void initSensor() { Wire.begin(); Wire.beginTransmission(MPU_ADDR); // I2C 통신용 어드레스(주소) Wire.write(0x6B); // MPU6050과 통신을 시작하기 위해서는 0x6B번지에 Wire.write(0); // MPU6050을 동작 대기 모드로 변경 Wire.endTransmission(true); } void getRawData() { Wire.beginTransmission(MPU_ADDR); Wire.write(0x3B); // AcX 레지스터 위치(주소)를 지칭합니다 Wire.endTransmission(false); Wire.requestFrom(MPU_ADDR, 14, true); // AcX 주소 이후의 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(); } 《 위 코드 다운로드 》 Angle_RawData.zip 0.00MB ▶ 실행 결과 : 코드를 실행해 보면, 가속도 값 3개와 자이로 값3개 총 6개의 값이 일렬로 나타납니다. 센서를 움직여보면 데이터 값이 변하는 것을 볼 수 있습니다. 방향에 따라 + , - 값으로 나타나는데요, 현재 보이는 값은 어떤 각도 값이나 보정된 값이 아닌 말 그대로 순수한 Raw data이기 때문에 방향과 위치에 따른 데이터 변화를 유추하기는 어렵습니다. 때문에, 기본적인 Raw 데이터를 추출하는 원리 정도만 파악하시면 되고, 다음 실험에서 삼각함수를 이용한 각도 값을 계산해 보거나 , 특정 라이브러리를 이용해서 고정시킨 위치 데이터를 확인해 볼 수 있게 됩니다. 또는 프로세싱(Processing)과 같은 그래픽 구현 툴을 이용해서 3D 이미지로 센서의 움직임을 그래픽 화면으로 볼 수 있는 실험도 진행할 예정입니다. 기울기센서(MPU6050)로부터 Raw 데이터 얻기 ▶ 동작 영상 (본 글 제일 아래 전체 동영상을 참고해보세요 : 설명 음성 추가) 【 기울기 센서 실습 #2 】 : 실습 #1에서 Raw 데이터를 얻었다면, 이번엔 이 데이터를 가지고 우리가 흔히 알아보기 쉬운 각도(라디안: radian) 값으로 바꾸어 출력해 보는 실습입니다. 먼저 각도를 얻을 수 있는 방법은, 앞서 설명한 것처럼 크게 세 가지입니다. 1. 가속도 센서를 이용한 방법 2. 자이로 센서를 이용한 방법 3. 이 둘을 합쳐놓은 '상호보완 필터' 코드를 통해 구하는 방법 이번 실습은 움직임이 없는 상태에서 보다 정확한 값을 구할 수 있는 1번 가속도 센서를 이용한 간단한 방법으로 진행합니다. 때문에 라이브러리 설치 없이 간단히 진행할 수 있고 코드도 비교적 단순하여 파악과 응용이 쉽습니다. 각도(라디안)를 라이브러리 설치 없이 진행되어 구하기 위해서는 중력과 X축, Y축, Z 축과의 기울기를 이용한 삼각함수를 적용해야 하는데요, 해당 수식은 아래와 같습니다. Roll/Pitch/Yaw 각도를 구하기 위한 삼각함수 수식 물론 코드에서는 이 수식이 적용되어 있습니다. 회로 연결은 실습 1과 같고 아래에 있는 아두이노 코드를 업로드해 주세요. ▶ 아두이노 코드 ( 코드에서는 가속도 AcX에 대한 'Roll 각도'와 가속도 AcY에 대한 'Pitch 각도'만 구합니다. 앞서 설명드린 것처럼 가속도 센서만 가지고는 Yaw에 해당하는 정확한 AcZ 각도가 구할 수 없습니다. Z축 Yaw가 중력 방향과 평행한 회전을 하기 때문에 삼각함수를 적용해도 올바른 데이터가 출력되지 않습니다.) // Roll과 Pitch 각도 구하기 실습 》 // 가속도 센서만 가지고 롤(Roll)과 피치(Pitch)를 구하는 예제입니다. // 본 코드는 드론과 같은 움직임이 심한 경우가 아닌 비교적 정적인 상태에서 안정된 값을 얻을 수 있으며, // 복잡한 외부라이브러리를 사용하지 않아 코드가 심플해서 파악후 적용하기가 쉽습니다. // 아래 코드관련 실습에 대한 설명과 회로도 및 자료는 https://rasino.tistory.com/ 에 있습니다 #include const int MPU_ADDR = 0x68; // I2C통신을 위한 MPU6050의 주소 int16_t AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ; // 가속도(Acceleration)와 자이로(Gyro) double angleAcX; double angleAcY; // double angleAcZ; const double RADIAN_TO_DEGREE = 180 / 3.14159; void setup() { initSensor(); Serial.begin(9600); delay(200); } void loop() { getAngleXY(); Serial.print(“Angle x : “); Serial.print(angleAcX); Serial.print(“\t\t Angle y : “); Serial.println(angleAcY); delay(20); } double getAngleXY() { getData(); // 삼각함수를 이용한 롤(Roll)의 각도 구하기 angleAcX = atan(AcY / sqrt(pow(AcX, 2) + pow(AcZ, 2))); angleAcX *= RADIAN_TO_DEGREE; // 삼각함수를 이용한 피치(Pitch)의 각도 구하기 angleAcY = atan(-AcX / sqrt(pow(AcY, 2) + pow(AcZ, 2))); angleAcY *= RADIAN_TO_DEGREE; // angleAcZ값(Yaw)은 아래의 삼각함수 공식은 있으나, 가속도 센서만 이용해서는 원하는 데이터를 얻을 수 없어 생략 // angleAcZ = atan(sqrt(pow(AcX, 2) + pow(AcY, 2)) / AcZ ); // angleAcZ *= RADIAN_TO_DEGREE; } void initSensor() { Wire.begin(); Wire.beginTransmission(MPU_ADDR); // I2C 통신용 어드레스(주소) Wire.write(0x6B); // MPU6050과 통신을 시작하기 위해서는 0x6B번지에 Wire.write(0); Wire.endTransmission(true); } void getData() { Wire.beginTransmission(MPU_ADDR); Wire.write(0x3B); // AcX 레지스터 위치(주소)를 지칭합니다 Wire.endTransmission(false); Wire.requestFrom(MPU_ADDR, 14, true); // AcX 주소 이후의 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(); } 《 위 코드 다운로드 》 Angle_Roll_Pitch.zip 0.00MB ▶ 실행 결과 : main loop( )에 있는 delay(20)을 느리게 혹은 빠르게 조절하여 확인해 볼 수 있습니다. 센서 보드를 중력의 방향과 수직으로 놓으면 X와 Y는 0도를 가리킵니다. 그 상태에서 Roll(X)을 앞 뒤로 돌려보고, Pitch(Y)를 앞뒤로 돌려 보세요. - Roll은 센서 보드 위 화살표 표시를 참고 기준으로 하여, 중력과 반대로 머리를 들면 +각도로 나오며, 중력의 방향으로 머리를 숙이면 -각도를 표시합니다. - Pitch 또한 피치 화살표를 기준으로, 화살표 방향으로 숙이면 +각도로 표시되며, 반대방향으로 회전시키면 -각도로 표시됩니다. - 아래 이미지는 시리얼 플로터를 실행시킨 화면인데요, 각도 값을 그래프 형태로 보면 좀 더 직관적으로 파악하기 좋습니다. ( 시리얼 플로터 창 열기 : 아두이노 IDE 툴 메뉴 클릭 》 시리얼 플로터 클릭! ) 파란선이 Roll (AcX)에 대한 각도 그래프이며, 빨간선이 Pitch(AcY)에 대한 각도 그래프입니다. 기울기 센서 모듈은 접촉이 불안정할 경우, 데이터가 원하는 대로 나오지 않거나, 오작동 할 수 있습니다. 접촉이 헐렁한 브레드보드를 바꾸어 보거나 연결선을 확인해 보세요. 필요한 경우 납땜으로 연결해 주면 더욱 안정된 접촉이 이루어집니다. 그 외에 동작은 정상 동작하나, 데이터 값이 튀는 노이즈가 심할 경우에는, 추출 값을 3~10회 정도의 평균값 처리하는 루틴을 넣어 주면 어느 정도 해결할 수 있습니다. ▶ 동작 영상 【 기울기 센서 실습 #3 】 : 실습 #2에서 MPU6050에 있는 가속도 센서를 이용해서 각도(라디안: radian) 값으로 바꾸어 출력해 보는 실습을 했다면, 이번엔 MPU6050에 있는 자이로 센서를 이용해서 각도를 계산해 출력해 보겠습니다. 1. 가속도 센서를 이용한 방법 2. 자이로 센서를 이용한 방법 3. 이 둘을 합쳐놓은 '상호보완 필터' 코드를 통해 구하는 방법 이번 실습은 2. 자이로 센서를 이용한 방법 입니다. 먼저 자이로 센서는 진자의 움직임과 같은 축을 중심으로 회전하는 각속도를 측정합니다. 각속도는 시간당 회전하는 각도를 의미하는데요, 예를 들면, 1. 수평한 자세를 유지하고 있는 상태이라면, 각속도는 0도/sec를 나타낼 텐데요, 2. 이 물체가 10초 동안 50도만큼 기울어졌을 경우 , 이 10초동안은 0이 아닌 각속도 값을 가지게 됩니다. 10초 동안의 평균 각속도는 5도/sec 가 되는데요, 즉, 초당 5도를 움직이는 속력이라 말할 수 있습니다. 3. 기울어지는 동작을 한 후 다시 멈춰서 50도를 유지한다고 할 때, 이때는 다시 각속도가 0도/sec 가 됩니다. 1번 2번 3번 과정을 거치면서 각속도는 0 -> 5 -> 0으로 바뀌었는데요, 그런데 각도는 0도에서 점차 증가해서 50도가 된 상태입니다. 그래서 각속도가 움직인 각도에 비례해서 증가하는 것이 아니기 때문에, 각도를 구하려면 전체 시간에 해당하는 만큼의 각속도를 모두 합(적분을) 해야합니다. 자이로 센서는 이와 같이 각속도를 데이터로 출력하기 때문에 이 각속도 데이터를 모두 합(적분)하면 기울어진 각도를 계산해 낼 수 있는 원리입니다. 그런데 자이로 센서의 경우 문제는 이러한 적분 때문에 발생하게 됩니다. 센서에서 측정되는 각속도는 노이즈나 미세한 기본 오차 값들이 적분으로 인해, 시간이 지날 수록 쌓여 결국 측정값(각도 오차)의 오차가 커지게 되는 문제가 있습니다. Drift 현상이 발생합니다.

(즉, 이 방법만으로는 시간이 지날 수록 각도 혹은 기울기의 오차가 커지게 되는 단점이 있죠. 하지만, 가속도 센서처럼 진동에 영향이 크게 없으며 중력과 일치하는 Z축의 Yaw 각도도 구할 수 있는 장점이 있습니다.

[ 용어 정리 ]

– Drift 현상 : 조건이 일정함에도 시간이 경과함에 따라서 값이 이탈 또는 흘러가는 현상.

– 각속도란 : 각속도 오메가(ω)는 원운동에서 단위 시간 동안에 회전한 각도를 말하며, 즉, 회전하는 물체에 대한 회전의 빠르기를 의미합니다.

– 각도 : 각속도에 시간을 곱한 것이 각도 이며, 이것들을 모두 합치면 움직인 전체 각도가 됩니다

속력/속도/가속도 와의 관계식

회로 연결은 실습 1과 같고 아래에 있는 아두이노 코드를 업로드해 주세요.

▶ 아두이노 코드

( 코드에서는 시리얼 모니터 통신속도를 115200bps 으로 바꾸었으니, 실행시 시리얼 모니터 창의 보드레이트를 115200 bps로 맞추어 주세요)

// 《 자이로 Gyro 센서로 Roll과 Pitch, Yaw의 각도 구하기 실습 》 // 자이로 센서만 가지고 롤(Roll)과 피치(Pitch), 야우(Yaw)를 구하는 예제입니다. /* 아래 코드관련 실습에 대한 설명과 회로도 및 자료는 https://rasino.tistory.com/ 에 있습니다 */ #include const int MPU_ADDR = 0x68; // I2C통신을 위한 MPU6050의 주소 int16_t AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ; // 가속도(Acceleration)와 자이로(Gyro) double angleAcX, angleAcY, angleAcZ; double angleGyX, angleGyY, angleGyZ; const double RADIAN_TO_DEGREE = 180 / 3.14159; const double DEG_PER_SEC = 32767 / 250; // 1초에 회전하는 각도 // GyX, GyY, GyZ 값의 범위 : -32768 ~ +32767 (16비트 정수범위) unsigned long now = 0; // 현재 시간 저장용 변수 unsigned long past = 0; // 이전 시간 저장용 변수 double dt = 0; // 한 사이클 동안 걸린 시간 변수 double averAcX, averAcY, averAcZ; double averGyX, averGyY, averGyZ; void setup() { initSensor(); Serial.begin(115200); caliSensor(); // 초기 센서 캘리브레이션 함수 호출 past = millis(); // past에 현재 시간 저장 } void loop() { getData(); getDT(); angleGyX += ((GyX – averGyX) / DEG_PER_SEC) * dt; angleGyY += ((GyY – averGyY) / DEG_PER_SEC) * dt; angleGyZ += ((GyZ – averGyZ) / DEG_PER_SEC) * dt; Serial.print(“Angle Gyro X:”); Serial.print(angleGyX); Serial.print(“\t\t Angle Gyro y:”); Serial.print(angleGyY); Serial.print(“\t\t Angle Gyro Z:”); Serial.println(angleGyZ); delay(20); } void initSensor() { Wire.begin(); Wire.beginTransmission(MPU_ADDR); // I2C 통신용 어드레스(주소) Wire.write(0x6B); // MPU6050과 통신을 시작하기 위해서는 0x6B번지에 Wire.write(0); Wire.endTransmission(true); } void getData() { Wire.beginTransmission(MPU_ADDR); Wire.write(0x3B); // AcX 레지스터 위치(주소)를 지칭합니다 Wire.endTransmission(false); Wire.requestFrom(MPU_ADDR, 14, true); // AcX 주소 이후의 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(); } // loop 한 사이클동안 걸리는 시간을 알기위한 함수 void getDT() { now = millis(); dt = (now - past) / 1000.0; past = now; } // 센서의 초기값을 10회 정도 평균값으로 구하여 저장하는 함수 void caliSensor() { double sumAcX = 0 , sumAcY = 0, sumAcZ = 0; double sumGyX = 0 , sumGyY = 0, sumGyZ = 0; getData(); for (int i=0;i<10;i++) { getData(); sumAcX+=AcX; sumAcY+=AcY; sumAcZ+=AcZ; sumGyX+=GyX; sumGyY+=GyY; sumGyZ+=GyZ; delay(50); } averAcX=sumAcX/10; averAcY=sumAcY/10; averAcZ=sumAcY/10; averGyX=sumGyX/10; averGyY=sumGyY/10; averGyZ=sumGyZ/10; } 《 위 코드 다운로드 》 Angle_Gyro.zip 0.00MB ▶ 실행 결과 : 센서 보드를 X축 Y축 Z축 각각 움직여 보세요. ▶ 실행 영상 (제일 아래 전체 설명 동영상 참고) 【 기울기 센서 실습 #4 】 : 실습 #2와 실습#3에서는 각각 가속도 센서와 자이로 센서를 이용한 각도를 구했는데요, 가속도센서는 진동에 약하기 때문에(튀는 데이터값의 영향이 큼) 짧은 시간의 변화에는 약하지만, 긴 시간에 대해서는 정확한 각도를 산출해 낼 수 있고, 자이로센서는 진동에 강하기 때문에 짧은 시간에 대해서는 정확한 각도를 얻을 수 있지만 시간이 지나면서 오차가 누적되어 긴 시간에서는 취약합니다. 그래서 각각의 장점도 있지만, 단점이 명확하여 어느 하나의 센서 만으로는 드론과 같은 자세제어나 보정은 어렵습니다. 따라서 센서 둘을 모두 이용하고, 이 둘의 장점을 이용하여 서로의 단점을 보완한 상호보완 필터 코드를 적용하여 사용한다면, 비교적 오류가 없는 각도를 구할 수 있어서 드론 등의 자세제어 코드에 사용할 수 있습니다. 1. 가속도 센서를 이용한 방법 2. 자이로 센서를 이용한 방법 3. 이 둘을 합쳐놓은 '상호보완 필터' 코드를 통해 구하는 방법 이번 실습은 3. 상호보완 필터를 이용한 방법 입니다. 아래 이미지는 상호보완 필터의 개념도 입니다. 상보필터(상호보완) 개념도 [ 상보필터의 원리 - Complementary Filter ] - 가속도 센서(Accelerometer)는 센서 특성상 고주파 영역에서 노이즈가 많이 발생하게 되어 정확한 값을 얻기 어려운데요, 그래서 노이즈 영역을 제거하고자 고역은 감쇠시키고, 낮은 주파수 영역을 통과시키는 저역필터(Low Pass Filter)를 적용해주면 정확도가 올라갑니다. - 자이로 센서(Gyroscope)는 센서 특성상 저주파 영역에서 값이 변하는 Drift현상이 발생하여 정확한 값을 기대하기가 어렵습니다. 그래서 저역을 감쇠시키고 노이즈가 적은 고역을 통과시키기 위한 고역필터(High Pass Filter)를 적용해주면 역시 정확도가 올라갑니다. ※ 이렇게 각각의 필터를 통과해서 노이즈가 걸러진 값들을 합하여 보다더 정확한 각도값을 얻게 됩니다. 이외에 칼만필터(Kalman Filter), Quanternion 라는 것도 있습니다. 상보필터에서는 가속도 센서의 저주파 영역에서의 장점과 , 자이로센서의 고주파 영역에서의 장점만을 융합한 필터로서 , 방법과 코드가 간단하여 적용하기 쉬운 장점이 있습니다. 상보필터에서는 ALPHA라는 가중치 값을 통해 자이로센서와 가속도센서 각각으로부터 얻은 각도를 어떤 비중으로 적용시킬지 정하여 계산하게 되는데요. 아래가 바로 보정값(가중치) ALPHA를 적용한 보정된 각도 값의 식(angleFiX) 입니다. angleFiX = ALPHA * angleTmpX + (1.0 - ALPHA) * angleAcX; 여기서 angleTmp 는 자이로센서 값을 기준으로 만든 상보필터 처리를 위한 임시각도이며 X축에 대해 정리하면 angleTmpX = angleFiX + angleGyX * dt 가 됩니다. 가중치 ALPHA 값은 α = T/(T+Δt) 식으로 구하는데요, α (ALPHA) = 1 / (1+0.04) 가되어, α 값은 0.96 이 됩니다. 즉, 1(T) 사이클 도는 동안의 loop Time(Δt=0.04) 을 적용한 식입니다. 그런데 이 값은 고정값은 아니며, loop Time이 길어지거나 등의 이유로 알파값을 시스템에 맞게 변경할 수 있습니다. 즉, angleFiX 식을 보면 아시겠지만, 자이로 값에 * 0.96 가중치를 곱하고(주고), 가속도 값에 * 0.04의 가중치를 줘서 합한 값이어서 자이로센서(자이로스코프)에 더 의존하는 형태라고 말 할 수 있습니다. 그런데, 이런 형태가 비교적 정밀한(안정적인) 출력값을 내는 이유는, 식을 다시 살펴보면 angleFiX = ALPHA * angleTmpX + (1.0 - ALPHA) * angleAcX; 각도 변화가 상당히 느린 구간(저주파 영역)에서는 자이로센서의 데이터 값이 작아지기 때문에(angleGyX * dt의 누적값 감소), (1.0-ALPHA) = 0.04 가중치 적용으로 작았던 가속도 데이터 값이 상대적으로 커지게 되어 , 자이로스코프의 저주파 영역에서 발생하는 Drift(드리프트)에 대한 단점을 보완 할 수 있게 됩니다. ▶ 아두이노 코드 ( 위에서 설명한 식을 코드에 적용한 아두이노 코드입니다. 실습 #1과 실습#2에 소개한 코드를 합쳐서, 상보필터 식을 적용한 코드입니다. 축 3가지를 동시에 시리얼모니터로 확인하기 불편하기 때문에, 일부 축에 주석처리 되어 있으니, 필요한 경우 주석을 해제하여 사용하세요. ) - 시리얼모티너(플로터) 출력은 아래처럼 각 축별로 비교하기 쉽도록 배치하였습니다. 《가속도센서 X축》 출력과 《필터링된 X축》 출력 《가속도센서 Y축》 출력과 《필터링된 Y축》 출력 《자이로센서 Z축》 출력과 《필터링된 Z축》 출력 // 《 상보필터를 적용한 Roll과 Pitch, Yaw의 각도 구하기 실습 》 /* 아래 코드관련 실습에 대한 설명과 회로도 및 자료는 https://rasino.tistory.com/ 에 있습니다 */ #include const int MPU_ADDR = 0x68; // I2C통신을 위한 MPU6050의 주소 int16_t AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ; // 가속도(Acceleration)와 자이로(Gyro) double angleAcX, angleAcY, angleAcZ; double angleGyX, angleGyY, angleGyZ; double angleFiX, angleFiY, angleFiZ; const double RADIAN_TO_DEGREE = 180 / 3.14159; const double DEG_PER_SEC = 32767 / 250; // 1초에 회전하는 각도 const double ALPHA = 1 / (1 + 0.04); // GyX, GyY, GyZ 값의 범위 : -32768 ~ +32767 (16비트 정수범위) unsigned long now = 0; // 현재 시간 저장용 변수 unsigned long past = 0; // 이전 시간 저장용 변수 double dt = 0; // 한 사이클 동안 걸린 시간 변수 double averAcX, averAcY, averAcZ; double averGyX, averGyY, averGyZ; void setup() { initSensor(); Serial.begin(115200); caliSensor(); // 초기 센서 캘리브레이션 함수 호출 past = millis(); // past에 현재 시간 저장 } void loop() { getData(); getDT(); angleAcX = atan(AcY / sqrt(pow(AcX, 2) + pow(AcZ, 2))); angleAcX *= RADIAN_TO_DEGREE; angleAcY = atan(-AcX / sqrt(pow(AcY, 2) + pow(AcZ, 2))); angleAcY *= RADIAN_TO_DEGREE; // 가속도 센서로는 Z축 회전각 계산 불가함. // 가속도 현재 값에서 초기평균값을 빼서 센서값에 대한 보정 angleGyX += ((GyX – averGyX) / DEG_PER_SEC) * dt; //각속도로 변환 angleGyY += ((GyY – averGyY) / DEG_PER_SEC) * dt; angleGyZ += ((GyZ – averGyZ) / DEG_PER_SEC) * dt; // 상보필터 처리를 위한 임시각도 저장 double angleTmpX = angleFiX + angleGyX * dt; double angleTmpY = angleFiY + angleGyY * dt; double angleTmpZ = angleFiZ + angleGyZ * dt; // (상보필터 값 처리) 임시 각도에 0.96가속도 센서로 얻어진 각도 0.04의 비중을 두어 현재 각도를 구함. angleFiX = ALPHA * angleTmpX + (1.0 – ALPHA) * angleAcX; angleFiY = ALPHA * angleTmpY + (1.0 – ALPHA) * angleAcY; angleFiZ = angleGyZ; // Z축은 자이로 센서만을 이용하열 구함. Serial.print(“AngleAcX:”); Serial.print(angleAcX); Serial.print(“\t FilteredX:”); Serial.print(angleFiX); Serial.print(“\t AngleAcY:”); Serial.print(angleAcY); Serial.print(“\t FilteredY:”); Serial.println(angleFiY); Serial.print(“\t AngleAcZ:”); Serial.print(angleGyZ); Serial.print(“\t FilteredZ:”); Serial.println(angleFiZ); // Serial.print(“Angle Gyro X:”); // Serial.print(angleGyX); // Serial.print(“\t\t Angle Gyro y:”); // Serial.print(angleGyY); // Serial.print(“\t\t Angle Gyro Z:”); // Serial.println(angleGyZ); // delay(20); } void initSensor() { Wire.begin(); Wire.beginTransmission(MPU_ADDR); // I2C 통신용 어드레스(주소) Wire.write(0x6B); // MPU6050과 통신을 시작하기 위해서는 0x6B번지에 Wire.write(0); Wire.endTransmission(true); } void getData() { Wire.beginTransmission(MPU_ADDR); Wire.write(0x3B); // AcX 레지스터 위치(주소)를 지칭합니다 Wire.endTransmission(false); Wire.requestFrom(MPU_ADDR, 14, true); // AcX 주소 이후의 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(); } // loop 한 사이클동안 걸리는 시간을 알기위한 함수 void getDT() { now = millis(); dt = (now - past) / 1000.0; past = now; } // 센서의 초기값을 10회 정도 평균값으로 구하여 저장하는 함수 void caliSensor() { double sumAcX = 0 , sumAcY = 0, sumAcZ = 0; double sumGyX = 0 , sumGyY = 0, sumGyZ = 0; getData(); for (int i=0;i<10;i++) { getData(); sumAcX+=AcX; sumAcY+=AcY; sumAcZ+=AcZ; sumGyX+=GyX; sumGyY+=GyY; sumGyZ+=GyZ; delay(50); } averAcX=sumAcX/10; averAcY=sumAcY/10; averAcZ=sumAcY/10; averGyX=sumGyX/10; averGyY=sumGyY/10; averGyZ=sumGyZ/10; } 《 위 코드 다운로드 》 Angle_Acc_Gyro_CompFilter.zip 0.00MB ※ 아래 실행결과 화면을 보시면 알겠지만, 상보필터를 적용 후의 그래프는 노이즈나 한 번씩 크게 튀는 값 들이 상당히 제거되어 나타나는 것을 알 수 있습니다. 단, 노이즈 향상을 위해 ALPHA값 등, 보정값을 과도하게 조정하게 되면, 보정된 데이터의 출력 딜레이(시간차)가 발생하게 됩니다. 이는 드론(Drone)과 같은 제어에 있어서는 적시에 올바른 제어를 할 수 없게 만들 수도 있습니다. ▶ 실행 결과 1. 《가속도센서 X축》 출력과《필터링된 X축》 출력 비교 화면 먼저, 시리얼모니터 화면을 살펴 보세요.(아래 이미지) , 보드를 77도 정도에서 고정한 상태에서 가속도센서에서 얻은 데이터는 각도 값이 68~70도 사이를 짧은 순간에 제법 심하게 요동치고 있는 반면에, 필터링한 각도 값은, 77도에서 소수점 단위 정도만 변동이 있을 뿐 매우 안정된 출력을 보여주고 있는 것을 알 수 있습니다. 그럼, 이제 시리얼 모니터만으로는 잘 체감이 안 되실텐데요, 같은 출력을 아두이노 IDE 메뉴에 있는 '시리얼 플로터'를 통해 그래프로 보면 좀더 확연히 그 차이를 구분하실 수 있게 됩니다. (아래) 파란색 그래프가 가속도센서로 부터 얻은 X축 회전(각도)상태의 데이터인데요, 떨림과 같은 병동이 심한 반면에, 필터링 코드를 거친 빨간색 X축의 데이터는 이런 노이즈들이 깔끔하게 제거 된 것을 알 수 있습니다. 2. 《가속도센서 Y축》 출력과《필터링된 Y축》 출력 비교 화면 그럼, Y축 그래프도 살펴 볼게요. 역시 마찬가지로, 필터링 되지 않은 Y축 출력과 필터링된 Y축 출력에 차이가 있음을 볼수 있습니다. 3. 《자이로센서 Z축》 출력과《필터링된 Z축》 출력 비교 화면 그리고, Z축 같은 경우는 앞서 설명드린대로, 가속도 센서로부터는 데이터를 얻을 수 없는 상태이고, 따라서 자이로 센서로 부터 얻은 Z축 데이터와, 자이로센서 데이터 가중치가 높은 필터링된 Z축 데이터를 출력해 본 것이어서 두 그래프간의 차이가 거의 없는 그래프 모습을 보여주고 있습니다. 3. 끝으로 전체 축을 동시에 비교해봤습니다. 《자이로센서 X-Y-Z-축》 출력과

아두이노 자이로센서(MPU6050센서) 써보기

아두이노 가속도 / 자이로 센서 중에 가장 유명한 센서인 MPU6050을 가져와봤습니다.

출처: https://www.amazon.com/SunFounder-MPU6050-Raspberry-Gyroscope-Accelerator/dp/B0151GI5VI

동작전압: 2.375V~3.46V (수정)

통신방식: I²C(I2C,IIC) , SPI

자이로 최대 측정값: ±(250/500/1000/2000)

자이로 센서 감도: (131/65.5/32.8/16.4)

데이터 시트

https://www.invensense.com/wp-content/uploads/2015/02/MPU-6500-Datasheet2.pdf

자이로/가속도 센서입니다.

원리는 이거 보고 이해하시길. https://mechaworld.tistory.com/11

주의사항!

납땜이 되어있는것도 있고 안되어 있는것도 있으니까 잘 보고 사시길.

안되어 있는건 본인이 인두기로 납땜해야 한다.

출처: https://blog.naver.com/roboholic84/220583168600

아두이노 보드의 i2c핀 위치

[출처] 아두이노 보드별 I²C 핀 알아보기! (i2c핀 아두이노 i2c)|작성자 오픈랩

연결법

출처: http://www.makeshare.org/bbs/board.php?bo_table=arduinosensor&wr_id=47

코딩하기..

코드는 요짝으로 코딩하자

// I2C device class (I2Cdev) demonstration Arduino sketch for MPU6050 class using DMP (MotionApps v2.0) // 6/21/2012 by Jeff Rowberg // Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib // // Changelog: // 2013-05-08 – added seamless Fastwire support // – added note about gyro calibration // 2012-06-21 – added note about Arduino 1.0.1 + Leonardo compatibility error // 2012-06-20 – improved FIFO overflow handling and simplified read process // 2012-06-19 – completely rearranged DMP initialization code and simplification // 2012-06-13 – pull gyro and accel data from FIFO packet instead of reading directly // 2012-06-09 – fix broken FIFO read sequence and change interrupt detection to RISING // 2012-06-05 – add gravity-compensated initial reference frame acceleration output // – add 3D math helper file to DMP6 example sketch // – add Euler output and Yaw/Pitch/Roll output formats // 2012-06-04 – remove accel offset clearing for better results (thanks Sungon Lee) // 2012-06-01 – fixed gyro sensitivity to be 2000 deg/sec instead of 250 // 2012-05-30 – basic DMP initialization working /* ============================================ I2Cdev device library code is placed under the MIT license Copyright (c) 2012 Jeff Rowberg Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. =============================================== */ // I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files // for both classes must be in the include path of your project #include “I2Cdev.h” #include “MPU6050_6Axis_MotionApps20.h” //#include “MPU6050.h” // not necessary if using MotionApps include file // Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation // is used in I2Cdev.h #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE #include “Wire.h” #endif // class default I2C address is 0x68 // specific I2C addresses may be passed as a parameter here // AD0 low = 0x68 (default for SparkFun breakout and InvenSense evaluation board) // AD0 high = 0x69 MPU6050 mpu; //MPU6050 mpu(0x69); // <-- use for AD0 high /* ========================================================================= NOTE: In addition to connection 3.3v, GND, SDA, and SCL, this sketch depends on the MPU-6050's INT pin being connected to the Arduino's external interrupt #0 pin. On the Arduino Uno and Mega 2560, this is digital I/O pin 2. * ========================================================================= */ /* ========================================================================= NOTE: Arduino v1.0.1 with the Leonardo board generates a compile error when using Serial.write(buf, len). The Teapot output uses this method. The solution requires a modification to the Arduino USBAPI.h file, which is fortunately simple, but annoying. This will be fixed in the next IDE release. For more info, see these links: http://arduino.cc/forum/index.php/topic,109987.0.html http://code.google.com/p/arduino/issues/detail?id=958 * ========================================================================= */ // uncomment "OUTPUT_READABLE_QUATERNION" if you want to see the actual // quaternion components in a [w, x, y, z] format (not best for parsing // on a remote host such as Processing or something though) //#define OUTPUT_READABLE_QUATERNION // uncomment "OUTPUT_READABLE_EULER" if you want to see Euler angles // (in degrees) calculated from the quaternions coming from the FIFO. // Note that Euler angles suffer from gimbal lock (for more info, see // http://en.wikipedia.org/wiki/Gimbal_lock) //#define OUTPUT_READABLE_EULER // uncomment "OUTPUT_READABLE_YAWPITCHROLL" if you want to see the yaw/ // pitch/roll angles (in degrees) calculated from the quaternions coming // from the FIFO. Note this also requires gravity vector calculations. // Also note that yaw/pitch/roll angles suffer from gimbal lock (for // more info, see: http://en.wikipedia.org/wiki/Gimbal_lock) #define OUTPUT_READABLE_YAWPITCHROLL // uncomment "OUTPUT_READABLE_REALACCEL" if you want to see acceleration // components with gravity removed. This acceleration reference frame is // not compensated for orientation, so +X is always +X according to the // sensor, just without the effects of gravity. If you want acceleration // compensated for orientation, us OUTPUT_READABLE_WORLDACCEL instead. //#define OUTPUT_READABLE_REALACCEL // uncomment "OUTPUT_READABLE_WORLDACCEL" if you want to see acceleration // components with gravity removed and adjusted for the world frame of // reference (yaw is relative to initial orientation, since no magnetometer // is present in this case). Could be quite handy in some cases. //#define OUTPUT_READABLE_WORLDACCEL // uncomment "OUTPUT_TEAPOT" if you want output that matches the // format used for the InvenSense teapot demo //#define OUTPUT_TEAPOT #define INTERRUPT_PIN 2 // use pin 2 on Arduino Uno & most boards #define LED_PIN 13 // (Arduino is 13, Teensy is 11, Teensy++ is 6) bool blinkState = false; // MPU control/status vars 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 // orientation/motion vars Quaternion q; // [w, x, y, z] quaternion container VectorInt16 aa; // [x, y, z] accel sensor measurements VectorInt16 aaReal; // [x, y, z] gravity-free accel sensor measurements VectorInt16 aaWorld; // [x, y, z] world-frame accel sensor measurements VectorFloat gravity; // [x, y, z] gravity vector float euler[3]; // [psi, theta, phi] Euler angle container float ypr[3]; // [yaw, pitch, roll] yaw/pitch/roll container and gravity vector // packet structure for InvenSense teapot demo uint8_t teapotPacket[14] = { '$', 0x02, 0,0, 0,0, 0,0, 0,0, 0x00, 0x00, '\r', ' ' }; // ================================================================ // === INTERRUPT DETECTION ROUTINE === // ================================================================ volatile bool mpuInterrupt = false; // indicates whether MPU interrupt pin has gone high void dmpDataReady() { mpuInterrupt = true; } // ================================================================ // === INITIAL SETUP === // ================================================================ void setup() { // join I2C bus (I2Cdev library doesn't do this automatically) #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 // initialize serial communication // (115200 chosen because it is required for Teapot Demo output, but it's // really up to you depending on your project) Serial.begin(115200); while (!Serial); // wait for Leonardo enumeration, others continue immediately // NOTE: 8MHz or slower host processors, like the Teensy @ 3.3v or Ardunio // Pro Mini running at 3.3v, cannot handle this baud rate reliably due to // the baud timing being too misaligned with processor ticks. You must use // 38400 or slower in these cases, or use some kind of external separate // crystal solution for the UART timer. // initialize device Serial.println(F("Initializing I2C devices...")); mpu.initialize(); pinMode(INTERRUPT_PIN, INPUT); // verify connection Serial.println(F("Testing device connections...")); Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed")); // wait for ready Serial.println(F(" Send any character to begin DMP programming and demo: ")); while (Serial.available() && Serial.read()); // empty buffer while (!Serial.available()); // wait for data while (Serial.available() && Serial.read()); // empty buffer again // load and configure the DMP Serial.println(F("Initializing DMP...")); devStatus = mpu.dmpInitialize(); // supply your own gyro offsets here, scaled for min sensitivity mpu.setXGyroOffset(220); mpu.setYGyroOffset(76); mpu.setZGyroOffset(-85); mpu.setZAccelOffset(1788); // 1688 factory default for my test chip // make sure it worked (returns 0 if so) if (devStatus == 0) { // turn on the DMP, now that it's ready Serial.println(F("Enabling DMP...")); mpu.setDMPEnabled(true); // enable Arduino interrupt detection Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)...")); attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN), dmpDataReady, RISING); mpuIntStatus = mpu.getIntStatus(); // set our DMP Ready flag so the main loop() function knows it's okay to use it Serial.println(F("DMP ready! Waiting for first interrupt...")); dmpReady = true; // get expected DMP packet size for later comparison 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(")")); } // configure LED for output pinMode(LED_PIN, OUTPUT); } // ================================================================ // === MAIN PROGRAM LOOP === // ================================================================ void loop() { // if programming failed, don't try to do anything if (!dmpReady) return; // wait for MPU interrupt or extra packet(s) available while (!mpuInterrupt && fifoCount < packetSize) { // other program behavior stuff here // . // . // . // if you are really paranoid you can frequently test in between other // stuff to see if mpuInterrupt is true, and if so, "break;" from the // while() loop to immediately process the MPU data // . // . // . } // reset interrupt flag and get INT_STATUS byte 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 & 0x10) || fifoCount == 1024) { // reset so we can continue cleanly mpu.resetFIFO(); Serial.println(F("FIFO overflow!")); // otherwise, check for DMP data ready interrupt (this should happen frequently) } else if (mpuIntStatus & 0x02) { // 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; #ifdef OUTPUT_READABLE_QUATERNION // display quaternion values in easy matrix form: w x y z mpu.dmpGetQuaternion(&q, fifoBuffer); Serial.print(“quat\t”); 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 // display Euler angles in degrees mpu.dmpGetQuaternion(&q, fifoBuffer); mpu.dmpGetEuler(euler, &q); Serial.print(“euler\t”); 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 // display Euler angles in degrees mpu.dmpGetQuaternion(&q, fifoBuffer); mpu.dmpGetGravity(&gravity, &q); mpu.dmpGetYawPitchRoll(ypr, &q, &gravity); 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); #endif #ifdef OUTPUT_READABLE_REALACCEL // display real acceleration, adjusted to remove gravity mpu.dmpGetQuaternion(&q, fifoBuffer); mpu.dmpGetAccel(&aa, fifoBuffer); mpu.dmpGetGravity(&gravity, &q); mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity); Serial.print(“areal\t”); Serial.print(aaReal.x); Serial.print(“\t”); Serial.print(aaReal.y); Serial.print(“\t”); Serial.println(aaReal.z); #endif #ifdef OUTPUT_READABLE_WORLDACCEL // display initial world-frame acceleration, adjusted to remove gravity // and rotated based on known orientation from quaternion mpu.dmpGetQuaternion(&q, fifoBuffer); mpu.dmpGetAccel(&aa, fifoBuffer); mpu.dmpGetGravity(&gravity, &q); mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity); mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q); Serial.print(“aworld\t”); Serial.print(aaWorld.x); Serial.print(“\t”); Serial.print(aaWorld.y); Serial.print(“\t”); Serial.println(aaWorld.z); #endif #ifdef OUTPUT_TEAPOT // display quaternion values in InvenSense Teapot demo format: teapotPacket[2] = fifoBuffer[0]; teapotPacket[3] = fifoBuffer[1]; teapotPacket[4] = fifoBuffer[4]; teapotPacket[5] = fifoBuffer[5]; teapotPacket[6] = fifoBuffer[8]; teapotPacket[7] = fifoBuffer[9]; teapotPacket[8] = fifoBuffer[12]; teapotPacket[9] = fifoBuffer[13]; Serial.write(teapotPacket, 14); teapotPacket[11]++; // packetCount, loops at 0xFF on purpose #endif // blink LED to indicate activity blinkState = !blinkState; digitalWrite(LED_PIN, blinkState); } }

예제를 참고해서 적느라 코드가 좀 길다.(복붙 매우 권장)

센서 동작 사진

실행시키려면 아무 문자나 입력 후 엔터하자

코드를 동작시키고 아무 문자나 (ex, A) 입력하면 센서가 동작한다.

구부렸을때

구부렸을때 값이 달라지는것을 확인할 수 있다.

또 다른쪽으로 휘게 했을때

다른쪽으로 휘게 해도 아까와는 값이 또 달라지는것을 확인할 수 있다.

TMI 정보

MPU6050 모듈은 드론에도 적용되는 자이로/가속도 센서이다.

이 모듈이 있어야 드론이 회전, 기울기 등을 측정할 수 있다고 한다. 모터 정밀 조정을 위해.

MPU6050 모듈은 가속도 자이로 센서를 이용하여 드론의 기울어진 정도와 회전한 정도를 알아낼 수있다.

회전정도와 기울기정도를 가지고 모터의 속도를 조절하여 드론을 올바르게 균형을 잡는데 도와주기도 한다.

간단한 자이로/가속도 센서 활용(?)법을 올렸다.

저번 색상센서와 마찬가지로 난이도는 쉬운편이다.

부품만 있으면 누구나 시도해볼만 하다.

MPU6050 가속도 센서, 자이로 센서로 측정값 읽어 보기

반응형

MPU-6050 센서란?

그림1

MPU-6050는 그림1과 같다. 모듈로 되어 있는 PCB 인데 내부에는 MEMS 가속도센서(Accelerometer)와 MEMS 자이로센서(gyro)를 포함하고 있다.

그림처럼 SCL, SDA 통신라인을 이용하는 I2C 통신을 사용한다.

내부에 16비트 ADC 장치를 가지고 있어서 정밀한 결과를 출력해준다.

참고로 나는 MPU-6050을 네이버 쇼핑에서 구입했는데 약 3천원 정도 했다.

MPU6050에는 1024바이트 FIFO 버퍼가 있는데 만일 센서 값을 읽어서 버퍼에 저장하면 Arduino에 Interrupt 신호를 보내고 아두이노는 이 신호를 통해 버퍼에 데이터가 있음을 알고 읽어 온다.

SCL, SDL 라인을 사용하면 MPU6050은 자동으로 I2C에서 Slave 역할을 한다. 내부에 자체 I2C 컨트롤러가 있어서 XDA, XCL 핀을 사용해서 다른 센서와 I2C 통신을 하여 마스터 역할을 할 수 있다. 그리고 받은 값은 다른 장치(아두이노)에 보낼 수 있다.

MPU-6050 간단한 예제 실행

그림2 그림3

그림2는 실제 연결한 사진이고 그림3은 fritzing 툴을 사용하여 간단하게 그린 화면이다.

I2C 통신을 사용하기 위해 아두이노 핀맵에서 통신 가능한 핀맵을 확인하여야 한다. Arduino uno(우노) 같은 경우 2개의 I2C 통신라인을 가지고 있다. A4(SDA), A5(SCL)이 기본 I2C 이다. 다른 핀을 사용하고 싶으면 pin map 을 검색해서 찾아보길 바란다.

그리고 2번 핀에는 MPU6050의 Interrupt 핀을 연결 했다. 앞서 Interrupt를 FIFO에서 읽기 위해 사용한다고 언급하였다.

나머지는 전원 연결 이다.

코드>>

// MPU-6050 Short Example Sketch // By Arduino User JohnChi // August 17, 2014 // Public Domain #include const int MPU_addr=0x68; // I2C address of the MPU-6050 int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ; void setup(){ Wire.begin(); 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); } 결과화면>>

주석>>

setup에서 아두이노와 MPU6050과 I2C 통신을 시작한다. 그리고 컴퓨터와 Serial 통신을 시작한다. 속도는 9600bps이므로 속도를 여기에 맞추자.

loop에서는 MPU6050에서의 값을 레지스터에서 읽어오는데 읽은 값은 가속도센서와 온도와 GYRO 값이다. 우선 온도는 쉽게 알수 있어서 확인해 보았는데 지금 10도인데 결과에는 40도쯤 나와 있다…..뭔가 이상하다…. 나도 공부중이라 잘 모르는 부분이 많다 ㅠ 혹시 아시는 분 계시면 댓글 부탁~!!!

우선은 간단 예제는 여기서 정리하고 자세한 내용은 다른 코드도 확인하여 디버깅 후에 업데이트 하겠다.

해당 코드는 아래 링크에서 가져왔으니 필요한 사람은 참조하길 바란다. 쉬운 예제 이 외에도 여러 코드가 있다.

원문 link>>

playground.arduino.cc/Main/MPU-6050/#short

반응형

에듀이노-코딩교육 전문 쇼핑몰

상품결제정보 고액결제의 경우 안전을 위해 카드사에서 확인전화를 드릴 수도 있습니다. 확인과정에서 도난 카드의 사용이나 타인 명의의 주문등 정상적인 주문이 아니라고 판단될 경우 임의로 주문을 보류 또는 취소할 수 있습니다.

무통장 입금은 상품 구매 대금은 PC뱅킹, 인터넷뱅킹, 텔레뱅킹 혹은 가까운 은행에서 직접 입금하시면 됩니다.

주문시 입력한 입금자명과 실제입금자의 성명이 반드시 일치하여야 하며, 7일 이내로 입금을 하셔야 하며 입금되지 않은 주문은 자동취소 됩니다.

배송정보 배송 방법 : 택배

배송 지역 : 전국지역

배송 비용 : 3,000원

배송 기간 : 1일 ~ 2일

배송 안내 : – 제주도, 산간벽지나 도서지방은 별도의 추가금액을 지불하셔야 하는 경우가 있습니다.

고객님께서 주문하신 상품은 입금 확인후 배송해 드립니다. 다만, 상품종류에 따라서 상품의 배송이 다소 지연될 수 있습니다.

교환 및 반품정보 교환 및 반품이 가능한 경우

– 상품을 공급 받으신 날로부터 7일이내 단, 가전제품의

경우 포장을 개봉하였거나 포장이 훼손되어 상품가치가 상실된 경우에는 교환/반품이 불가능합니다.

– 공급받으신 상품 및 용역의 내용이 표시.광고 내용과

다르거나 다르게 이행된 경우에는 공급받은 날로부터 3월이내, 그사실을 알게 된 날로부터 30일이내

교환 및 반품이 불가능한 경우

– 고객님의 책임 있는 사유로 상품등이 멸실 또는 훼손된 경우. 단, 상품의 내용을 확인하기 위하여

포장 등을 훼손한 경우는 제외

– 포장을 개봉하였거나 포장이 훼손되어 상품가치가 상실된 경우

(예 : 가전제품, 식품, 음반 등, 단 액정화면이 부착된 노트북, LCD모니터, 디지털 카메라 등의 불량화소에

따른 반품/교환은 제조사 기준에 따릅니다.)

– 고객님의 사용 또는 일부 소비에 의하여 상품의 가치가 현저히 감소한 경우 단, 화장품등의 경우 시용제품을

제공한 경우에 한 합니다.

– 시간의 경과에 의하여 재판매가 곤란할 정도로 상품등의 가치가 현저히 감소한 경우

– 복제가 가능한 상품등의 포장을 훼손한 경우

(자세한 내용은 고객만족센터 1:1 E-MAIL상담을 이용해 주시기 바랍니다.)

※ 고객님의 마음이 바뀌어 교환, 반품을 하실 경우 상품반송 비용은 고객님께서 부담하셔야 합니다.

(색상 교환, 사이즈 교환 등 포함)

키워드에 대한 정보 mpu6050 아두 이노

다음은 Bing에서 mpu6050 아두 이노 주제에 대한 검색 결과입니다. 필요한 경우 더 읽을 수 있습니다.

이 기사는 인터넷의 다양한 출처에서 편집되었습니다. 이 기사가 유용했기를 바랍니다. 이 기사가 유용하다고 생각되면 공유하십시오. 매우 감사합니다!

사람들이 주제에 대해 자주 검색하는 키워드 【 아두이노 완공 #29 】 MPU6050 자이로 가속도 센서 , 바로 이 영상으로 시작하세요~!

  • 라즈이노
  • 라즈이노IOT
  • 아두이노
  • 라즈베리파이
  • Arduino
  • RaspberryPi
  • 프로그래밍
  • 프로세싱
  • 라이노
  • 3D프린터
  • 영상강좌
  • 배우기강좌

【 #아두이노 #완공 ##29 #】 #MPU6050 #자이로 #가속도 #센서 #, #바로 #이 #영상으로 #시작하세요~!


YouTube에서 mpu6050 아두 이노 주제의 다른 동영상 보기

주제에 대한 기사를 시청해 주셔서 감사합니다 【 아두이노 완공 #29 】 MPU6050 자이로 가속도 센서 , 바로 이 영상으로 시작하세요~! | mpu6050 아두 이노, 이 기사가 유용하다고 생각되면 공유하십시오, 매우 감사합니다.

See also  Sk 매직 얼음 정수기 | 2022 얼음정수기 선택하는법! Sk매직 신제품 올인원플러스 얼음정수기! 120 개의 자세한 답변

Leave a Comment