산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

MEMS 센서 탐구: 아두이노 프로젝트를 위한 가속도계, 자이로스코프, 자력계

MEMS란 무엇인가?

이 튜토리얼에서는 MEMS 가속도계, 자이로스코프, 자력계의 작동 원리와 아두이노 보드와의 사용법을 배웁니다. 또한 Processing IDE를 사용하여 센서를 활용한 실용적인 애플리케이션도 만들어 보겠습니다.

MEMS(Micro-Electro-Mechanical Systems)는 0.001mm~0.1mm 크기의 마이크로 구성 요소로 이루어진 매우 작은 시스템 또는 장치입니다. 이 구성 요소들은 실리콘, 폴리머, 금속, 세라믹 등으로 만들어지며, 보통 CPU(마이크로컨트롤러)와 결합되어 시스템을 완성합니다.

이제 각 MEMS 센서가 어떻게 작동하는지 간단히 설명하겠습니다.

MEMS 가속도계

가속도계는 정전 용량의 변화를 측정하여 가속도를 측정합니다. 마이크로 구조는 대략 다음과 같습니다. 한 방향으로만 움직일 수 있도록 스프링에 연결된 질량과 고정된 외부 판이 있습니다. 특정 방향으로 가속도가 가해지면 질량이 움직이고 판과 질량 사이의 정전 용량이 변합니다. 이 정전 용량 변화를 측정하고 처리하여 특정 가속도 값에 대응시킵니다.

MEMS 센서 탐구: 아두이노 프로젝트를 위한 가속도계, 자이로스코프, 자력계

MEMS 자이로스코프

자이로스코프는 코리올리 효과(Coriolis Effect)를 사용하여 각속도를 측정합니다. 질량이 특정 속도로 특정 방향으로 움직이고 있을 때 외부 각속도가 가해지면(초록 화살표), 힘(파란/빨간 화살표)이 발생하여 질량이 수직 방향으로 변위됩니다. 가속도계와 유사하게 이 변위로 정전 용량 변화가 발생하며, 이를 측정 및 처리하여 특정 각속도에 대응시킵니다.

MEMS 센서 탐구: 아두이노 프로젝트를 위한 가속도계, 자이로스코프, 자력계

자이로스코프의 마이크로 구조는 대략 다음과 같습니다. 지속적으로 움직이는(진동하는) 질량에 외부 각속도가 가해지면 질량의 유연한 부분이 움직여 수직 변위를 만듭니다.

MEMS 센서 탐구: 아두이노 프로젝트를 위한 가속도계, 자이로스코프, 자력계

MEMS 자력계

자력계는 홀 효과(Hall Effect) 또는 자기 저항 효과(Magneto Resistive Effect)를 사용하여 지구 자기장을 측정합니다. 시중 센서의 약 90%가 홀 효과를 사용하며, 그 작동 원리는 다음과 같습니다.

MEMS 센서 탐구: 아두이노 프로젝트를 위한 가속도계, 자이로스코프, 자력계

사진과 같은 도전성 판에 전류를 흐르게 하면 전자가 판의 한쪽에서 다른 쪽으로 직선으로 흐릅니다. 여기에 자기장을 가까이 가져오면 직선 흐름이 방해받아 전자가 판의 한쪽으로, 양극이 다른 쪽으로 치우칩니다. 이때 양쪽 사이에 미터를 연결하면 자기장의 세기와 방향에 따른 전압을 측정할 수 있습니다.

MEMS 센서 탐구: 아두이노 프로젝트를 위한 가속도계, 자이로스코프, 자력계

나머지 10%의 센서는 자기 저항 효과를 사용합니다. 이 센서는 자기장에 민감한 재료(주로 철(Fe)과 니켈(Ni) 조성)를 사용하여, 자기장에 노출되면 저항이 변합니다.

아두이노와 MEMS 센서


이제 이 센서들을 아두이노 보드에 연결하여 활용해 보겠습니다. 예제로 GY-80 브레이크아웃 보드를 사용하며, 이 보드에는 다음 센서들이 탑재되어 있습니다: ADXL345 3축 가속도계, L3G4200D 3축 자이로스코프, MC5883L 3축 자력계, 그리고 기압계와 온도계(이 튜토리얼에서는 사용하지 않음).

필요한 부품

MEMS 센서 탐구: 아두이노 프로젝트를 위한 가속도계, 자이로스코프, 자력계

이 보드는 I2C 통신 프로토콜을 사용하여 두 개의 선만으로 모든 센서와 통신할 수 있습니다. 아두이노와 센서 간 통신을 위해 각 센서의 고유 장치 주소와 데이터를 읽기 위한 내부 레지스터 주소를 알아야 합니다. 이 주소들은 각 센서의 데이터시트에서 확인할 수 있습니다:

I2C 통신 작동 원리에 대한 자세한 내용은 I2C 통신 프로토콜 튜토리얼을 참조하세요.

소스 코드

이제 센서에서 데이터를 가져오는 코드를 살펴보겠습니다. 가속도계부터 시작하며, 각 코드 전에 설명과 코드 내 주석으로 추가 설명을 제공합니다.

아두이노 가속도계 코드

먼저 아두이노 Wire 라이브러리를 포함하고 센서의 레지스터 주소를 정의합니다. 설정 섹션에서 Wire 라이브러리를 초기화하고 결과를 시리얼 모니터에 표시하기 위해 시리얼 통신을 시작합니다. 또한 Power_CTL 레지스터에 적절한 바이트를 전송하여 센서를 활성화(측정 모드)해야 합니다.

#include <Wire.h>

//--- 가속도계 레지스터 주소
#define Power_Register 0x2D
#define X_Axis_Register_DATAX0 0x32
#define X_Axis_Register_DATAX1 0x33
#define Y_Axis_Register_DATAY0 0x34
#define Y_Axis_Register_DATAY1 0x35
#define Z_Axis_Register_DATAZ0 0x36
#define Z_Axis_Register_DATAZ1 0x37

int ADXAddress = 0x53;  // 장치 주소 (8비트는 읽기 모드 선택용)
int X0, X1, X_out;
int Y0, Y1, Y_out;
int Z1, Z0, Z_out;
float Xa, Ya, Za;

void setup() {
  Wire.begin();  // Wire 라이브러리 초기화
  Serial.begin(9600);
  delay(100);
  
  Wire.beginTransmission(ADXAddress);
  Wire.write(Power_Register);  // Power_CTL 레지스터
  Wire.write(8);  // 비트 D3 높게 설정으로 측정 활성화 (0000 1000)
  Wire.endTransmission();
}

void loop() {
  // X축
  Wire.beginTransmission(ADXAddress);
  Wire.write(X_Axis_Register_DATAX0);
  Wire.write(X_Axis_Register_DATAX1);
  Wire.endTransmission();
  Wire.requestFrom(ADXAddress, 2);  // 2바이트 요청
  
  if (Wire.available() <= 2) {
    X0 = Wire.read();
    X1 = Wire.read();
    // 원시 데이터를 X축 가속도로 변환 - 출력은 2의 보수
    // X0: 최하위 바이트, X1: 최상위 바이트
    X1 = X1 << 8;
    X_out = X0 + X1;
    Xa = X_out / 256.0;  // Xa = -1 ~ +1, X축에 작용하는 중력 가속도
  }
  
  // Y축 (동일 방식)
  Wire.beginTransmission(ADXAddress);
  Wire.write(Y_Axis_Register_DATAY0);
  Wire.write(Y_Axis_Register_DATAY1);
  Wire.endTransmission();
  Wire.requestFrom(ADXAddress, 2);
  if (Wire.available() <= 2) {
    Y0 = Wire.read();
    Y1 = Wire.read();
    Y1 = Y1 << 8;
    Y_out = Y0 + Y1;
    Ya = Y_out / 256.0;
  }
  
  // Z축 (동일 방식)
  Wire.beginTransmission(ADXAddress);
  Wire.write(Z_Axis_Register_DATAZ0);
  Wire.write(Z_Axis_Register_DATAZ1);
  Wire.endTransmission();
  Wire.requestFrom(ADXAddress, 2);
  if (Wire.available() <= 2) {
    Z0 = Wire.read();
    Z1 = Wire.read();
    Z1 = Z1 << 8;
    Z_out = Z0 + Z1;
    Za = Z_out / 256.0;
  }
  
  // 시리얼 모니터에 출력
  Serial.print("Xa= "); Serial.print(Xa);
  Serial.print(" Ya= "); Serial.print(Ya);
  Serial.print(" Za= "); Serial.println(Za);
}

아두이노 자이로스코프 코드

자이로스코프 데이터 읽기도 가속도계와 유사합니다. 레지스터 주소와 변수를 정의하고, 설정 섹션에서 CTRL_REG1을 사용하여 센서를 깨우고 일반 모드로 설정하며, 감도도 선택합니다. 이 예제에서는 2000dps 감도 모드를 선택합니다.

루프 섹션에서 X, Y, Z축 데이터를 읽고 원시 데이터를 각도 값으로 변환합니다. 데이터시트에 따르면 2000dps 감도 모드는 70 mdps/digit 단위에 해당하므로, 원시 출력 데이터에 0.07을 곱해 초당 도(degrees per second) 단위의 각속도를 구합니다. 각속도에 시간을 곱하면 각도 값이 됩니다. 루프 섹션 상단과 하단에서 millis() 함수를 사용하여 각 루프의 시간 간격(dt)을 계산합니다.

#include <Wire.h>

//--- 자이로 레지스터 주소
#define Gyro_gX0 0x28
#define Gyro_gX1 0x29
#define Gyro_gY0 0x2A
#define Gyro_gY1 0x2B
#define Gyro_gZ0 0x2C
#define Gyro_gZ1 0x2D

int Gyro = 0x69;  // 장치 주소
int gX0, gX1, gX_out;
int gY0, gY1, gY_out;
int gZ0, gZ1, gZ_out;
float Xg, Yg, Zg;
float angleX, angleY, angleZ, angleXc, angleYc, angleZc;
unsigned long start, finished, elapsed;
float dt = 0.015;

void setup() {
  Wire.begin();
  Serial.begin(9600);
  delay(100);
  
  Wire.beginTransmission(Gyro);
  Wire.write(0x20);  // CTRL_REG1 - 전원 모드
  Wire.write(15);    // 일반 모드: 15d - 00001111b
  Wire.endTransmission();
  
  Wire.beginTransmission(Gyro);
  Wire.write(0x23);  // CTRL_REG4 - 감도, 스케일 선택
  Wire.write(48);    // 2000dps: 48d - 00110000b
  Wire.endTransmission();
}

void loop() {
  start = millis();
  
  // X축 읽기
  Wire.beginTransmission(Gyro);
  Wire.write(Gyro_gX0);
  Wire.endTransmission();
  Wire.requestFrom(Gyro, 1);
  if (Wire.available() <= 1) gX0 = Wire.read();
  
  Wire.beginTransmission(Gyro);
  Wire.write(Gyro_gX1);
  Wire.endTransmission();
  Wire.requestFrom(Gyro, 1);
  if (Wire.available() <= 1) gX1 = Wire.read();
  
  // Y축, Z축 읽기 (동일 방식)...
  
  //---------- X축 처리
  gX1 = gX1 << 8;
  gX_out = gX0 + gX1;
  Xg = gX_out * 0.07;  // 각속도
  angleXc = Xg * dt;   // 각속도 * dt = 각도
  angleX = angleX + angleXc;
  
  // Y축, Z축 처리 (동일 방식)...
  
  // 시리얼 모니터 출력
  Serial.print("angleX= "); Serial.print(angleX);
  Serial.print(" angleY= "); Serial.print(angleY);
  Serial.print(" angleZ= "); Serial.println(angleZ);
  
  delay(10);
  
  // dt 계산
  finished = millis();
  elapsed = finished - start;
  dt = elapsed / 1000.0;
  start = elapsed = 0;
}

아두이노 자력계 코드

자력계도 비슷한 기법을 사용합니다. 레지스터 주소를 정의하고 설정 섹션에서 연속 측정 모드로 설정합니다. 루프 섹션에서 각 축의 원시 데이터를 이전 센서들과 같은 방법으로 가져옵니다.

원시 데이터를 자기장 값(가우스 단위)으로 변환합니다. 데이터시트에 따르면 기본 감도 모드는 0.92mG/digit이므로, 원시 데이터에 0.00092를 곱해 가우스 단위의 지구 자기장을 구합니다.

#include <Wire.h>  // I2C 아두이노 라이브러리

#define Magnetometer_mX0 0x03
#define Magnetometer_mX1 0x04
#define Magnetometer_mZ0 0x05
#define Magnetometer_mZ1 0x06
#define Magnetometer_mY0 0x07
#define Magnetometer_mY1 0x08

int mX0, mX1, mX_out;
int mY0, mY1, mY_out;
int mZ0, mZ1, mZ_out;
float Xm, Ym, Zm;

#define Magnetometer 0x1E  // HMC5883의 I2C 7비트 주소

void setup() {
  Serial.begin(9600);
  Wire.begin();
  delay(100);
  
  Wire.beginTransmission(Magnetometer);
  Wire.write(0x02);  // 모드 레지스터 선택
  Wire.write(0x00);  // 연속 측정 모드
  Wire.endTransmission();
}

void loop() {
  // X축
  Wire.beginTransmission(Magnetometer);
  Wire.write(Magnetometer_mX1);
  Wire.endTransmission();
  Wire.requestFrom(Magnetometer, 1);
  if (Wire.available() <= 1) mX0 = Wire.read();
  
  Wire.beginTransmission(Magnetometer);
  Wire.write(Magnetometer_mX0);
  Wire.endTransmission();
  Wire.requestFrom(Magnetometer, 1);
  if (Wire.available() <= 1) mX1 = Wire.read();
  
  // Y축, Z축 읽기 (동일 방식)...
  
  //---- X축 변환
  mX1 = mX1 << 8;
  mX_out = mX0 + mX1;
  Xm = mX_out * 0.00092;  // 가우스 단위
  // 지구 자기장은 0.25~0.65 가우스 범위이므로 이 정도 값이 나와야 함
  
  // Y축, Z축 변환 (동일 방식)...
  
  // 각 축 값 출력
  Serial.print("x: "); Serial.print(Xm);
  Serial.print(" y: "); Serial.print(Ym);
  Serial.print(" z: "); Serial.println(Zm);
  
  delay(50);
}

Processing IDE로 만든 MEMS 디지털 나침반이라는 멋진 애플리케이션 예시입니다. 자세한 내용과 소스 코드는 다음 링크에서 확인하세요:

MEMS 센서 탐구: 아두이노 프로젝트를 위한 가속도계, 자이로스코프, 자력계

제조공정

  1. 자기계란? 기본 원리, 작동 원리 및 실생활 응용
  2. 신뢰성의 인터넷(Internet of Reliability)에서 데이터 활용: 효과적 관리 전략
  3. 아두이노 나노와 MPU-6050으로 실시간 자이로스코프 게임 만들기
  4. NeoPixel 링과 Arduino로 만드는 인터랙티브 자이로스코프 LED 디스플레이
  5. K30 CO2 센서: 실시간 실내 공기질 모니터링
  6. 1Sheeld와 아두이노로 시각/청각 장애인 간 소통 돕기
  7. 스마트 저금통 만들기: 아두이노 나노로 동전 인식기 제어하기
  8. 아두이노 블루투스로 LED 제어하기 - HC-05 & MIT App Inventor 입문 가이드
  9. DFRobot 정전식 지문 인식 센서 아두이노/ESP8266 연동 가이드
  10. 아두이노 메가와 센서를 활용한 인터랙티브 넥시온 HMI 프로젝트