OLED와 MPU6500으로 만든 첫 번째 렙 카운터
연결 실패부터 센서 검증, 그리고 5회 렙 카운팅까지
이번 작업에서는 ESP32에 OLED와 IMU 센서를 연결하고, 센서의 기울기를 이용해 간단한 렙 카운터를 만들어봤다.
처음부터 순조롭지는 않았다.
OLED와 MPU6050 모듈 모두 핀헤더가 납땜되지 않은 상태였고, 그래서 일단 핀 헤더를 구멍에 끼운 상태로 테스트를 시작했다.
결과는 당연하게도 불안정했다.
그런데 이 과정에서 단순히 “안 된다”에서 끝내지 않고, 어느 선이 실제로 연결되어 있는지 보드 스스로 진단하게 만드는 방법을 시도했다.
1. 납땜 없이 OLED 연결하기
기본 연결은 다음과 같이 잡았다.
3V3 → VCC
GND → GND
GPIO 21 → SDA
GPIO 22 → SCL
핀헤더는 긴 쪽을 브레드보드 방향, 짧은 쪽을 기판 방향으로 꽂았다.
하지만 핀이 구멍보다 가늘어 헐거웠고, 처음에는 I2C 스캐너에서 아무것도 발견되지 않았다.
문제는 너무 많았다.
전원 문제인지, SDA 문제인지, SCL 문제인지, 브레드보드 줄이 어긋난 것인지 알 수 없었다.
멀티미터도 없는 상황이었다.
그래서 다른 방법을 써보기로 했다.
LCD가 부착된 브레드보드
2. 멀티미터 대신 ESP32가 연결 상태를 진단하게 만들기
I2C 장치에는 일반적으로 풀업 저항이 연결되어 있다.
이 특성을 이용해 SDA와 SCL을 INPUT_PULLDOWN으로 설정하고 각각의 상태를 읽었다.
외부에서 선을 HIGH로 끌어올리고 있다면 HIGH가 읽히고, 연결되지 않았다면 LOW가 읽힌다.
즉, 완벽한 회로 검증 장비는 아니지만 현재 해당 선에 외부 풀업이 존재하는지 확인하는 간이 진단 도구로 사용할 수 있었다.
실제로 단계별로 확인하면서 문제가 좁혀졌다.
1차
SDA ❌ / SCL ❌
→ 두 선 모두 문제가 있을 가능성
→ 우선 전원 연결부터 의심
2차
SDA ✅ / SCL ❌
→ 전원과 SDA는 살아 있고 SCL 쪽 문제로 범위 축소
3차
SDA ❌ / SCL ❌
→ SCL을 고치는 과정에서 SDA 접촉까지 다시 빠짐
납땜하지 않은 핀헤더의 전형적인 문제였다.
하나를 누르면 다른 하나가 튀어나온다.
손은 두 개인데 핀은 네 개였다.
3. 눌러서 고정하니 드디어 0x3C
핀 전체를 한쪽 방향으로 살짝 기울여 누르자 네 개의 핀이 동시에 구멍 벽에 밀착됐다.
그 상태를 고무줄과 테이프로 유지한 뒤 다시 스캔했다.
결과:
0x3C 발견
OLED가 정상적으로 인식됐다.
하지만 손을 대면 다시 연결이 끊겼다.
즉,
통신은 된다. 하지만 아직 사용할 수 있는 상태는 아니다.
이때 확실해진 것은 하나였다.
코드 문제가 아니라 물리적인 접촉 문제였다.
4. OLED로 직접 화면을 만들어보기
OLED가 인식된 뒤에는 화면 출력까지 테스트했다.
사용한 라이브러리는 Adafruit SSD1306.
라이브러리를 설치하는 과정에서는 macOS의 터미널 접근 권한 문제도 만났다. ~/Documents 접근이 막혀 있어 권한을 굳이 변경하는 대신 라이브러리를 별도의 경 로에 설치했다.
사용한 위치:
~/Library/ArduinoCLI
OLED 테스트에서는 세 가지 화면을 만들어봤다.
얼굴
웃음
활짝 웃음
윙크
놀람
하트 눈
졸림
눈 깜빡임
눈동자 움직임
자동차
흐르는 배경
회전하는 바퀴
노면에 따른 덜컹거림
원근감을 표현하기 위한 배경 속도 차이
특히 나무를 가로등보다 약 0.6배 느리게 움직여 깊이감을 표현했다.
한글
OLED 기본 글꼴에는 한글이 없었다. 방법을 강구해본결과,
그래서 맥의 한글 폰트로 문구를 먼저 흑백 이미지로 만들고, 이를 104×17 크기의 비트맵 배열로 변환해 OLED에 넣었다.
OLED 입장에서는 이것이 ‘한글’이 아니라 그냥 픽셀 그림이다.
따라서 문구를 바꾸려면 다시 이미지를 굽듯이 배열을 만들어야 한다.
LCD 디스플레이가 부착된 브레드보드
5. 첫 인두질 — OLED 4핀 납땜
결국 제대로 사용하려면 납땜이 필요했다.
핀 수가 4개뿐인 OLED를 먼저 작업했다.
결과:
브릿지 없음
냉납 없음
연결 불량 없음
I2C 주소
0x3C연속 3회 안정적으로 확인
가장 큰 차이는 이것이었다.
누르고 있지 않아도 잡혔다.
납땜 전에는 손으로 눌러야만 연결됐지만, 납땜 후에는 가만히 있어도 계속 인식됐다.
이때 처음으로 납땜이 단순히 “붙이는 작업”이 아니라 전기적으로 안정적인 연결을 만드는 작업이라는 걸 체감했다.
6. MPU6050 납땜
다음은 8핀 IMU 모듈이었다.
핀 수가 두 배라 더 삐뚤어지기 쉬웠지만 방법은 같았다.
양 끝 핀 하나씩 먼저 납땜
수평 확인
나머지 핀 납땜
브릿지와 냉납 확인
현재 사용하지 않는 XDA, XCL, AD0, INT까지 모두 납땜했다.
특히 AD0는 나중에 센서를 두 개 사용할 경우 중요하다.
기본 주소가 0x68이고, AD0를 3.3V에 연결하면 0x69로 변경할 수 있기 때문이다.
검은색 손잡이가 달린 테이블 위에 드라이버
작은 마이크로컨트롤러가 종이 위에 앉아 있다
테이블 위에 마이크로컨트롤러 한 쌍
7. OLED와 IMU를 같은 I2C 버스에 연결
이제 두 부품을 동시에 연결했다.
ESP32의 SDA/SCL 두 선을 OLED와 IMU가 함께 사용한다.
각 부품의 주소가 다르기 때문에 같은 버스를 공유할 수 있다.
구성은 다음과 같다.
ESP32 → OLED → MPU6500
총 8가닥을 연결했고, 별도의 전원 레일은 사용하지 않았다.
부품이 두 개뿐인 상황에서는 전원 레일을 추가하면 연결 지점이 오히려 늘어나기 때문이다.
중요한 점은 핀의 위치가 아니라 기판에 적힌 글자를 보고 연결하는 것이었다.
두 모듈의 핀 순서가 달랐다.
OLED:
GND / VCC / SCL / SDA
MPU6500:
VCC / GND / SCL / SDA
같은 위치에 같은 신호가 있다고 생각하면 바로 사고가 난다.
전선이 연결된 아두이노 보드
8. 그런데 MPU6050이 아니었다
I2C 스캐너에서는 IMU가 정상적으로 0x68에서 발견됐다.
그런데 여기서 한 단계 더 확인했다.
IMU의 WHO_AM_I 레지스터인 0x75를 읽어봤다.
결과:
0x70
처음에는 MPU6050이라고 알고 있었지만 실제 칩은 MPU6500이었다.
즉, 단순히 주소가 잡혔다고 해서 부품의 정체까지 확인된 것은 아니었다.
이번 작업에서는 I2C 주소뿐 아니라 센서 내부의 식별 레지스터까지 읽어 실제 칩을 검증했다.
MPU6050과 MPU6500은 레지스터 구조가 상당 부분 호환되기 때문에 기존 가속도 읽기 코드는 그대로 활용할 수 있었다.
다만 기존 barclip/logger/logger.ino에는 MPU6050의 WHO_AM_I = 0x68을 확인하는 검사가 들어 있어, 현재는 해당 부분을 수정해야 한다.
이걸 미리 발견한 덕분에 이후 문제가 생겼을 때 납땜이나 배선부터 의심하는 일을 피할 수 있었다.
9. 센서로 렙 카운터 만들기
하드웨어가 안정적으로 연결되자 IMU의 가속도 데이터를 이용해 간단한 렙 카운터를 만들었다.
핵심은 절대적인 센서 방향을 기준으로 삼지 않는 것이다.
전원을 넣은 뒤 약 3초 동안 가만히 있으면 그때의 중력 방향을 기준 자세로 저장한다.
그 이후에는 현재 중력 벡터와 기준 중력 벡터가 이루는 각도를 계산한다.
따라서 센서를 어떤 방향으로 붙였더라도 처음 자세를 기준으로 얼마나 움직였는지를 계산할 수 있다.
10. 판정선을 두 개 사용했다
렙 카운터에서 가장 중요한 것은 경계에서 숫자가 여러 번 올라가는 것을 막는 것이다.
그래서 판정선을 하나가 아니라 두 개로 만들었다.
40° 초과 → 내려감 상태
15° 미만으로 복귀 → 1회 인정
즉,
기준 자세 → 40° 이상 → 내려감 → 다시 15° 이하 → 1회
이렇게 동작한다.
하나의 기준값만 사용하면 경계 근처에서 센서값이 흔들릴 때 한 번의 움직임을 여러 번으로 인식할 수 있다.
버튼에서 발생하는 채터링과 같은 문제다.
이번에는 상태 전환에 히스테리시스(hysteresis)를 적용한 셈이다.
11. OLED에 센서 상태를 시각화
단순히 숫자만 표시하지 않고 현재 센서 상태를 한 화면에서 볼 수 있도록 만들었다.
화면에는 다음 정보를 표시했다.
현재 렙 수
현재 각도
기울기 막대
판정선
현재 상태
가속도 크기
센서가 실제로 어떤 움직임을 보고 있는지 바로 확인할 수 있도록 만든 것이다.
12. 실제 테스트 — 5번 움직여서 5렙
마지막으로 실제 기울임 동작을 5회 수행했다.
결과:
인식된 렙: 5회
최대 각도: 100.5°
오작동: 0회
실제 데이터의 일부:
각도 22.8° UP ← 세우기 시작
각도 47.7° DOWN ← 40° 초과
각도 88.3° DOWN ← 거의 수직
각도 1.0° UP ← 15° 아래 복귀 → 렙 +1특히 중요한 것은 가속도 크기가 테스트 내내 약 1.00g으로 유지됐다는 점이다.
즉, 센서를 심하게 흔든 것이 아니라 중력 방향을 회전시키는 움직임이었고, 데이터가 비교적 깨끗하게 들어왔다.
최종 상태
항목
확정값
보드
ESP32
전원
3.3V
SDA
GPIO 21
SCL
GPIO 22
OLED 주소
0x3C
IMU 주소
0x68
실제 IMU
MPU6500
WHO_AM_I
0x70
가속도 범위
±8g
가속도 스케일
4096 LSB/g
내려감 판정
40° 초과
렙 인정
15° 이하 복귀
라이브러리 위치
~/Library/ArduinoCLI
최종 테스트
5회 → 5렙
오작동
0회
이번 작업에서 배운 것
이번 작업에서 가장 큰 수확은 OLED나 IMU를 연결했다는 사실 자체가 아니다.
문제가 생겼을 때 어디가 문제인지 스스로 좁혀가는 방법을 만든 것이다.
처음에는 “OLED가 안 잡힌다”는 하나의 문제였다.
하지만 이를
전원 → SDA → SCL → 물리적 접촉 → 납땜 → I2C 주소 → 칩 식별 → 센서 데이터
순서로 쪼개면서 하나씩 검증할 수 있었다.
납땜 → 배선 → I2C 디버깅 → 센서 식별 → 데이터 검증 → 상태 판정 → 시각화 → 실제 테스트
라는 하나의 작은 피지컬 AI/IoT 개발 사이클을 처음부터 끝까지 경험해본 작업이었다.
그리고 결과적으로,
ESP32 + OLED + MPU6500으로 실제 5회 움직임을 5회 정확하게 세는 렙 카운터를 만들었다.