콘텐츠로 이동

Chapter 04: 센서 입문 - 세상을 느끼다


🎯 이 장에서 배우는 것

  • [ ] 아날로그와 디지털 신호의 차이를 설명할 수 있다
  • [ ] ADC를 사용하여 센서 값을 읽을 수 있다
  • [ ] Grove 조도 센서로 밝기를 측정할 수 있다
  • [ ] DHT11 센서로 온도와 습도를 측정할 수 있다
  • [ ] 센서 값에 따라 LED를 자동 제어할 수 있다

💡 왜 이걸 배우나요?

지금까지 버튼은 눌렀다(1) / 안 눌렀다(0) 두 가지만 구분했어. 하지만 세상은 그렇게 단순하지 않지!

  • 방이 조금 어두운지, 많이 어두운지
  • 온도가 25도인지, 30도인지
  • 소리가 작은지, 큰지

이런 "정도"를 알려면 센서가 필요해. 센서는 세상의 다양한 정보를 숫자로 바꿔주는 장치야.

실제로 어디에 쓰일까? 🤔 - 🌡️ 에어컨이 "덥다"를 아는 방법 → 온도 센서 - 📱 스마트폰 화면 밝기 자동 조절 → 조도 센서 - 🚗 자동차 후방 감지 → 초음파 센서

이번 장에서 센서를 배우면, 피코가 세상을 느끼기 시작해!


📚 핵심 개념

개념 1: 디지털 신호 vs 아날로그 신호

비유로 시작: 디지털 신호는 마치 계단과 같아요. 1층, 2층, 3층... 딱딱 끊어지지. 아날로그 신호는 마치 경사로와 같아요. 부드럽게 연속으로 이어져.

정확한 정의: - 디지털 신호: 0과 1, 두 가지 상태만 있는 신호 (ON/OFF) - 아날로그 신호: 연속적인 값을 가지는 신호 (0~100% 사이 모든 값)

예시로 확인:

디지털: 버튼        →  눌림(1) 또는 안눌림(0)
아날로그: 볼륨 다이얼  →  0%, 30%, 75%, 100%... 무한한 값

flowchart LR subgraph 디지털 D1[0️⃣ OFF] --> D2[1️⃣ ON] end subgraph 아날로그 A1[0] --> A2[0.3] --> A3[0.7] --> A4[1.0] end style D1 fill:#ffcdd2,stroke:#c62828 style D2 fill:#c8e6c9,stroke:#2e7d32 style A1 fill:#e3f2fd,stroke:#1976d2 style A2 fill:#bbdefb,stroke:#1976d2 style A3 fill:#90caf9,stroke:#1976d2 style A4 fill:#64b5f6,stroke:#1976d2

쉽게 말하면: 디지털은 "예/아니오", 아날로그는 "정도"를 표현해!


개념 2: ADC (Analog-to-Digital Converter)

비유로 시작: ADC는 마치 통역사와 같아요. 센서가 말하는 "아날로그 언어"를 컴퓨터가 이해하는 "디지털 숫자"로 바꿔줘.

정확한 정의: ADC는 연속적인 아날로그 전압을 디지털 숫자로 변환하는 장치야. 피코의 ADC는 16비트라서 0~65535 범위의 숫자로 바꿔줘.

예시로 확인:

센서 전압    →    ADC 변환    →    디지털 값
0V          →                →    0
1.65V       →     피코 ADC   →    32768 (중간값)
3.3V        →                →    65535 (최대값)

flowchart LR A[🌡️ 센서<br/>아날로그 전압] --> B[🔄 ADC<br/>변환기] --> C[💻 피코<br/>디지털 숫자] style A fill:#fff3e0,stroke:#f57c00 style B fill:#e8f5e9,stroke:#388e3c style C fill:#e3f2fd,stroke:#1976d2

쉽게 말하면: ADC는 센서의 "느낌"을 컴퓨터가 읽을 수 있는 "숫자"로 바꿔줘!


개념 3: 센서의 종류

flowchart TB S[🎛️ 센서 종류] --> D[디지털 센서] S --> A[아날로그 센서] D --> D1[버튼: 0 또는 1] D --> D2[DHT11: 디지털 통신] A --> A1[조도 센서: 밝기 정도] A --> A2[온도 센서: 온도 정도] A --> A3[가변저항: 회전 정도] style S fill:#f3e5f5,stroke:#7b1fa2 style D fill:#e3f2fd,stroke:#1976d2 style A fill:#fff3e0,stroke:#f57c00 style D1 fill:#e8eaf6,stroke:#3f51b5 style D2 fill:#e8eaf6,stroke:#3f51b5 style A1 fill:#fff8e1,stroke:#ffa000 style A2 fill:#fff8e1,stroke:#ffa000 style A3 fill:#fff8e1,stroke:#ffa000

오늘 사용할 센서: | 센서 | 종류 | 측정 대상 | 연결 포트 | |------|------|----------|----------| | Grove 조도 센서 | 아날로그 | 빛의 밝기 | A0 | | Grove DHT11 | 디지털 | 온도, 습도 | D16 |


🔨 따라하기

Step 1: 조도 센서로 밝기 읽기

목표: Grove 조도 센서를 연결하고 밝기 값을 읽어보자!

회로 연결:

┌─────────────────────────────────────────────────────┐
│                  Pico 2W + Grove Shield             │
│                                                     │
│    ┌─────────────┐                                  │
│    │  A0 포트    │◄──── Grove 조도 센서            │
│    │  (아날로그)  │      (노란색 케이블)             │
│    └─────────────┘                                  │
│                                                     │
│    Grove 케이블을 A0 포트에 연결하면 끝!            │
└─────────────────────────────────────────────────────┘
flowchart LR subgraph Grove조도센서 L[💡 조도 센서] end subgraph PicoShield P[A0 포트] end L -->|Grove 케이블| P style L fill:#fff9c4,stroke:#f9a825 style P fill:#e3f2fd,stroke:#1976d2

코드:

# === WHAT: 조도 센서 값 읽기 ===
# 조도 센서로 현재 밝기를 측정해서 출력하는 코드야

# --- WHY: 왜 필요한지 ---
# 방이 얼마나 밝은지 알아야 자동 조명 같은 걸 만들 수 있어!

# HOW: 어떻게 동작하는지
from machine import ADC, Pin  # ADC: 아날로그 값을 읽는 기능
import time

# Grove 조도 센서는 A0 포트에 연결
# A0 = GPIO26번 핀
light_sensor = ADC(Pin(26))  # ADC 객체 생성

# 무한 반복
while True:
    # 센서 값 읽기 (0 ~ 65535)
    light_value = light_sensor.read_u16()

    # 결과 출력
    print("밝기:", light_value)

    # 0.5초 대기
    time.sleep(0.5)

실행 결과:

밝기: 45230
밝기: 45180
밝기: 12450  ← 손으로 가렸을 때
밝기: 11890
밝기: 58920  ← 손전등 비췄을 때
밝기: 59100

여기서 잠깐! 🤔

read_u16()이 뭐야? - read_u16()은 16비트 unsigned(양수만) 정수로 읽어라는 뜻이야 - u = unsigned(부호 없음), 16 = 16비트 - 그래서 결과가 0 ~ 65535 범위로 나와!


Step 2: 밝기 값을 퍼센트로 변환하기

목표: 0~65535 숫자는 직관적이지 않으니, 0~100%로 바꿔보자!

코드:

# === WHAT: 밝기를 퍼센트로 변환 ===
# 센서 값을 사람이 이해하기 쉬운 퍼센트로 바꾸는 코드야

# --- WHY: 왜 필요한지 ---
# "45230"보다 "69%"가 훨씬 이해하기 쉽잖아!

# HOW: 어떻게 동작하는지
from machine import ADC, Pin
import time

light_sensor = ADC(Pin(26))

while True:
    # 원본 값 읽기
    raw_value = light_sensor.read_u16()

    # 퍼센트로 변환 (0~65535 → 0~100)
    # 공식: (현재값 / 최대값) * 100
    percent = (raw_value / 65535) * 100

    # 소수점 1자리까지 출력
    print(f"밝기: {percent:.1f}%")

    time.sleep(0.5)

실행 결과:

밝기: 69.0%
밝기: 68.9%
밝기: 19.0%  ← 손으로 가렸을 때
밝기: 18.1%

여기서 잠깐! 🤔

f-string 포맷팅 - f"밝기: {percent:.1f}%" - .1f = 소수점 1자리까지 표시 - .2f = 소수점 2자리까지 표시 - 이게 없으면 69.0324756... 같이 길게 나와!


Step 3: DHT11 온습도 센서 사용하기

목표: DHT11 센서로 온도와 습도를 측정해보자!

회로 연결:

┌─────────────────────────────────────────────────────┐
│                  Pico 2W + Grove Shield             │
│                                                     │
│    ┌─────────────┐                                  │
│    │  D16 포트   │◄──── Grove DHT11 센서           │
│    │  (디지털)   │      (흰색 센서 모듈)            │
│    └─────────────┘                                  │
│                                                     │
│    Grove 케이블을 D16 포트에 연결!                  │
└─────────────────────────────────────────────────────┘

라이브러리 설치가 필요해! 📦

DHT11은 특별한 통신 방식을 써서 라이브러리가 필요해. Thonny에서 설치하자:

  1. Thonny 메뉴 → 도구패키지 관리
  2. 검색창에 dht 입력
  3. micropython-dht 선택 → 설치
flowchart LR A[🔧 도구] --> B[📦 패키지 관리] --> C[🔍 dht 검색] --> D[✅ 설치] style A fill:#e3f2fd,stroke:#1976d2 style B fill:#e8f5e9,stroke:#388e3c style C fill:#fff3e0,stroke:#f57c00 style D fill:#c8e6c9,stroke:#2e7d32

코드:

# === WHAT: DHT11 온습도 센서 읽기 ===
# 현재 온도와 습도를 측정해서 출력하는 코드야

# --- WHY: 왜 필요한지 ---
# 스마트 홈, 식물 관리, 기상 관측에 온습도는 필수!

# HOW: 어떻게 동작하는지
from machine import Pin
import dht              # DHT 센서 라이브러리
import time

# DHT11 센서 객체 생성 (D16 포트 = GPIO16)
sensor = dht.DHT11(Pin(16))

while True:
    try:
        # 센서 측정 명령
        sensor.measure()

        # 측정된 값 읽기
        temp = sensor.temperature()  # 온도 (섭씨)
        humidity = sensor.humidity() # 습도 (%)

        # 결과 출력
        print(f"온도: {temp}°C, 습도: {humidity}%")

    except Exception as e:
        # 센서 읽기 실패 시
        print("센서 읽기 실패:", e)

    # DHT11은 최소 1초 간격 필요
    time.sleep(2)

실행 결과:

온도: 24°C, 습도: 55%
온도: 24°C, 습도: 56%
온도: 25°C, 습도: 54%

여기서 잠깐! 🤔

try-except가 뭐야? - DHT11 센서는 가끔 읽기에 실패해 (통신 오류) - try: 이 코드를 시도해봐 - except: 실패하면 이렇게 해 - 에러가 나도 프로그램이 멈추지 않아!

왜 2초나 기다려? - DHT11은 저가형 센서라 측정에 시간이 걸려 - 최소 1초 이상 간격을 줘야 정확한 값이 나와 - DHT22(고급형)는 0.5초면 돼


Step 4: 센서 값으로 LED 자동 제어하기

목표: 어두우면 LED가 켜지는 자동 야간등을 만들어보자!

회로 연결:

flowchart LR subgraph 입력 L[💡 조도센서<br/>A0] end subgraph 처리 P[🤖 피코<br/>조건 판단] end subgraph 출력 LED[💡 LED<br/>D18] end L --> P --> LED style L fill:#fff9c4,stroke:#f9a825 style P fill:#e3f2fd,stroke:#1976d2 style LED fill:#c8e6c9,stroke:#388e3c
┌─────────────────────────────────────────────────────┐
│                  연결 정리                          │
│                                                     │
│    A0  포트 ◄──── Grove 조도 센서                  │
│    D18 포트 ◄──── Grove LED                        │
└─────────────────────────────────────────────────────┘

코드:

# === WHAT: 자동 야간등 ===
# 어두우면 LED가 켜지고, 밝으면 LED가 꺼지는 코드야

# --- WHY: 왜 필요한지 ---
# 현관등, 복도등처럼 자동으로 켜지는 조명의 원리야!

# HOW: 어떻게 동작하는지
from machine import ADC, Pin
import time

# 센서와 LED 설정
light_sensor = ADC(Pin(26))  # A0 포트
led = Pin(18, Pin.OUT)       # D18 포트

# 임계값 설정 (이 값보다 어두우면 LED ON)
# 밝기 30% 이하면 어둡다고 판단
THRESHOLD = 30

while True:
    # 밝기 읽고 퍼센트 변환
    raw = light_sensor.read_u16()
    brightness = (raw / 65535) * 100

    # 조건 판단
    if brightness < THRESHOLD:
        # 어두우면 LED 켜기
        led.on()
        status = "🌙 어두움 → LED ON"
    else:
        # 밝으면 LED 끄기
        led.off()
        status = "☀️ 밝음 → LED OFF"

    print(f"밝기: {brightness:.1f}% | {status}")
    time.sleep(0.5)

실행 결과:

밝기: 68.5% | ☀️ 밝음 → LED OFF
밝기: 67.9% | ☀️ 밝음 → LED OFF
밝기: 25.3% | 🌙 어두움 → LED ON   ← 손으로 가림
밝기: 18.7% | 🌙 어두움 → LED ON
밝기: 52.1% | ☀️ 밝음 → LED OFF   ← 손 뗌

여기서 잠깐! 🤔

THRESHOLD(임계값)를 왜 따로 만들어? - 숫자 30이 코드 여러 곳에 있으면 수정하기 힘들어 - 맨 위에 THRESHOLD = 30으로 정의하면 한 번만 바꾸면 돼! - 대문자로 쓰면 "이건 설정값이야"라는 표시


Step 5: 환경 모니터링 시스템 만들기

목표: 조도 + 온습도를 함께 측정하는 환경 모니터를 만들어보자!

코드:

# === WHAT: 환경 모니터링 시스템 ===
# 조도, 온도, 습도를 한번에 측정해서 보여주는 코드야

# --- WHY: 왜 필요한지 ---
# 내 방의 환경 데이터를 수집하면 쾌적한 환경을 만들 수 있어!

# HOW: 어떻게 동작하는지
from machine import ADC, Pin
import dht
import time

# 센서 설정
light_sensor = ADC(Pin(26))  # 조도 센서 (A0)
dht_sensor = dht.DHT11(Pin(16))  # 온습도 센서 (D16)

print("=" * 40)
print("🏠 환경 모니터링 시스템 시작!")
print("=" * 40)

count = 1  # 측정 횟수

while True:
    # 조도 측정
    light_raw = light_sensor.read_u16()
    brightness = (light_raw / 65535) * 100

    # 온습도 측정
    try:
        dht_sensor.measure()
        temp = dht_sensor.temperature()
        humidity = dht_sensor.humidity()

        # 결과 출력
        print(f"\n📊 측정 #{count}")
        print(f"   💡 밝기: {brightness:.1f}%")
        print(f"   🌡️ 온도: {temp}°C")
        print(f"   💧 습도: {humidity}%")

        # 환경 평가
        if temp < 18:
            print("   ❄️ 좀 춥네요!")
        elif temp > 28:
            print("   🔥 좀 덥네요!")
        else:
            print("   ✅ 쾌적해요!")

    except:
        print(f"\n📊 측정 #{count}")
        print(f"   💡 밝기: {brightness:.1f}%")
        print("   ⚠️ 온습도 센서 읽기 실패")

    count += 1
    time.sleep(3)  # 3초마다 측정

실행 결과:

========================================
🏠 환경 모니터링 시스템 시작!
========================================

📊 측정 #1
   💡 밝기: 65.3%
   🌡️ 온도: 24°C
   💧 습도: 55%
   ✅ 쾌적해요!

📊 측정 #2
   💡 밝기: 18.7%
   🌡️ 온도: 24°C
   💧 습도: 56%
   ✅ 쾌적해요!

📊 측정 #3
   💡 밝기: 64.1%
   🌡️ 온도: 25°C
   💧 습도: 54%
   ✅ 쾌적해요!


📝 전체 코드

파일명: environment_monitor.py

# === 환경 모니터링 시스템 (완성본) ===
# 조도, 온도, 습도를 측정하고 LED로 알림하는 시스템
# 
# 하드웨어 연결:
#   - Grove 조도 센서 → A0 포트
#   - Grove DHT11 → D16 포트
#   - Grove LED → D18 포트

from machine import ADC, Pin
import dht
import time

# === 하드웨어 설정 ===
light_sensor = ADC(Pin(26))      # 조도 센서 (A0 = GPIO26)
dht_sensor = dht.DHT11(Pin(16))  # 온습도 센서 (D16)
led = Pin(18, Pin.OUT)           # LED (D18)

# === 설정값 ===
LIGHT_THRESHOLD = 30  # 이 값 이하면 어두움 (%)
TEMP_LOW = 18         # 이 값 이하면 추움 (°C)
TEMP_HIGH = 28        # 이 값 이상이면 더움 (°C)

# === 초기화 ===
print("=" * 45)
print("🏠 스마트 환경 모니터링 시스템")
print("=" * 45)
print(f"📌 어두움 기준: {LIGHT_THRESHOLD}% 이하")
print(f"📌 쾌적 온도: {TEMP_LOW}°C ~ {TEMP_HIGH}°C")
print("-" * 45)

count = 1

# === 메인 루프 ===
while True:
    # 조도 측정
    light_raw = light_sensor.read_u16()
    brightness = (light_raw / 65535) * 100

    # 어두우면 LED 켜기
    if brightness < LIGHT_THRESHOLD:
        led.on()
        light_status = "🌙 어두움 (LED ON)"
    else:
        led.off()
        light_status = "☀️ 밝음"

    # 온습도 측정
    try:
        dht_sensor.measure()
        temp = dht_sensor.temperature()
        humidity = dht_sensor.humidity()

        # 온도 평가
        if temp < TEMP_LOW:
            temp_status = "❄️ 추움"
        elif temp > TEMP_HIGH:
            temp_status = "🔥 더움"
        else:
            temp_status = "✅ 쾌적"

        # 결과 출력
        print(f"\n📊 측정 #{count}")
        print(f"   💡 밝기: {brightness:.1f}% | {light_status}")
        print(f"   🌡️ 온도: {temp}°C | {temp_status}")
        print(f"   💧 습도: {humidity}%")

    except Exception as e:
        print(f"\n📊 측정 #{count}")
        print(f"   💡 밝기: {brightness:.1f}% | {light_status}")
        print(f"   ⚠️ 온습도 센서 오류: {e}")

    count += 1
    time.sleep(3)

⚠️ 자주 하는 실수

실수 1: ADC 핀 번호 혼동

증상: 센서 값이 항상 0이거나 이상한 값이 나옴

원인: Grove Shield의 포트 이름과 실제 GPIO 번호가 달라!

해결:

# 잘못된 코드 ❌
light_sensor = ADC(Pin(0))  # A0라서 0번?

# 올바른 코드 ✅
light_sensor = ADC(Pin(26))  # A0 포트 = GPIO26!

Grove Shield 포트 매핑: | Grove 포트 | GPIO 번호 | |-----------|----------| | A0 | GPIO26 | | A1 | GPIO27 | | A2 | GPIO28 |


실수 2: DHT11 측정 간격 너무 짧음

증상: "센서 읽기 실패" 메시지가 자주 뜸

원인: DHT11은 최소 1초 이상 간격이 필요해!

해결:

# 잘못된 코드 ❌
while True:
    sensor.measure()
    print(sensor.temperature())
    time.sleep(0.1)  # 0.1초는 너무 짧아!

# 올바른 코드 ✅
while True:
    sensor.measure()
    print(sensor.temperature())
    time.sleep(2)  # 2초 이상 권장


실수 3: dht 라이브러리 미설치

증상: ImportError: no module named 'dht'

원인: dht 라이브러리가 설치되지 않음

해결: 1. Thonny 메뉴 → 도구패키지 관리 2. dht 검색 3. 설치 클릭

# 에러 메시지
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ImportError: no module named 'dht'

# 해결: 패키지 관리에서 dht 설치 후 다시 실행!

실수 4: try-except 없이 DHT 사용

증상: 프로그램이 가끔 멈춤

원인: DHT 센서는 가끔 통신 오류가 발생해

해결:

# 잘못된 코드 ❌
while True:
    sensor.measure()  # 여기서 에러나면 프로그램 종료!
    print(sensor.temperature())

# 올바른 코드 ✅
while True:
    try:
        sensor.measure()
        print(sensor.temperature())
    except:
        print("측정 실패, 다시 시도...")
    time.sleep(2)


✅ 스스로 점검하기

1. 아날로그와 디지털의 차이는?

버튼은 ( ) 신호, 조도 센서는 ( ) 신호를 출력해.

2. ADC의 역할은?

ADC는 ( ) 신호를 ( ) 신호로 변환해줘.

3. 피코 ADC의 범위는?

read_u16() 함수는 ( ) ~ ( ) 범위의 값을 반환해.

4. DHT11 측정 간격은?

DHT11 센서는 최소 ( )초 이상 간격을 줘야 해.

5. A0 포트의 GPIO 번호는?

Grove Shield의 A0 포트는 GPIO( )번이야.

정답 확인 1. 버튼은 **(디지털)** 신호, 조도 센서는 **(아날로그)** 신호를 출력해. 2. ADC는 **(아날로그)** 신호를 **(디지털)** 신호로 변환해줘. 3. `read_u16()` 함수는 **(0)** ~ **(65535)** 범위의 값을 반환해. 4. DHT11 센서는 최소 **(1)** 초 이상 간격을 줘야 해. (2초 권장) 5. Grove Shield의 A0 포트는 GPIO**(26)**번이야.

🚀 더 해보기

도전 1: 밝기 레벨 표시기 ⭐

밝기에 따라 다른 메시지를 출력해봐!

0~20%: "🌑 아주 어두움"
21~40%: "🌒 어두움"
41~60%: "🌓 보통"
61~80%: "🌔 밝음"
81~100%: "🌕 아주 밝음"

힌트: if-elif-else를 여러 개 써봐!


도전 2: 불쾌지수 계산기 ⭐⭐

온도와 습도로 불쾌지수를 계산해봐!

불쾌지수 = 0.81 × 온도 + 0.01 × 습도 × (0.99 × 온도 - 14.3) + 46.3
불쾌지수 체감
~67 쾌적 😊
68~74 보통 😐
75~79 불쾌 😣
80~ 매우 불쾌 😫

도전 3: 데이터 로깅 시스템 ⭐⭐⭐

측정 데이터를 파일로 저장해봐!

# 힌트: 파일 쓰기
with open("data.txt", "a") as f:
    f.write(f"{temp},{humidity},{brightness}\n")

나중에 엑셀에서 열어서 그래프를 그려볼 수 있어!


🔗 다음 장으로

이번 장에서 배운 것: - ✅ 아날로그 vs 디지털 신호의 차이 - ✅ ADC로 센서 값 읽기 (0~65535) - ✅ 조도 센서로 밝기 측정 - ✅ DHT11로 온도/습도 측정 - ✅ 센서 + LED로 자동 야간등 만들기

다음 장 예고: 🎨 출력의 마법 - 세상에 표현하다

지금까지 세상의 정보를 "읽는" 방법을 배웠어. 다음 장에서는 세상에 "표현"하는 방법을 배워볼 거야!

  • RGB LED로 무지개 색 만들기 🌈
  • 부저로 멜로디 연주하기 🎵
  • 서보모터로 움직임 만들기 🤖

센서가 느낀 정보를 다양한 방법으로 표현해보자!