ESP32 피지컬 컴퓨팅 강좌 5강. 초음파 센서(HC-SR04)로 거리 측정 + 주차 거리 경보(LED/부저 단계)
대상: 1~4강(버튼/가변저항/PWM/부저)을 완료한 입문자
이번 강의 목표: 초음파 센서로 거리를 측정하고, 거리 단계에 따라 LED와 부저 경고 패턴이 달라지는 “주차 거리 경보” 장치를 만든다.
🎬 도입 이야기(왜 이걸 배우나요?)
차를 주차할 때 “삐…삐…삐삐삐!” 소리가 점점 빨라지면, 우리는 ‘가까워졌다’는 걸 즉시 알죠.
이 기능의 핵심은 거리 센서 + 단계형 피드백입니다.
오늘은 교실에서 바로 만들 수 있는 대표 거리 센서 HC-SR04를 ESP32에 연결하고,
거리 변화에 따라 빛(LED) + 소리(부저)가 “단계적으로” 바뀌는 경보 장치를 완성합니다.
✅ 5강 프로젝트
- 프로젝트명: 주차 거리 경보(3단계)
- 결과:
- 거리를 cm로 측정해서 시리얼 모니터에 출력
- 먼 거리: LED 약하게/부저 없음
- 중간 거리: LED 켜짐/부저 느리게 “삐-”
- 가까운 거리: LED 강하게/부저 빠르게 “삐삐삐”
🧰 준비물(BOM)
- ESP32 개발보드 1개
- 브레드보드 1개
- 점퍼선 여러 개
- 초음파 센서 HC-SR04 1개
- LED 1개 + 220Ω 저항 1개
- (이전 강의) 패시브 부저 1개(권장)
- (선택) 버튼 1개(모드 전환 확장용)
중요(전압 레벨)
HC-SR04의 ECHO 핀은 5V 신호가 나오는 경우가 많습니다.
ESP32 입력은 3.3V라서, 안전하게 하려면 분압(저항 2개) 또는 레벨 시프터를 사용하세요.
🔌 회로 연결표
A) LED 연결(거리 표시)
- ESP32 GPIO2 → (220Ω) → LED 긴 다리(+)
- LED 짧은 다리(-) → GND
B) 부저 연결(경고음)
- 부저 + → ESP32 GPIO25
- 부저 - → GND
C) HC-SR04 연결
- HC-SR04 VCC → 5V (ESP32 보드의 5V/VIN 핀)
- HC-SR04 GND → GND
- HC-SR04 TRIG → ESP32 GPIO5
- HC-SR04 ECHO → (분압 후) ESP32 GPIO18
D) ECHO 분압(레벨 다운) 권장
아래처럼 저항 2개로 ECHO를 3.3V 수준으로 낮춥니다.
- HC-SR04 ECHO → 저항 1kΩ → (노드) → ESP32 GPIO18
- (노드) → 저항 2kΩ → GND
분압 비율 = 아래 저항 / (위+아래) = 2k / (1k+2k) = 0.666…
5V × 0.666… ≈ 3.33V → ESP32에 비교적 안전한 수준
🧠 핵심 개념
초음파 거리 측정 원리(아주 간단히)
- TRIG로 초음파 “발사”
- ECHO가 HIGH인 시간 = 왕복 시간
- 거리(cm) ≈ (시간(μs) × 0.0343) / 2
🧪 실습 1: 거리(cm) 측정해서 출력하기
먼저 거리값이 잘 나오는지 확인합니다.
const int TRIG_PIN = 5;
const int ECHO_PIN = 18;
float readDistanceCM() {
// TRIG: 10us 펄스
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
// ECHO 펄스 폭(마이크로초) 측정
// timeout: 30ms(약 5m) 정도로 제한
unsigned long duration = pulseIn(ECHO_PIN, HIGH, 30000);
if (duration == 0) return -1; // timeout
// 거리 계산: (시간 * 음속) / 2
// 음속 ≈ 0.0343 cm/us
float cm = (duration * 0.0343) / 2.0;
return cm;
}
void setup() {
Serial.begin(115200);
delay(300);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
Serial.println("HC-SR04 distance test start");
}
void loop() {
float d = readDistanceCM();
if (d < 0) {
Serial.println("No echo (timeout)");
} else {
Serial.print("Distance: ");
Serial.print(d, 1);
Serial.println(" cm");
}
delay(150);
}
확인 포인트
- 손을 가까이/멀리 하면 거리값이 바뀌어야 합니다.
- 값이 -1(타임아웃)이 자주 나오면: 배선/전원/분압/센서 방향을 확인하세요.
✅ 5강 프로젝트: 주차 거리 경보(LED + 부저 단계)
거리값을 “그대로 출력”하는 게 아니라, 사람에게 직관적인 단계로 바꿔서 피드백합니다.
이게 피지컬 컴퓨팅의 핵심(센서 → 판단 → 출력)입니다.
단계 예시(조절 가능)
- 60cm 이상: 안전(부저 X)
- 30~60cm: 주의(느린 삐-)
- 30cm 미만: 위험(빠른 삐삐삐)
const int TRIG_PIN = 5;
const int ECHO_PIN = 18;
const int LED_PIN = 2;
// 부저(LEDC)
const int BUZZ_PIN = 25;
const int BUZZ_CH = 1;
const int BUZZ_RES = 8;
// LED PWM(LEDC)
const int LED_CH = 0;
const int LED_FREQ = 5000;
const int LED_RES = 8; // 0~255
// 단계 기준(원하면 수정)
const float FAR_CM = 60.0; // 이 이상: 부저 없음
const float NEAR_CM = 30.0; // 이 미만: 빠른 경보
// 부저 패턴 타이밍
unsigned long lastBeep = 0;
bool beepOn = false;
float readDistanceCM() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
unsigned long duration = pulseIn(ECHO_PIN, HIGH, 30000);
if (duration == 0) return -1;
return (duration * 0.0343) / 2.0;
}
void setup() {
Serial.begin(115200);
delay(300);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
// LED PWM
ledcSetup(LED_CH, LED_FREQ, LED_RES);
ledcAttachPin(LED_PIN, LED_CH);
ledcWrite(LED_CH, 0);
// BUZZ PWM
ledcSetup(BUZZ_CH, 1000, BUZZ_RES);
ledcAttachPin(BUZZ_PIN, BUZZ_CH);
ledcWriteTone(BUZZ_CH, 0);
Serial.println("Parking Distance Alarm Start");
}
void loop() {
float d = readDistanceCM();
// 거리 측정 실패 시(타임아웃) : 출력 끄기
if (d < 0) {
ledcWrite(LED_CH, 0);
ledcWriteTone(BUZZ_CH, 0);
delay(100);
return;
}
// 1) LED 밝기(가까울수록 밝게)
// 10~100cm를 255~0으로 매핑(가까우면 밝게)
float clampD = d;
if (clampD < 10) clampD = 10;
if (clampD > 100) clampD = 100;
int ledDuty = (int)map((int)clampD, 10, 100, 255, 0);
ledcWrite(LED_CH, ledDuty);
// 2) 부저 단계형 패턴
unsigned long now = millis();
if (d >= FAR_CM) {
// 안전: 부저 끔
ledcWriteTone(BUZZ_CH, 0);
beepOn = false;
} else if (d >= NEAR_CM) {
// 주의: 느린 삐- (예: 500ms 간격)
unsigned long interval = 500;
if (now - lastBeep >= interval) {
lastBeep = now;
beepOn = !beepOn;
ledcWriteTone(BUZZ_CH, beepOn ? 1200 : 0);
}
} else {
// 위험: 빠른 삐삐삐 (예: 150ms 간격)
unsigned long interval = 150;
if (now - lastBeep >= interval) {
lastBeep = now;
beepOn = !beepOn;
ledcWriteTone(BUZZ_CH, beepOn ? 1700 : 0);
}
}
// 시리얼 출력(너무 잦으면 느려질 수 있어 간격을 둠)
static unsigned long lastPrint = 0;
if (now - lastPrint >= 200) {
lastPrint = now;
Serial.print("D=");
Serial.print(d, 1);
Serial.print("cm LED=");
Serial.print(ledDuty);
Serial.print(" STATE=");
if (d >= FAR_CM) Serial.println("SAFE");
else if (d >= NEAR_CM) Serial.println("CAUTION");
else Serial.println("DANGER");
}
delay(20);
}
🧩 체크포인트(자주 틀리는 부분 TOP 12)
- ECHO를 그대로 ESP32에 연결 → 5V 신호일 수 있어 분압/레벨시프터 권장
- TRIG/ECHO 핀 반대로 연결 → TRIG는 출력, ECHO는 입력
- 센서 전원 → HC-SR04는 보통 5V에서 안정적(3.3V에서 불안정할 수 있음)
- GND 공통 누락 → ESP32와 센서의 GND는 반드시 연결
- timeout 없이 pulseIn 사용 → 멈춤/렉 발생 가능, timeout을 꼭 넣기
- 거리값 튐 → 평균/중앙값 필터를 적용하면 안정됨(확장 과제)
- 너무 가까이(2~3cm) → HC-SR04는 최소 측정거리 근처에서 값이 이상할 수 있음
- 부저가 계속 울림 → 조건문에서 끄는 코드(0Hz)를 반드시 넣기
- LED 안 켜짐 → 극성/저항/핀 번호 확인
- 주파수 너무 높아 불쾌 → 800~1500Hz 사이로 조절해보세요
- 시리얼 출력 때문에 느려짐 → 출력 간격(lastPrint) 조절
- 핀 충돌 → 보드에 따라 문제 핀이 있으면 TRIG=17, ECHO=16 등으로 변경
🚀 확장 과제(선택)
- 과제 1: 거리값을 5번 측정해서 평균내고 사용하기(노이즈 줄이기)
힌트: 평균 필터
// for (i=0..4) 거리 측정 누적 -> sum/5 // 너무 빠르게 측정하면 센서가 꼬일 수 있어 20~40ms 간격 권장
- 과제 2: LED 3개(녹/노/빨)로 단계 표시(신호등 방식)
- 과제 3: 임계값을 “가변저항(3강)”으로 조절하게 만들기(거리 기준 튜닝)
- 과제 4: OLED/LCD를 붙여 거리(cm)와 상태(SAFE/CAUTION/DANGER) 표시(중급 파트 예고)
📝 평가 루브릭(선택)
| 평가 요소 | 우수(4) | 보통(3) | 기초(2) | 미흡(1) |
|---|---|---|---|---|
| 센서 연결/안전 | ECHO 레벨다운 이유 설명+구현 | 연결 정상, 측정 성공 | 오류 있으나 도움으로 수정 | 측정 실패 |
| 거리 측정 | 원리/공식 설명 가능 | 값이 안정적으로 변화 | 값이 자주 튐 | 값 출력 불가 |
| 단계 피드백 | 3단계 이상/패턴 설계 | 3단계 경보 정상 동작 | 일부 단계만 동작 | 피드백 없음 |
| 확장 과제 | 2개 이상 해결 + 설명 | 1개 해결 | 시도 흔적 | 미시도 |
⚠️ 유의사항
- HC-SR04는 주변 환경(각도/재질/흡음)에 따라 값이 튈 수 있어요. “완벽한 센서”가 아니라는 걸 경험하는 것도 학습입니다.
- 전압 레벨(5V→3.3V)을 무시하면 ESP32가 손상될 수 있으니, 가능하면 분압을 적용하세요.
- 초음파 센서는 너무 빠른 연속 측정 시 오작동할 수 있어, 측정 간격 50ms 이상을 권장합니다.
➡️ 다음 예고(6강)
- 6강: 온습도 센서(DHT11/22) + “미니 기상대” 만들기
- 미니 프로젝트: 온습도 표시 + 임계값(더움/습함) 경고 LED/부저