🌐 Quick Overview for International Readers
Control Arduino/ESP32 LEDs using Python, OpenCV, and MediaPipe Hand Tracking. This tutorial explains how to count extended fingers via webcam and send serial commands to trigger hardware outputs in real-time.
단순히 버튼을 누르거나 웹페이지 스위치로 LED를 제어하는 단계를 넘어, 오늘은 영화 '마이너리티 리포트'처럼 카메라에 내 손가락을 펼치는 것만으로 하드웨어를 제어하는 컴퓨터 비전(Computer Vision) IoT 프로젝트를 진행해보겠습니다.
Google의 MediaPipe 라이브러리와 OpenCV를 활용하면 복잡한 딥러닝 모델 학습 없이도 단 몇 십 줄의 Python 코드로 실시간 손가락 마디(Landmark) 추적 및 개수 인식이 가능합니다. 인식된 손가락 개수를 시리얼 통신(Serial)으로 아두이노/ESP32에 전달해 LED를 켜고 끌 수 있는 시스템을 완성해봅시다.
1. 시스템 구조 및 준비물 (System Architecture)
전체적인 시스템 데이터 흐름은 다음과 같습니다:
[웹캠 영상 입력] ➔ [Python OpenCV / MediaPipe 처리 (손가락 개수 카운트)] ➔ [시리얼 통신 전송] ➔ [아두이노 / ESP32 LED 제어]
- PC / 노트북 (웹캠 및 Python 실행 환경)
- 아두이노 Uno 또는 ESP32 1개
- LED 1개 및 220Ω 저항 1개
- USB 데이터 케이블
2. 아두이노 소스코드 (Arduino C++ Code)
시리얼 포트로 들어오는 데이터가 '1'이면 LED를 켜고, '0'이면 끄는 기본 수신 코드입니다. 아두이노 IDE에서 먼저 업로드해 둡니다.
const int ledPin = 13; // 아두이노 내장 LED 사용 (또는 GPIO 2)
void setup() {
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
}
void loop() {
if (Serial.available() > 0) {
char command = Serial.read();
if (command == '1') {
digitalWrite(ledPin, HIGH); // 손가락 펴짐 ➔ LED ON
} else if (command == '0') {
digitalWrite(ledPin, LOW); // 주먹 쥠 ➔ LED OFF
}
}
}
3. 파이썬 손 인식 및 제어 프로그램 (Python Script)
파이썬 실행 전 필요한 라이브러리를 먼저 터미널(CMD)에서 설치해야 합니다.
pip install opencv-python mediapipe pyserial
아래 코드에서 COM3 부분을 실제 아두이노가 연결된 포트 번호로 수정 후 실행하세요.
import cv2
import mediapipe as mp
import serial
import time
# 아두이노 시리얼 포트 설정 (본인 포트로 변경: 예 'COM3' 또는 '/dev/ttyUSB0')
try:
py_serial = serial.Serial(port='COM3', baudrate=9600, timeout=1)
time.sleep(2) # 시리얼 연결 안정화 대기
print("Arduino Connected!")
except:
print("Serial Port Connection Failed. Check Port Number.")
# MediaPipe Hand 모듈 초기화
mp_hands = mp.solutions.hands
mp_draw = mp.solutions.drawing_utils
hands = mp_hands.Hands(max_num_hands=1, min_detection_confidence=0.7)
# 손가락 끝 마디 랜드마크 인덱스 (검지, 중지, 약지, 소지)
tip_ids = [8, 12, 16, 20]
cap = cv2.VideoCapture(0) # 웹캠 열기
while cap.isOpened():
success, img = cap.read()
if not success:
continue
img = cv2.flip(img, 1) # 좌우 반전
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
results = hands.process(img_rgb)
total_fingers = 0
if results.multi_hand_landmarks:
for hand_landmarks in results.multi_hand_landmarks:
mp_draw.draw_landmarks(img, hand_landmarks, mp_hands.HAND_CONNECTIONS)
lm_list = []
for id, lm in enumerate(hand_landmarks.landmark):
h, w, c = img.shape
cx, cy = int(lm.x * w), int(lm.y * h)
lm_list.append([id, cx, cy])
if len(lm_list) != 0:
fingers = []
# 엄지 손가락 판별 (X축 기준)
if lm_list[4][1] > lm_list[3][1]:
fingers.append(1)
else:
fingers.append(0)
# 나머지 4개 손가락 판별 (Y축 기준: 끝마디가 아래마디보다 위에 있는지)
for id in range(0, 4):
if lm_list[tip_ids[id]][2] < lm_list[tip_ids[id] - 2][2]:
fingers.append(1)
else:
fingers.append(0)
total_fingers = fingers.count(1)
# 손가락이 1개 이상 펴지면 LED ON ('1'), 주먹을 쥐면 LED OFF ('0')
if total_fingers > 0:
py_serial.write(b'1')
else:
py_serial.write(b'0')
# 화면에 인식된 손가락 개수 표시
cv2.putText(img, f'Fingers: {total_fingers}', (30, 70),
cv2.FONT_HERSHEY_SIMPLEX, 1.5, (0, 255, 0), 3)
cv2.imshow("Hand Tracking Controller", img)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
if 'py_serial' in locals():
py_serial.close()
4. 핵심 구현 원리 (Key Technical Points)
1) MediaPipe의 21개 Hand Landmark 추적
MediaPipe는 손 전체에서 21개 3D 포인트를 실시간으로 추적합니다. 손가락 끝 마디(8, 12, 16, 20번)의 Y 좌표값과 바로 밑 마디(6, 10, 14, 18번)의 Y 좌표를 비교하여 손가락이 올라가 있는지(펴짐) 내려가 있는지(굽힘)를 수식으로 간단하게 판별합니다.
2) Python-Arduino간 PySerial 데이터 전송
py_serial.write(b'1')와 같이 바이트(Byte) 형태로 문자열을 전달합니다. 파이썬 매 프레임마다 연속 전송하여 웹캠에서의 동작 지연 시간(Latency)을 50ms 미만으로 극소화시켰습니다.
5. 트러블슈팅 및 예외 처리 (Troubleshooting)
- SerialException: PermissionError (포트 열기 실패): 아두이노 IDE의 시리얼 모니터 창이 열려 있으면 파이썬이 포트를 점유하지 못합니다. 아두이노 IDE 시리얼 모니터 창을 닫은 후 파이썬 코드를 실행하세요.
- 손가락 인식율 저하 (조명/배경 영향):
min_detection_confidence=0.7신뢰도 수치를 0.5로 낮추거나 손을 정면으로 카메라에 비추면 훨씬 안정적으로 인식합니다. - 웹캠이 열리지 않을 때: 다른 웹캠 프로그램(Zoom, 팀즈 등)이 카메라를 사용 중인지 확인하고
cv2.VideoCapture(0)의 인덱스를 `1`로 바꿔보세요.
6. 응용 및 발전 아이디어 (Next Projects)
기본 LED 제어를 익히셨다면 다음 단계로 발전시켜 보세요:
- 손가락 개수별 동작 지정: 1개=LED 1번, 2개=LED 2번, 3개=모터 회전 등 멀티 채널 제어
- 손바닥 각도/거리 인식: 손을 앞으로 가져가면 서보모터 각도가 조절되는 3D 무선 컨트롤러 제작
- 스마트홈 비접촉 스위치: 위생이 중요한 의료 환경이나 요리 중 손을 대지 않고 가전기기를 켜는 스위치 구현
다음 글에서는 MediaPipe Pose 모듈을 이용한 "몸짓/포즈 인식으로 스마트 조명 제어하기" 실습을 다뤄보겠습니다. 질문은 댓글로 편하게 남겨주세요!
'아두이노' 카테고리의 다른 글
| ESP32 아두이노 웹서버 만들기: 스마트폰으로 LED 켜고 끄기 완벽 가이드 (0) | 2026.08.21 |
|---|---|
| [아두이노 + TinyML] 손 제스처 인식 컨트롤러 만들기 – Arduino Nano 33 BLE Sense 활용법 완전 정복 (2) | 2025.04.25 |
| 아두이노 + RTC 모듈로 디지털 시계 만들기 – DS3231 연결부터 LCD 출력까지 완벽 정리 (0) | 2025.04.23 |
| 아두이노 블로그 시리즈 – 블루투스로 모터 제어하기 (HC-06) (0) | 2025.04.22 |
| 아두이노 UART 디버깅 콘솔 확장 – 설정값 EEPROM에 저장하기 (0) | 2025.04.21 |