아두이노 나노와 자이로 센서(GY-521)로 만드는 정밀 드릴 깊이 표시기
부품 및 소모품
부품 수량
아두이노 나노 R3 1
자이로 센서 GY-521 (MPU-6050) 1
7-세그먼트 8자리 디스플레이 모듈 (MAX7219, SPI) 1
푸시 버튼 1
전원 스위치 1
전원: AA/AAA 배터리 홀더 또는 파워뱅크 1
3D 프린트 케이스 및 홀더 1세트
네오디뮴 자석 (부착용) 1
필수 도구 및 장비
3D 프린터 (Anycubic i3 Mega 등)
앱 및 온라인 서비스
프로젝트 소개
벤치 드릴로 정해진 깊이까지 구멍을 뚫으려면 내장 눈금자와 화살표를 읽어야 하는데, 나이가 들수록 밀리미터 단위 판독이 어렵고 조명이 어두우면 거의 불가능합니다. 안경을 쓰자니 쓰고 벗기 번거롭고. 폴 에이커스(Paul Akers)의 "2 Second Lean" 정신으로 더 나은 해결책 을 직접 만들었습니다.
측정 방식 선정
초음파 거리 측정: 반사판이 드릴과 함께 움직여야 해 기계적 장치 필요
와이어 인코더: 풀리, 포크 광센서, 스프링 리턴 등 복잡
로터리 인코더: 기어비 필요, 분해능 한계
대부분 벤치 드릴의 사이드 핸들휠은 약 270° 회전합니다. 이 회전각을 자이로 센서로 측정 하면 케이블 꼬임 없이 단일 저가 부품으로 정밀 깊이 측정이 가능합니다. 센서를 핸들휠 회전축에 직접 부착하면 됩니다.
컨셉
기존 작업 흐름 유지: 드릴로 표면 긁기 → 현재 위치를 '기준점'으로 저장(버튼 누름) → 목표 깊이만큼 더해 '정지점' 설정 → 드릴링 중 정지점 도달 시 알림.
버튼 한 번으로 현재 위치를 정지점으로 저장. 나머지 부품(아두이노, 디스플레이, 배터리)은 자석으로 드릴 본체에 탈부착 가능.
드릴 스핀들에 SW17(17mm) 육각 너트가 있어, 센서를 수용하고 육각 너트에 끼우는 3D 프린트 홀더 설계.
배선
자이로 센서 GY-521 (I2C)
VCC → 5V
GND → GND
SCL → A5
SDA → A4
XDA, XCL, ADO, INT → 미연결
7-세그먼트 모듈 (MAX7219, SPI)
VCC → 3.3V
GND → GND
DIN → D12
CS → D10
CLK → D11
버튼
전원
AA 배터리 6개 직렬 → 전원 스위치 → 전체 시스템 공급.
케이스 설계
Autodesk Fusion 360으로 설계, Anycubic i3 Mega로 출력. 네오디뮴 자석 내장해 드릴 본체에 착탈식 부착.
아두이노 스케치 핵심 포인트
LedControl 라이브러리 로 7-세그먼트 제어 (라이브러리 매니저에서 설치)
자이로 센서는 라이브러리 없이 Wire.h로 직접 I2C 통신
초기화 시 delay(1000) 필수! USB 연결 시엔 잘 되나 외부 전원만 연결하면 센서가 데이터를 안 줌. 웨이크업 후 1초 대기가 핵심 해결책.
센서 초기화 코드
Wire.begin();
Wire.beginTransmission(MPU);
Wire.write(0x6B); Wire.write(0x00); // MPU-6050 웨이크업
Wire.endTransmission(true);
delay(1000); // ★ 이 지연이 필수적!
Wire.beginTransmission(MPU);
Wire.write(0x1C); // ACCEL_CONFIG 레지스터
Wire.write(0x10); // +/- 8g 풀스케일
Wire.endTransmission(true);
오프셋 보정
셋업에서 100회 측정해 가속도계 오프셋 평균 계산.
각도 계산 (X축)
AccAngleX = atan(AccY / sqrt(AccX² + AccZ²)) * RAD_TO_DEG;
TotalAngleX = 0.5 * TotalAngleX + 0.5 * AccAngleX; // 50% 가중 평균으로 노이즈 완화
-90°~+90° → 0°~360° 변환
delta = 0;
if (AccZ < 0) delta = 180.0 - TotalAngleX * 2.0;
if (AccZ > 0 && AccY < 0) delta = 360.0;
DrillingMachineAngle = TotalAngleX + delta;
if (DrillingMachineAngle > 350) DrillingMachineAngle = 0; // 360° 근사값 0°로
깊이 환산
최대 회전각(시리얼 모니터로 실측) 316°, 최대 드릴 깊이 50mm일 때:
currentPos = 50.0 / 316.0 * DrillingMachineAngle;
버튼 동작
버튼 누름 → 현재 위치를 정지점(stopPos)로 저장, 디스플레이에 '8888' 표시 후 1초 대기
정지점 설정 시 우측 디스플레이에 남은 깊이 표시
현재 위치 ≥ 정지점 → 'StOP' 표시 (작은 't'는 setRow(0,2,B00001111)로 구현)
조립 및 테스트
홀더가 회전 가능하게 설계돼 있어 디스플레이가 0.0을 가리키도록 센서 정렬 쉬움. 실전 테스트 결과 센서 반응 빠르고 계산값이 실제 드릴 깊이와 정확히 일치. 큰 LED 디스플레이로 85세까지 안경 없이도 밀리미터 단위 판독 가능!
시청 링크: https://techpluscode.de/wp-content/uploads/2021/03/bta-bohrtiefenmessung-anwendung.mp4
참고 자료
코드
/* drilling-depth.ino
* author: Thomas Angielsky
* version: 2021-03-20
* https://techpluscode.de/bohrtiefenanzeige-mit-gyro-sensor/
* GY-521 자이로 센서로 테이블 드릴 드릴링 깊이 측정, 7-세그먼트 표시
* 오차 보상 아이디어: electronoobs.com 참고
*/
#include <Wire.h>
#include <math.h>
#include "LedControl.h"
#define MPU 0x68
char txt[8];
String s;
float currentPos, stopPos;
float rad_to_deg;
float AccX, AccY, AccZ;
float AccAngleX, AccAngleY;
float AccAngleErrorX, AccAngleErrorY;
float TotalAngleX, TotalAngleY;
float DrillingMachineAngle, delta;
LedControl lc = LedControl(12, 11, 10, 1); // DIN, CLK, CS, 모듈 수
void setup() {
stopPos = 0.0; currentPos = 0.0;
rad_to_deg = 180.0 / PI;
Wire.begin();
Wire.beginTransmission(MPU);
Wire.write(0x6B); Wire.write(0x00);
Wire.endTransmission(true);
delay(1000); // ★ 외부 전원 시 필수!
Wire.beginTransmission(MPU);
Wire.write(0x1C); Wire.write(0x10);
Wire.endTransmission(true);
// 오프셋 보정: 100회 측정 평균
for (int a = 0; a < 100; a++) {
Wire.beginTransmission(MPU);
Wire.write(0x3B); Wire.endTransmission(false);
Wire.requestFrom(MPU, 6, true);
AccX = (Wire.read()<<8 | Wire.read()) / 4096.0;
AccY = (Wire.read()<<8 | Wire.read()) / 4096.0;
AccZ = (Wire.read()<<8 | Wire.read()) / 4096.0;
AccAngleErrorX += atan(AccY / sqrt(AccX*AccX + AccZ*AccZ)) * rad_to_deg;
}
AccAngleErrorX /= 100.0;
pinMode(9, INPUT_PULLUP); // 버튼
lc.shutdown(0, false);
lc.setIntensity(0, 8);
lc.clearDisplay(0);
}
void loop() {
Wire.beginTransmission(MPU);
Wire.write(0x3B); Wire.endTransmission(false);
Wire.requestFrom(MPU, 6, true);
AccX = (Wire.read()<<8 | Wire.read()) / 4096.0;
AccY = (Wire.read()<<8 | Wire.read()) / 4096.0;
AccZ = (Wire.read()<<8 | Wire.read()) / 4096.0;
AccAngleX = atan(AccY / sqrt(AccX*AccX + AccZ*AccZ)) * rad_to_deg - AccAngleErrorX;
TotalAngleX = 0.5 * TotalAngleX + 0.5 * AccAngleX;
delta = 0;
if (AccZ < 0) delta = 180.0 - TotalAngleX * 2.0;
if (AccZ > 0 && AccY < 0) delta = 360.0;
DrillingMachineAngle = TotalAngleX + delta;
if (DrillingMachineAngle > 350) DrillingMachineAngle = 0;
currentPos = 50.0 / 316.0 * DrillingMachineAngle;
// 버튼 눌림: 정지점 저장
if (digitalRead(9) == LOW) {
stopPos = currentPos;
lc.setChar(0, 3, '8', false);
lc.setChar(0, 2, '8', false);
lc.setChar(0, 1, '8', false);
lc.setChar(0, 0, '8', false);
delay(1000);
}
// 우측 디스플레이: 정지점 관련 표시
if (stopPos > 0) {
if (currentPos >= stopPos) {
lc.setChar(0, 3, '5', false); // S
lc.setRow(0, 2, B00001111); // t
lc.setChar(0, 1, '0', false); // O
lc.setChar(0, 0, 'P', false); // P
} else {
dtostrf(stopPos - currentPos, 4, 1, txt);
s = ' ' + String(txt);
lc.setChar(0, 0, s.charAt(s.length()-1), false);
lc.setChar(0, 1, s.charAt(s.length()-3), true); // 소수점
lc.setChar(0, 2, s.charAt(s.length()-4), false);
lc.setChar(0, 3, s.charAt(s.length()-5), false);
}
} else {
lc.setChar(0, 3, ' ', false);
lc.setChar(0, 2, ' ', false);
lc.setChar(0, 1, ' ', false);
lc.setChar(0, 0, ' ', false);
}
// 좌측 디스플레이: 현재 깊이
dtostrf(currentPos, 4, 1, txt);
s = ' ' + String(txt);
lc.setChar(0, 4, s.charAt(s.length()-1), false);
lc.setChar(0, 5, s.charAt(s.length()-3), true);
lc.setChar(0, 6, s.charAt(s.length()-4), false);
lc.setChar(0, 7, s.charAt(s.length()-5), false);
delay(200);
}
커스텀 파트 및 인클로저
drilling-depth-3d-model_Yn2q0MSNa4.zip (STL 파일 포함)
회로도