이 튜토리얼에서는 아두이노와 ADXL345 가속도 센서를 사용하여 각도를 측정하고 방향을 추적하는 방법을 배웁니다. 자세한 내용은 아래 동영상을 시청하거나 글로 된 튜토리얼을 참조하세요.
본문에 나와있는 아두이노를 이용한 여러 센서 인터페이스 링크를 확인하세요.

목차입니다.
개요
ADXL345 가속도계 작동 방식
아두이노를 이용해 ADXL345 가속도계 데이터를 읽는 방법
ADXL345 가속도계 아두이노 코드
ADXL345 가속도계 교정
아두이노와 ADXL345 가속도계를 이용한 방향 추적 - 3D 시각화
개요
먼저 센서의 작동 원리와 데이터 판독 방법을 설명한 후, Processing 개발 환경을 이용하여 가속도계 방향을 3D로 시각화해 보겠습니다.

아두이노와 ADXL345 가속도계 사용법
ADXL345 가속도계 작동 방식
우선 ADXL345 센서의 작동 원리를 살펴보겠습니다. 이 센서는 3축 가속도계로, 정적 및 동적 가속도를 모두 측정할 수 있습니다. 지구 중력은 정적 가속도의 대표적인 예이며, 동적 가속도는 진동, 움직임 등에 의해 발생합니다.

ADXL345 가속도계 작동 원리
가속도의 측정 단위는 미터/초²(m/s²)입니다. 하지만 가속도계 센서는 보통 측정값을 "g" 또는 중력 가속도로 표시합니다. 1g는 지구 중력의 값으로, 9.8m/s²와 같습니다.
따라서 가속도계를 평평하게 놓고 Z축이 중력 방향과 반대인 위쪽을 향하도록 설치하면 센서의 Z축 출력은 1g가 됩니다. 반면에 X축과 Y축 출력은 0이 되는데, 이는 중력이 이 축들에 수직으로 작용하여 전혀 영향을 미치지 않기 때문입니다.

ADXL345 3축 가속도계 출력 데이터
센서를 뒤집으면 Z축 출력은 -1g가 됩니다. 즉, 센서의 방향에 따라 중력에 대한 센서 출력값이 -1g에서 +1g까지 달라질 수 있다는 뜻입니다.

adxl345 Z축 출력
따라서 이 데이터를 바탕으로 삼각법 계산을 이용하면 센서가 위치한 각도를 계산할 수 있습니다.
아두이노를 이용해 ADXL345 가속도계 데이터를 읽는 방법
자, 이제 아두이노를 이용해 ADXL345 가속도계 데이터를 읽는 방법을 살펴보겠습니다. 이 센서는 아두이노와 통신하기 위해 I2C 프로토콜을 사용하므로 연결선 두 가닥과 전원선 두 가닥만 있으면 됩니다.

아두이노와 ADXL345 가속도계 회로도
MEMS 가속도계, 자이로스코프 및 자기계 작동 방식도 참조하십시오.
ADXL345 가속도계 아두이노 코드
다음은 ADXL345 가속도계 데이터를 읽는 아두이노 코드입니다.
/*
Arduino and ADXL345 Accelerometer Tutorial
by Dejan, https://howtomechatronics.com
*/
#include <Wire.h> // Wire library - used for I2C communication
int ADXL345 = 0x53; // The ADXL345 sensor I2C address
float X_out, Y_out, Z_out; // Outputs
void setup() {
Serial.begin(9600); // Initiate serial communication for printing the results on the Serial monitor
Wire.begin(); // Initiate the Wire library
// Set ADXL345 in measuring mode
Wire.beginTransmission(ADXL345); // Start communicating with the device
Wire.write(0x2D); // Access/ talk to POWER_CTL Register - 0x2D
// Enable measurement
Wire.write(8); // (8dec -> 0000 1000 binary) Bit D3 High for measuring enable
Wire.endTransmission();
delay(10);
}
void loop() {
// === Read acceleromter data === //
Wire.beginTransmission(ADXL345);
Wire.write(0x32); // Start with register 0x32 (ACCEL_XOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(ADXL345, 6, true); // Read 6 registers total, each axis value is stored in 2 registers
X_out = ( Wire.read()| Wire.read() << 8); // X-axis value
X_out = X_out/256; //For a range of +-2g, we need to divide the raw values by 256, according to the datasheet
Y_out = ( Wire.read()| Wire.read() << 8); // Y-axis value
Y_out = Y_out/256;
Z_out = ( Wire.read()| Wire.read() << 8); // Z-axis value
Z_out = Z_out/256;
Serial.print("Xa= ");
Serial.print(X_out);
Serial.print(" Ya= ");
Serial.print(Y_out);
Serial.print(" Za= ");
Serial.println(Z_out);
}
설명: 먼저 I2C 통신에 사용되는 Wire.h 라이브러리를 포함해야 합니다. I2C 통신의 작동 방식과 아두이노와의 연동 방법에 대해 더 자세히 알고 싶다면 제가 작성한 다른 상세 튜토리얼을 참고하세요 .
에조익
I2C 통신을 사용하는 각 장치는 고유한 I2C 주소를 가지고 있으며, 이 주소는 센서의 데이터시트( ADXL345 데이터시트 )에서 확인할 수 있습니다. 따라서 주소와 세 개의 출력에 대한 변수를 정의한 후, 설정 섹션에서 먼저 와이어 라이브러리를 초기화하고 가속도계를 측정 모드로 설정해야 합니다. 이를 위해 데이터시트를 다시 살펴보면 POWER_CTL 레지스터의 D3 비트를 HIGH로 설정해야 함을 알 수 있습니다.

adxl345 전원 레지스터 - 측정 모드 활성화
따라서 beginTransmission() 함수를 사용하여 통신을 시작하고, write() 함수를 사용하여 접근할 레지스터를 지정한 다음, 다시 write() 함수를 사용하여 D3 비트를 HIGH로 설정합니다. 여기서 10진수로 8을 쓰는데, 이는 D3 비트를 HIGH로 설정하는 것에 해당합니다.
// Set ADXL345 in measuring mode
Wire.beginTransmission(ADXL345); // Start communicating with the device
Wire.write(0x2D); // Access/ talk to POWER_CTL Register - 0x2D
// Enable measurement
Wire.write(8); // (8dec -> 0000 1000 binary) Bit D3 High for measuring enable
Wire.endTransmission();
이제 루프 섹션에서 센서에서 데이터를 읽습니다. 각 축의 데이터는 2바이트 또는 레지스터에 저장됩니다. 이러한 레지스터의 주소는 데이터시트에서 확인할 수 있습니다.

adxl345 가속도계 xyz 데이터 레지스터
모든 레지스터의 값을 읽으려면 먼저 첫 번째 레지스터부터 시작하여 requestFrom() 함수를 사용하여 6개의 레지스터를 읽도록 요청합니다. 그런 다음 read() 함수를 사용하여 각 레지스터의 데이터를 읽고, 출력값이 2의 보수 형식이므로 적절하게 조합하여 올바른 값을 얻습니다.
// === Read acceleromter data === //
Wire.beginTransmission(ADXL345);
Wire.write(0x32); // Start with register 0x32 (ACCEL_XOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(ADXL345, 6, true); // Read 6 registers total, each axis value is stored in 2 registers
X_out = ( Wire.read()| Wire.read() << 8); // X-axis value
X_out = X_out/256; //For a range of +-2g, we need to divide the raw values by 256, according to the datasheet
Y_out = ( Wire.read()| Wire.read() << 8); // Y-axis value
Y_out = Y_out/256;
Z_out = ( Wire.read()| Wire.read() << 8); // Z-axis value
Z_out = Z_out/256;
센서의 출력값은 선택된 감도에 따라 달라지며, 감도는 ±2g에서 ±16g까지 다양할 수 있습니다. 기본 감도는 ±2g이므로 -1g에서 +1g 사이의 값을 얻으려면 출력값을 256으로 나누어야 합니다. 256 LSB/g는 1g당 256개의 카운트가 있음을 의미합니다.

adxl345 감도 범위 - 데이터시트 참
용도에 따라 적절한 감도를 선택할 수 있습니다. 이 경우 방향 추적에는 ±2g 감도가 적합하지만, 갑작스러운 움직임, 충격 등과 같이 더 큰 가속도를 감지해야 하는 경우에는 DATA_FORMAT 레지스터와 D1 및 D0 비트를 사용하여 다른 감도 범위를 선택할 수 있습니다.

adxl345 감도 범위 레지스터 및 진리표
ADXL345 가속도계 컬리브레이션(교정)
하지만 일단 데이터를 읽으면 시리얼 모니터에 출력하여 값이 예상대로인지 확인할 수 있습니다. 제 경우에는 얻은 값이 예상과 정확히 일치하지 않았는데, 특히 Z축에서 0.1g의 눈에 띄는 오차가 있었습니다.

adxl345 가속도계 교정
이 문제를 해결하려면 3개의 오프셋 보정 레지스터를 사용하여 가속도계를 보정해야 합니다. 보정 방법은 다음과 같습니다. 센서를 평평하게 놓고, 256으로 나누지 않은 RAW 값을 출력합니다.

adxl345 가속도계 교정 과정
여기서 출력값이 얼마나 차이가 나는지 확인할 수 있습니다. 제 경우에는 Z축 출력값이 약 283이었습니다. 이는 양수로 27의 차이입니다. 이제 이 값을 4로 나누면 Z축 오프셋 레지스터에 기록해야 할 값을 얻을 수 있습니다. 코드를 업로드하면 Z축 출력값은 정확히 256, 즉 1g가 될 것입니다.
// This code goes in the SETUP section
// Off-set Calibration
//X-axis
Wire.beginTransmission(ADXL345);
Wire.write(0x1E); // X-axis offset register
Wire.write(1);
Wire.endTransmission();
delay(10);
//Y-axis
Wire.beginTransmission(ADXL345);
Wire.write(0x1F); // Y-axis offset register
Wire.write(-2);
Wire.endTransmission();
delay(10);
//Z-axis
Wire.beginTransmission(ADXL345);
Wire.write(0x20); // Z-axis offset register
Wire.write(-7);
Wire.endTransmission();
delay(10);
필요한 경우 동일한 방법을 사용하여 다른 축도 보정해야 합니다. 참고로 이 보정 값은 레지스터에 영구적으로 기록되지 않습니다. 센서 전원을 켤 때마다 이 값을 레지스터에 기록해야 합니다.
보정 작업이 완료되면 이제 이 두 공식을 사용하여 롤과 피치, 즉 X축을 중심으로 한 회전과 Y축을 중심으로 한 회전을 도 단위로 계산할 수 있습니다.
// Calculate Roll and Pitch (rotation around X-axis, rotation around Y-axis)
roll = atan(Y_out / sqrt(pow(X_out, 2) + pow(Z_out, 2))) * 180 / PI;
pitch = atan(-1 * X_out / sqrt(pow(Y_out, 2) + pow(Z_out, 2))) * 180 / PI;
이러한 공식이 어떻게 작동하는지에 대한 자세한 내용은 Freescale Semiconductor의 애플리케이션 노트를 참조하십시오 .
아두이노와 ADXL345 가속도계를 이용한 방향 추적 - 3D 시각화
좋습니다, 이제 가속도계 3D 시각화 예시를 만들어 보겠습니다.

아두이노와 ADXL345 가속도계를 이용한 방향 추적 - 3D 시각화
그래서 우리는 롤(Roll)과 피치(Pitch) 값을 시리얼 포트를 통해 전송하는 동일한 코드를 사용하고 있습니다. 다음은 전체 아두이노 코드입니다.
/*
Arduino and ADXL345 Accelerometer - 3D Visualization Example
by Dejan, https://howtomechatronics.com
*/
#include <Wire.h> // Wire library - used for I2C communication
int ADXL345 = 0x53; // The ADXL345 sensor I2C address
float X_out, Y_out, Z_out; // Outputs
float roll,pitch,rollF,pitchF=0;
void setup() {
Serial.begin(9600); // Initiate serial communication for printing the results on the Serial monitor
Wire.begin(); // Initiate the Wire library
// Set ADXL345 in measuring mode
Wire.beginTransmission(ADXL345); // Start communicating with the device
Wire.write(0x2D); // Access/ talk to POWER_CTL Register - 0x2D
// Enable measurement
Wire.write(8); // Bit D3 High for measuring enable (8dec -> 0000 1000 binary)
Wire.endTransmission();
delay(10);
//Off-set Calibration
//X-axis
Wire.beginTransmission(ADXL345);
Wire.write(0x1E);
Wire.write(1);
Wire.endTransmission();
delay(10);
//Y-axis
Wire.beginTransmission(ADXL345);
Wire.write(0x1F);
Wire.write(-2);
Wire.endTransmission();
delay(10);
//Z-axis
Wire.beginTransmission(ADXL345);
Wire.write(0x20);
Wire.write(-9);
Wire.endTransmission();
delay(10);
}
void loop() {
// === Read acceleromter data === //
Wire.beginTransmission(ADXL345);
Wire.write(0x32); // Start with register 0x32 (ACCEL_XOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(ADXL345, 6, true); // Read 6 registers total, each axis value is stored in 2 registers
X_out = ( Wire.read() | Wire.read() << 8); // X-axis value
X_out = X_out / 256; //For a range of +-2g, we need to divide the raw values by 256, according to the datasheet
Y_out = ( Wire.read() | Wire.read() << 8); // Y-axis value
Y_out = Y_out / 256;
Z_out = ( Wire.read() | Wire.read() << 8); // Z-axis value
Z_out = Z_out / 256;
// Calculate Roll and Pitch (rotation around X-axis, rotation around Y-axis)
roll = atan(Y_out / sqrt(pow(X_out, 2) + pow(Z_out, 2))) * 180 / PI;
pitch = atan(-1 * X_out / sqrt(pow(Y_out, 2) + pow(Z_out, 2))) * 180 / PI;
// Low-pass filter
rollF = 0.94 * rollF + 0.06 * roll;
pitchF = 0.94 * pitchF + 0.06 * pitch;
Serial.print(rollF);
Serial.print("/");
Serial.println(pitchF);
}
이제 Processing 개발 환경 에서 이러한 값들을 받아 우리가 생성할 3D 객체를 회전시키는 데 사용해야 합니다. 다음은 전체 Processing 코드입니다.
/*
Arduino and ADXL345 Accelerometer - 3D Visualization Example
by Dejan, https://howtomechatronics.com
*/
import processing.serial.*;
import java.awt.event.KeyEvent;
import java.io.IOException;
Serial myPort;
String data="";
float roll, pitch;
void setup() {
size (960, 640, P3D);
myPort = new Serial(this, "COM8", 9600); // starts the serial communication
myPort.bufferUntil('\n');
}
void draw() {
translate(width/2, height/2, 0);
background(33);
textSize(22);
text("Roll: " + int(roll) + " Pitch: " + int(pitch), -100, 265);
// Rotate the object
rotateX(radians(roll));
rotateZ(radians(-pitch));
// 3D 0bject
textSize(30);
fill(0, 76, 153);
box (386, 40, 200); // Draw box
textSize(25);
fill(255, 255, 255);
text("www.HowToMechatronics.com", -183, 10, 101);
//delay(10);
//println("ypr:\t" + angleX + "\t" + angleY); // Print the values to check whether we are getting proper values
}
// Read data from the Serial Port
void serialEvent (Serial myPort) {
// reads the data from the Serial Port up to the character '.' and puts it into the String variable "data".
data = myPort.readStringUntil('\n');
// if you got any bytes other than the linefeed:
if (data != null) {
data = trim(data);
// split the string at "/"
String items[] = split(data, '/');
if (items.length > 1) {
//--- Roll,Pitch in degrees
roll = float(items[0]);
pitch = float(items[1]);
}
}
}
설명: 여기서는 시리얼 라이브러리를 포함하고, 시리얼 포트와 전송 속도를 정의해야 합니다. 전송 속도는 업로드된 아두이노 스케치의 전송 속도와 일치해야 합니다. 그런 다음 수신된 데이터를 읽어 적절한 roll 및 pitch 변수에 저장합니다. 메인 그리기 루프에서는 이러한 값을 사용하여 3D 객체를 회전시킵니다. 이 예에서는 특정 색상과 텍스트가 있는 간단한 상자입니다.
스케치를 실행하면 3D 객체가 나타나고 가속도 센서의 방향을 추적합니다. 여기서 객체가 약간 흔들리는 것을 볼 수 있는데, 이는 가속도 센서가 중력뿐만 아니라 손의 움직임으로 발생하는 작은 힘까지 감지하기 때문입니다. 더 부드러운 결과를 얻으려면 간단한 저역 통과 필터를 사용할 수 있습니다. 저는 아두이노 코드에 이전 상태의 94%에 현재 상태 또는 각도의 6%를 더하는 필터를 구현했습니다.
// Low-pass filter
rollF = 0.94 * rollF + 0.06 * roll;
pitchF = 0.94 * pitchF + 0.06 * pitch;
이 필터를 사용하면 객체의 움직임이 훨씬 부드러워진 것을 알 수 있지만, 반응 속도가 느려지는 부작용도 있습니다. 또한, Z축을 중심으로 한 회전(Yaw) 값을 얻을 수 없다는 점도 확인할 수 있습니다. 3축 가속도계 데이터만으로는 Yaw 값을 계산할 수 없습니다.
이를 실현하고 방향 추적 센서의 전반적인 성능을 향상시키기 위해서는 자이로스코프라는 추가 센서를 포함하고, 그 데이터를 가속도계 데이터와 융합해야 합니다.

ADXL345 가속도계 및 L3G4200D 자이로스코프 또는 MPU6050 6자유도 모듈
따라서 ADXL345 가속도계를 자이로스코프 센서와 함께 사용하거나, 3축 가속도계와 3축 자이로스코프가 하나의 칩에 통합된 MPU6050 IMU를 사용할 수 있습니다 . 이 센서에 대한 자세한 설명은 다음 영상에서 확인하실 수 있습니다.
참고: 아두이노와 MPU6050 가속도계 및 자이로스코프 튜토리얼
이 튜토리얼이 도움이 되셨고 새로운 것을 배우셨기를 바랍니다. 궁금한 점이 있으면 아래 댓글란에 질문해 주세요. 그리고 제 아두이노 프로젝트 모음 도 꼭 확인해 보세요 .
원문 튜토리얼은 다음 링크를 참고하세요.
일요일인데 나와서 이러면은 즐거운 거 맞죠?
'아두이노우노 R4' 카테고리의 다른 글
| 아두이노 IDE에서 ATtiny85 프로그래밍 마스터 1 (1) | 2026.02.16 |
|---|---|
| LDR 및 서보 모터를 사용한 2축 태양광 추적기 아두이노 프로젝트 (0) | 2026.02.14 |
| 아두이노 OLED 메뉴 디스플레이 (2) | 2026.02.03 |
| 아두이노와 3-디스플레이 OLED 시계 (0) | 2026.02.03 |
| Visuino를 사용한 실시간 시계 및 GC9A01 디스플레이 (0) | 2026.01.29 |
| 아두이노로 RGB LED 스트립 제어 (1) | 2025.12.27 |
| MFRC522 RFID 리더 접근 제어 배열 사용 (0) | 2025.12.11 |
| RFID RC522 모듈 Arduino Uno R4 WIFI 인터페이스 (0) | 2025.11.28 |
취업, 창업의 막막함, 외주 관리, 제품 부재!
당신의 고민은 무엇입니까? 현실과 동떨어진 교육, 실패만 반복하는 외주 계약,
아이디어는 있지만 구현할 기술이 없는 막막함.
우리는 알고 있습니다. 문제의 원인은 '명확한 학습, 실전 경험과 신뢰할 수 있는 기술력의 부재'에서 시작됩니다.
이제 고민을 멈추고, 캐어랩을 만나세요!
코딩(펌웨어), 전자부품과 디지털 회로설계, PCB 설계 제작, 고객(시장/수출) 발굴과 마케팅 전략으로 당신을 지원합니다.
제품 설계의 고수는 성공이 만든 게 아니라 실패가 만듭니다. 아이디어를 양산 가능한 제품으로!
귀사의 제품을 만드세요. 교육과 개발 실적으로 신뢰할 수 있는 파트너를 확보하세요.
캐어랩