라즈베리파이, 아두이노

[간단한 아두이노 코딩] 9. XYZ 가속도 센서 사용하기(GY-61)

포도알77 2020. 11. 24. 10:12

XYZ 가속도 센서 사용하기(GY-61)

 

1. 가속도와 가속도 센서의 동작 원리

  가속도 센서는 쉽게 말해 속도의 변화량을 측정하는 센서이다. 가속도를 가장 쉽게 느낄 수 있는 것은 차량의 속도를 올리거나 줄일 때 몸이 기울어지는 현상이 있다.

 

 이처럼 속도가 단위 시간동안 변화한 양을 가속도라고 부른다. ( 속도 = 거리/시간,  가속도 = 속도/시간)

 

 또 다른 예로는 우리가 늘 느끼는 중력 가속도가 있다. 중력 가속도는 잘 알려진바와 같이 약 9.8m/s^2이며, 가속도 센서에도 중력은 존재하기 때문에 중력 방향(지구의 중심)으로 가속도가 측정된다.

 

 가속도 센서의 동작 원리는 뉴턴 제 2법칙(가속도 법칙) F=ma (m 질량, a 가속도)와 용수철 법칙으로 잘 알려진 후크의 법칙 F=kx(k 용수철 상수, x 용수철 길이 변화량)을 이용하여 F = ma = kx, a = kx/m의 공식을 도출할 수 있고, k와 m은 상수이므로 결국 가속도는 용수철 길이 변화량에 비례함을 알 수 있다.

 

 이 정보를 바탕으로 가속도 센서에는 질량을 가진 물체와 스프링을 이용하여 변화량에 따른 가속도를 측정하게 된다.

 

2. 가속도 센서 이용하기

 가속도 센서는 X축, Y축 그리고 Z축에 대해 발생하는 중력 가속도를 측정해준다. 따라서 정지된 상태에서 각 축별로 중력 가속도 -G(9.8)~G(9.8)까지 측정된다.

 

 가속도 센서를 이용하면 삼각함수 공식에 의해 축과 중력 가속도 작용하는 방향 사이의 각도를 계산할 수 있다. 

 위의 그림에서는 각도를 계산하는 방법을 말해주고 있다. 사실 대단하게 쓰여진 것처럼 보이지만, 센서는 X, Y, Z 축에 대한 가속도값을 반환하므로 삼각함수의 탄젠트(밑변분의 높이)를 이용하면 쉽게 각도를 알 수 있다.

 

 여기서 Y,Z 축 모두 해당 각도로 기울어진 상태이므로, angle X라고 표현하는거 같은데 여기까진 확실히 잘 모르겠다. 아무튼 두 축이 같은 값이므로 여기서도 X축의 각도라고 표현하고 진행하겠다.

 

 이 각도는 결국에는 x,y,z축이 있으므로 x의 각도는 y,z, y축의 각도는z, x, z축의 각도는 x,y로 구할 수 있다는 것을 직관적으로 알 수 있다.

 

 그렇다면 각도 공식은 아래와 같이 구해진다.  여기서 편하게 각도라고 말했지만 쎄타는 라디안이다.

 

 

 

3. 회로도

 회로도 그리는 프로그램에 GY-61 (ADXL335)의 레이아웃이 조금 다르게 나온다. VCC, GND를 연결하고 X, Y, Z핀을 A0, A1, A2에 연결하면 된다.

 

 

4. 소스코드

 소스코드는 별도로 짜는것 보다 기존에 잘 알려진 것을 분석하는 편이 이해하기 더 편할 것 같아 설명을 첨부한다.

 

// 핀설정
const int xPin = 0;
const int yPin = 1;
const int zPin = 2;

// GY61(ADXL335)에서 각 핀별로 반환되는 최소, 최대값
int minVal = 265;
int maxVal = 402;

// 각도를 저장하는 편수
double x, y, z;

void setup()
{
  Serial.begin(9600); 
}

void loop()
{
  // x, y, z 축의 GY-61 아날로그 데이터를 저장
  int xRead = analogRead(xPin);
  int yRead = analogRead(yPin);
  int zRead = analogRead(zPin);

  // map(value, fromLow, fromHigh, toLow, toHigh)
  // 이 함수는 현재 값의 하한(fromLow)과 상한(fromHigh)에 대해서
  // 매핑하고자 하는 하한(toLow)과 상한(toHigh)로 value값을 변경해준다.
  // 예를 들어 0~360도를 0~2Pi까지 변환하고 싶다면
  // map(angle, 0, 360, 0, 2*PI)가 된다.
 
  // 각 축이 중력가속도의 k배까지 측정할 수 있을 때 결국 범위는 -k*G ~ k*G까지이다.
  // 따라서 센서에서 얻어진 축의 값을 -90 ~ 90으로 매핑하는 것이다.
  // 각도를 구하기 위해서 반드시 90을 쓸 필요는 없다는 뜻이다.
  int xAng = map(xRead, minVal, maxVal, -90, 90);
  int yAng = map(yRead, minVal, maxVal, -90, 90);
  int zAng = map(zRead, minVal, maxVal, -90, 90);

  // 주어진 가속도 값을 이용하여 각도를 구하는 함수이다.
  // atan2는 tan-1(y/x)일 때, atan(y,x)로 쓸 수 있다.
  // 여기서 -val으로 쓰는 이유는, 센서에서 얻어진 값은 축의 정방향
  //(Z축이면 Z축 센서가 위를 보는 방향)에서 항상 -g에 값이 출력되기 때문이다.

  // atan에서 각도를 구하는 방법은 RAD_TO_DEG * atan이다.
  // 삼각 함수는 항상 raidan을 쓴다. 따라서 radian에 해당하는 값을 곱해주어야 한다.

  // 구해진 atan2값에서 PI를 더해주는 것은, atan2가 -pi ~ pi 값으로 출력하기 때문에,
  // 0~360도까지 각도를 구하기 위해서 pi를 한번 더 구해주는 것이다.
  // 여기서도 map 함수를 쓸 수 있으면 좋겠지만, map 함수는 정수 타입만 매핑된다.
  // 따라서 앞서 언급한 수학 공식에 따라 아래와 같이 다시 계산하는 것이다.
  x = RAD_TO_DEG * (atan2(-yAng, -zAng) + PI);
  y = RAD_TO_DEG * (atan2(-xAng, -zAng) + PI);
  z = RAD_TO_DEG * (atan2(-yAng, -xAng) + PI);

  Serial.print("x: ");
  Serial.print(x);
  Serial.print(" | y: ");
  Serial.print(y);
  Serial.print(" | z: ");
  Serial.println(z);

  delay(1000);
}
페이스북으로 공유카카오톡으로 공유카카오스토리로 공유트위터로 공유URL 복사