KY-039 심박 센서로 심박수 측정하기: Arduino 튜토리얼
부품 및 소모품
| 부품 |
수량 |
| Arduino UNO |
1 |
| KY-039 심박 센서 (적외선 LED + 포토트랜지스터) |
1 |
| 점퍼 와이어 |
1세트 |
프로젝트 소개
센서 이해하기
Arduino 37종 센서 키트에 포함된 '심박 센서'는 실제로는 심박수(BPM)를 직접 출력하지 않습니다. 단지 적외선 LED와 포토트랜지스터로 구성되어, 손가락을 사이에 둘 때 혈관 확장에 따른 적외선 투과량 변화를 아날로그 값(0~1023)으로 출력할 뿐입니다.
신호 처리 단계
1. 원시 데이터 확인
센서 값을 그대로 읽으면 정수값만 나와서 파형이 매우 거칠게 나타납니다 (360~383 사이 변동).
2. 이동 평균으로 평활화
최근 20개 읽기 값의 평균을 내면 심박 파형이 명확해집니다.
#define samp_siz 20
int reads[samp_siz];
int ptr = 0;
long sum = 0;
int reader = analogRead(sensorPin);
sum -= reads[ptr];
sum += reader;
reads[ptr] = reader;
float last = (float)sum / samp_siz;
ptr = (ptr + 1) % samp_siz;
3. 50/60Hz 전원 노이즈 제거
형광등/LED 조명의 깜빡임(50Hz = 20ms 주기) 노이즈를 제거하려면 20ms 동안 샘플링하여 평균을 냅니다.
int n = 0;
unsigned long start = millis();
float reader = 0;
do {
reader += analogRead(sensorPin);
n++;
} while (millis() < start + 20); // 60Hz 지역이면 16.67ms
reader /= n;
4. 심박 감지 알고리즘
평활화된 곡선에서 '연속 상승' 구간을 감지하여 심박으로 판단합니다. 5회 연속 상승하면 심박 시작점으로 간주하고, 이전 심박과의 시간 차이로 BPM 계산.
- 가중 평균: 최근 3회 심박 간격의 0.4 : 0.3 : 0.3 비율로 평균
- 공식:
BPM = 60000 / (0.4*first + 0.3*second + 0.3*third)
최종 코드
#define samp_siz 4
#define rise_threshold 4
int sensorPin = A0;
void setup() {
Serial.begin(9600);
}
void loop() {
float reads[samp_siz], sum = 0;
long int now, ptr = 0;
float last, reader, start;
float first, second, third, before = 0, print_value;
bool rising = false;
int rise_count = 0;
int n;
long int last_beat = 0;
for (int i = 0; i < samp_siz; i++) reads[i] = 0;
while (1) {
// 20ms 평균으로 50Hz 노이즈 제거
n = 0; start = millis(); reader = 0;
do {
reader += analogRead(sensorPin);
n++;
now = millis();
} while (now < start + 20);
reader /= n;
// 이동 평균 유지
sum -= reads[ptr];
sum += reader;
reads[ptr] = reader;
last = sum / samp_siz;
// 상승 곡선 감지 (심박)
if (last > before) {
rise_count++;
if (!rising && rise_count > rise_threshold) {
rising = true;
first = millis() - last_beat;
last_beat = millis();
print_value = 60000.0 / (0.4 * first + 0.3 * second + 0.3 * third);
Serial.println(print_value);
third = second;
second = first;
}
} else {
rising = false;
rise_count = 0;
}
before = last;
ptr = (ptr + 1) % samp_siz;
}
}
개선 방향
- 최근 15초간 심박수 평균 내기 (이상치 제거 후)
- 하강 곡선 또는 최고점 기반 감지 방식 추가
- 고심박수(180~200 BPM) 대응 로직 보완
- 손가락 움직임으로 인한 아티팩트 필터링
회로도
KY-039 모듈 핀: VCC → 5V, GND → GND, S (신호) → A0. 손가락을 IR LED와 포토트랜지스터 사이에 가볍게 올립니다.