Chapter 05: 출력의 마법 - 세상에 표현하다¶
🎯 이 장에서 배우는 것¶
- [ ] PWM의 개념과 듀티 사이클을 설명할 수 있다
- [ ] LED의 밝기를 부드럽게 조절할 수 있다
- [ ] RGB LED로 다양한 색상을 표현할 수 있다
- [ ] 부저로 멜로디를 연주할 수 있다
- [ ] 서보모터로 원하는 각도를 제어할 수 있다
💡 왜 이걸 배우나요?¶
지금까지 우리는 LED를 켜고 끄는 것만 했어. 마치 전등 스위치처럼 ON/OFF 두 가지 상태만 있었지.
그런데 생각해봐. 선풍기는 약/중/강 세기가 있고, 방 조명은 밝기 조절이 되고, 스마트폰 화면은 수백만 가지 색을 표현해. 이런 건 어떻게 하는 걸까?
우리가 지금까지 한 것: 오늘 배울 것:
⬛⬜ ⬛🟨🟧🟧🟧🟧🟧⬜
OFF ON 어둡게 ←→ 밝게
(2가지) (무한한 단계!)
오늘 배우는 PWM이라는 기술은 이 마법의 핵심이야. 이걸 이해하면:
- 🌈 RGB LED로 무지개 색을 만들고
- 🎵 부저로 "학교 종" 멜로디를 연주하고
- 🤖 서보모터로 로봇 팔처럼 각도를 조절할 수 있어!
📚 핵심 개념¶
개념 1: PWM (Pulse Width Modulation)¶
비유로 시작: PWM은 마치 눈 깜빡이기와 같아요.
방 전등을 생각해봐. 전등은 켜거나 끄는 것밖에 안 되잖아. 그런데 만약 1초에 100번씩 엄청 빠르게 껐다 켰다 반복하면 어떻게 보일까?
우리 눈이 그 속도를 따라가지 못해서 중간 밝기로 보여! 이게 PWM의 원리야.
정확히 말하면: PWM은 디지털 신호를 빠르게 ON/OFF 반복해서 아날로그처럼 중간 값을 만드는 기술이야. 한 주기에서 ON 상태인 비율을 듀티 사이클(Duty Cycle)이라고 해.
예시로 확인:
25% 듀티 사이클 (어두움):
┌─┐ ┌─┐ ┌─┐ ┌─┐
│█│ │█│ │█│ │█│ ← 25%만 켜짐
└─┴───┴─┴───┴─┴───┴─┘
50% 듀티 사이클 (중간):
┌──┐ ┌──┐ ┌──┐ ┌──┐
│██│ │██│ │██│ │██│ ← 50% 켜짐
└──┴──┴──┴──┴──┴──┴──┘
75% 듀티 사이클 (밝음):
┌───┐ ┌───┐ ┌───┐ ┌───┐
│███│ │███│ │███│ │███│ ← 75% 켜짐
└───┴─┴───┴─┴───┴─┴───┘
쉽게 말하면: PWM은 "엄청 빠르게 깜빡여서 눈속임하기"야. 깜빡이는 비율이 듀티 사이클!
개념 2: RGB LED의 색 혼합¶
비유로 시작: RGB LED는 마치 물감 섞기와 같아요. (정확히는 빛의 삼원색!)
정확히 말하면: RGB LED 안에는 빨강(R), 초록(G), 파랑(B) 3개의 LED가 들어있어. 각각의 밝기를 조절하면 1600만 가지 이상의 색을 만들 수 있어.
예시로 확인: | 색상 | R | G | B | 결과 | |------|---|---|---|------| | 빨강 | 255 | 0 | 0 | 🔴 | | 초록 | 0 | 255 | 0 | 🟢 | | 파랑 | 0 | 0 | 255 | 🔵 | | 노랑 | 255 | 255 | 0 | 🟡 | | 흰색 | 255 | 255 | 255 | ⚪ | | 주황 | 255 | 128 | 0 | 🟠 |
쉽게 말하면: RGB LED는 "3가지 색 LED를 섞어서 모든 색을 만드는 장치"야!
개념 3: 주파수와 소리¶
비유로 시작: 소리의 높낮이는 마치 줄넘기 속도와 같아요.
줄넘기를 천천히 돌리면 느릿느릿, 빨리 돌리면 휘잉~ 소리가 나잖아. 소리도 마찬가지야. 공기를 빠르게 진동시키면 높은 소리, 천천히 진동시키면 낮은 소리가 나.
정확히 말하면: 주파수(Hz)는 1초에 몇 번 진동하는지를 나타내. "도"는 262Hz(초당 262번), "솔"은 392Hz(초당 392번) 진동해.
예시로 확인:
낮은 도 (262Hz):
~~~~~~~~~~~~~~~~~~~~~ (1초에 262번)
높은 솔 (392Hz):
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (1초에 392번, 더 빽빽)
| 음계 | 주파수(Hz) |
|---|---|
| 도 | 262 |
| 레 | 294 |
| 미 | 330 |
| 파 | 349 |
| 솔 | 392 |
| 라 | 440 |
| 시 | 494 |
| 높은 도 | 523 |
쉽게 말하면: 주파수가 높으면 높은 소리, 낮으면 낮은 소리!
개념 4: 서보모터의 각도 제어¶
비유로 시작: 서보모터는 마치 시계 바늘과 같아요.
시계 바늘이 정확히 3시를 가리키는 것처럼, 서보모터는 "90도로 가!" 하면 정확히 90도 위치로 이동해.
정확히 말하면: 서보모터는 PWM 신호의 펄스 폭에 따라 0~180도 사이의 각도로 회전해. 1ms 펄스면 0도, 2ms 펄스면 180도야.
펄스 폭에 따른 각도:
1.0ms → 0° (완전히 왼쪽)
┌─┐
─┘ └────────────────
1.5ms → 90° (중앙)
┌──┐
─┘ └───────────────
2.0ms → 180° (완전히 오른쪽)
┌───┐
─┘ └──────────────
쉽게 말하면: 서보모터는 "몇 도로 가!" 하면 정확히 그 각도로 가는 모터야!
🔨 따라하기¶
Step 1: PWM으로 LED 밝기 조절하기¶
목표: 내장 LED의 밝기를 점점 밝게, 점점 어둡게 만들기
회로: 이번 단계는 피코 내장 LED를 사용하므로 추가 연결 없음!
코드:
# === WHAT: LED 밝기를 부드럽게 조절하는 코드 ===
# PWM을 사용해서 LED를 숨쉬듯이 밝아졌다 어두워졌다 하게 만들어요
# --- WHY: 왜 필요한지 ---
# 디지털 핀은 ON/OFF만 되는데, PWM을 쓰면 중간 밝기를 만들 수 있어요
# 이게 바로 스마트폰 화면 밝기 조절의 원리!
# HOW: 어떻게 동작하는지
from machine import Pin, PWM # Pin과 PWM 기능 가져오기
import time # 시간 관련 기능
# 내장 LED를 PWM 모드로 설정
led_pwm = PWM(Pin("LED")) # "LED"는 피코의 내장 LED
led_pwm.freq(1000) # 주파수 1000Hz (1초에 1000번 깜빡임)
print("LED 밝기 조절 시작!")
# 점점 밝아지기
print("밝아지는 중...")
for brightness in range(0, 65536, 1000): # 0부터 65535까지 1000씩 증가
led_pwm.duty_u16(brightness) # 밝기 설정 (0~65535)
time.sleep(0.02) # 0.02초 대기
# 점점 어두워지기
print("어두워지는 중...")
for brightness in range(65535, -1, -1000): # 65535부터 0까지 1000씩 감소
led_pwm.duty_u16(brightness)
time.sleep(0.02)
print("완료!")
led_pwm.deinit() # PWM 해제
실행 결과:
LED 밝기 조절 시작!
밝아지는 중...
어두워지는 중...
완료!
여기서 잠깐! 🤔
duty_u16()의 값 범위가 왜 0~65535일까?
- 16비트 = 2¹⁶ = 65536가지 단계
- 0 = 0% (완전 꺼짐)
- 32767 = 50% (중간 밝기)
- 65535 = 100% (최대 밝기)
Step 2: Grove RGB LED로 색 만들기¶
목표: RGB LED로 빨강, 초록, 파랑, 그리고 혼합색 만들기
회로 연결:
Grove RGB LED 연결 (D18 포트 사용)
Pico 2W Grove RGB LED
┌─────────────┐ ┌──────────────┐
│ │ │ │
│ 3V3 ●────┼────────────┼─ VCC (빨강) │
│ GND ●────┼────────────┼─ GND (검정) │
│ GP18 ●────┼────────────┼─ SIG (노랑) │
│ │ │ │
└─────────────┘ └──────────────┘
💡 Grove 케이블로 D18 포트에 꽂으면 끝!
코드:
# === WHAT: RGB LED로 다양한 색을 표현하는 코드 ===
# WS2812 타입 RGB LED를 제어해서 무지개 색을 만들어요
# --- WHY: 왜 필요한지 ---
# 단색 LED는 한 가지 색만 나오지만
# RGB LED는 빨강+초록+파랑을 섞어서 모든 색을 만들 수 있어요
# HOW: 어떻게 동작하는지
from machine import Pin
from neopixel import NeoPixel # RGB LED 제어 라이브러리
import time
# RGB LED 설정 (D18 포트, LED 1개)
rgb = NeoPixel(Pin(18), 1) # GPIO 18번에 연결, 1개의 LED
# 색상 정의 (R, G, B) - 각각 0~255 범위
RED = (255, 0, 0) # 빨강
GREEN = (0, 255, 0) # 초록
BLUE = (0, 0, 255) # 파랑
YELLOW = (255, 255, 0) # 노랑 (빨강+초록)
CYAN = (0, 255, 255) # 청록 (초록+파랑)
MAGENTA = (255, 0, 255)# 자주 (빨강+파랑)
WHITE = (255, 255, 255)# 흰색 (전부 최대)
OFF = (0, 0, 0) # 끄기
print("🌈 RGB LED 색상 테스트!")
# 색상 리스트
colors = [
("빨강", RED),
("초록", GREEN),
("파랑", BLUE),
("노랑", YELLOW),
("청록", CYAN),
("자주", MAGENTA),
("흰색", WHITE)
]
# 각 색상 표시
for name, color in colors:
print(f"현재 색: {name}")
rgb[0] = color # 첫 번째 LED에 색상 설정
rgb.write() # LED에 적용!
time.sleep(1) # 1초 대기
# 끄기
rgb[0] = OFF
rgb.write()
print("완료!")
실행 결과:
🌈 RGB LED 색상 테스트!
현재 색: 빨강
현재 색: 초록
현재 색: 파랑
현재 색: 노랑
현재 색: 청록
현재 색: 자주
현재 색: 흰색
완료!
여기서 잠깐! 🤔
rgb.write()를 왜 매번 호출해야 할까?
- rgb[0] = color는 메모리에 값만 저장하는 거야
- rgb.write()를 해야 실제로 LED에 신호가 전송돼!
- 마치 문서 작성 후 "저장" 버튼을 눌러야 저장되는 것처럼
Step 3: 무지개 색 그라데이션 만들기¶
목표: 색이 부드럽게 변하는 무지개 효과 만들기
코드:
# === WHAT: 무지개 그라데이션을 만드는 코드 ===
# 색상 값을 조금씩 바꿔서 부드러운 색 변화를 만들어요
# --- WHY: 왜 필요한지 ---
# 색이 뚝뚝 끊기지 않고 부드럽게 변하면 더 예뻐요
# 게이밍 키보드, 무드등에서 많이 쓰이는 효과!
# HOW: 어떻게 동작하는지
from machine import Pin
from neopixel import NeoPixel
import time
rgb = NeoPixel(Pin(18), 1)
def wheel(pos):
"""색상환에서 0~255 위치의 색을 반환하는 함수"""
# 0~255 값을 받아서 무지개 색을 만들어요
if pos < 85:
# 빨강 → 초록
return (255 - pos * 3, pos * 3, 0)
elif pos < 170:
# 초록 → 파랑
pos -= 85
return (0, 255 - pos * 3, pos * 3)
else:
# 파랑 → 빨강
pos -= 170
return (pos * 3, 0, 255 - pos * 3)
print("🌈 무지개 그라데이션 시작!")
print("Ctrl+C로 종료하세요")
try:
while True:
# 0부터 255까지 색상 변화
for i in range(256):
rgb[0] = wheel(i)
rgb.write()
time.sleep(0.02) # 부드러운 변화를 위해 짧은 딜레이
except KeyboardInterrupt:
# Ctrl+C를 누르면 종료
rgb[0] = (0, 0, 0)
rgb.write()
print("\n종료!")
실행 결과:
🌈 무지개 그라데이션 시작!
Ctrl+C로 종료하세요
Step 4: Grove 부저로 소리 내기¶
목표: 부저로 "도레미파솔라시도" 연주하기
회로 연결:
Grove Buzzer 연결 (D20 포트 사용)
Pico 2W Grove Buzzer
┌─────────────┐ ┌──────────────┐
│ │ │ 🔊 │
│ 3V3 ●────┼────────────┼─ VCC (빨강) │
│ GND ●────┼────────────┼─ GND (검정) │
│ GP20 ●────┼────────────┼─ SIG (노랑) │
│ │ │ │
└─────────────┘ └──────────────┘
💡 Grove 케이블로 D20 포트에 연결!
코드:
# === WHAT: 부저로 음계를 연주하는 코드 ===
# PWM 주파수를 바꿔서 도레미파솔라시도를 연주해요
# --- WHY: 왜 필요한지 ---
# 부저는 전기 신호를 소리로 바꿔주는 장치예요
# 알람, 효과음, 간단한 멜로디를 만들 수 있어요
# HOW: 어떻게 동작하는지
from machine import Pin, PWM
import time
# 부저를 PWM 모드로 설정 (D20 포트)
buzzer = PWM(Pin(20))
# 음계별 주파수 정의 (Hz)
NOTES = {
'C4': 262, # 도
'D4': 294, # 레
'E4': 330, # 미
'F4': 349, # 파
'G4': 392, # 솔
'A4': 440, # 라
'B4': 494, # 시
'C5': 523, # 높은 도
'REST': 0 # 쉼표 (무음)
}
def play_tone(frequency, duration):
"""특정 주파수의 소리를 duration 초 동안 재생"""
if frequency == 0:
# 쉼표면 소리 끄기
buzzer.duty_u16(0)
else:
buzzer.freq(frequency) # 주파수 설정
buzzer.duty_u16(32768) # 50% 듀티 (소리 크기)
time.sleep(duration)
buzzer.duty_u16(0) # 소리 끄기
time.sleep(0.05) # 음 사이 짧은 간격
print("🎵 도레미파솔라시도 연주!")
# 음계 연주
scale = ['C4', 'D4', 'E4', 'F4', 'G4', 'A4', 'B4', 'C5']
for note in scale:
print(f"♪ {note}")
play_tone(NOTES[note], 0.3) # 0.3초씩 연주
print("🎵 역순으로!")
for note in reversed(scale):
print(f"♪ {note}")
play_tone(NOTES[note], 0.3)
buzzer.deinit() # PWM 해제
print("연주 완료!")
실행 결과:
🎵 도레미파솔라시도 연주!
♪ C4
♪ D4
♪ E4
♪ F4
♪ G4
♪ A4
♪ B4
♪ C5
🎵 역순으로!
♪ C5
♪ B4
...
연주 완료!
여기서 잠깐! 🤔
duty_u16(32768)은 뭘까?
- 32768은 65535의 절반, 즉 50% 듀티 사이클이야
- 부저는 ON/OFF 비율이 50%일 때 가장 깨끗한 소리가 나!
- 값을 바꾸면 소리 크기가 변해 (0이면 무음)
Step 5: 학교 종 멜로디 연주하기¶
목표: "학교 종이 땡땡땡" 멜로디 완성하기
코드:
# === WHAT: "학교 종" 멜로디를 연주하는 코드 ===
# 음계와 박자를 조합해서 실제 노래를 연주해요
# --- WHY: 왜 필요한지 ---
# 단순 음계보다 실제 노래를 연주하면 더 재미있어요!
# 알람 시계, 도어벨, 게임 효과음 등에 활용 가능
# HOW: 어떻게 동작하는지
from machine import Pin, PWM
import time
buzzer = PWM(Pin(20))
# 음계 주파수
NOTES = {
'C4': 262, 'D4': 294, 'E4': 330, 'F4': 349,
'G4': 392, 'A4': 440, 'B4': 494, 'C5': 523,
'REST': 0
}
def play_tone(frequency, duration):
if frequency == 0:
buzzer.duty_u16(0)
else:
buzzer.freq(frequency)
buzzer.duty_u16(32768)
time.sleep(duration)
buzzer.duty_u16(0)
time.sleep(0.03)
# 🎵 학교 종이 땡땡땡 악보
# (음, 박자) 형식 - 박자 1 = 0.4초
school_bell = [
('G4', 1), ('G4', 1), ('A4', 1), ('A4', 1), # 학교 종이
('G4', 1), ('G4', 1), ('E4', 2), # 땡땡땡
('G4', 1), ('G4', 1), ('E4', 1), ('E4', 1), # 어서 모이
('D4', 2), ('REST', 1), # 자~
('G4', 1), ('G4', 1), ('A4', 1), ('A4', 1), # 선생님이
('G4', 1), ('G4', 1), ('E4', 2), # 우리를
('G4', 1), ('E4', 1), ('D4', 1), ('E4', 1), # 기다리신
('C4', 2), # 다
]
print("🔔 학교 종이 땡땡땡 연주 시작!")
print()
beat = 0.4 # 한 박자 = 0.4초
for note, duration in school_bell:
play_tone(NOTES[note], beat * duration)
buzzer.deinit()
print("🎵 연주 완료!")
실행 결과:
🔔 학교 종이 땡땡땡 연주 시작!
🎵 연주 완료!
Step 6: Grove 서보모터 각도 제어하기¶
목표: 서보모터를 0도, 90도, 180도로 움직이기
회로 연결:
Grove Servo 연결 (D16 포트 사용)
Pico 2W Grove Servo
┌─────────────┐ ┌──────────────┐
│ │ │ 🔧 │
│ 3V3 ●────┼────────────┼─ VCC (빨강) │
│ GND ●────┼────────────┼─ GND (검정) │
│ GP16 ●────┼────────────┼─ SIG (노랑) │
│ │ │ │
└─────────────┘ └──────────────┘
💡 Grove 케이블로 D16 포트에 연결!
⚠️ 서보모터는 전류를 많이 먹어서 USB 전원으로 1-2개까지만!
코드:
# === WHAT: 서보모터 각도를 제어하는 코드 ===
# PWM 신호의 펄스 폭을 조절해서 0~180도 회전시켜요
# --- WHY: 왜 필요한지 ---
# 서보모터는 정확한 각도 제어가 가능해서
# 로봇 팔, 자동문, RC카 조향 등에 사용돼요
# HOW: 어떻게 동작하는지
from machine import Pin, PWM
import time
# 서보모터 PWM 설정 (D16 포트)
servo = PWM(Pin(16))
servo.freq(50) # 서보모터는 50Hz (1초에 50번)
def set_angle(angle):
"""0~180도 각도를 설정하는 함수"""
# 서보모터는 펄스 폭으로 각도 결정
# 0도 = 0.5ms, 90도 = 1.5ms, 180도 = 2.5ms
# 50Hz에서 한 주기 = 20ms = 20000us
# 각도를 듀티 사이클로 변환
# 0도 → 500us/20000us = 2.5% → 1638 (65535의 2.5%)
# 180도 → 2500us/20000us = 12.5% → 8192 (65535의 12.5%)
min_duty = 1638 # 0도 (약 0.5ms)
max_duty = 8192 # 180도 (약 2.5ms)
duty = int(min_duty + (max_duty - min_duty) * angle / 180)
servo.duty_u16(duty)
print("🔧 서보모터 테스트!")
# 기본 위치로
print("90도 (중앙)")
set_angle(90)
time.sleep(1)
# 0도로
print("0도 (왼쪽)")
set_angle(0)
time.sleep(1)
# 180도로
print("180도 (오른쪽)")
set_angle(180)
time.sleep(1)
# 다시 중앙으로
print("90도 (중앙)")
set_angle(90)
time.sleep(1)
servo.deinit()
print("완료!")
실행 결과:
🔧 서보모터 테스트!
90도 (중앙)
0도 (왼쪽)
180도 (오른쪽)
90도 (중앙)
완료!
Step 7: 부드러운 서보모터 움직임¶
목표: 서보모터를 부드럽게 스윕하기
코드:
# === WHAT: 서보모터를 부드럽게 움직이는 코드 ===
# 각도를 조금씩 바꿔서 부드러운 움직임을 만들어요
# --- WHY: 왜 필요한지 ---
# 급격한 움직임보다 부드러운 움직임이 더 자연스럽고
# 서보모터에도 무리가 덜 가요
# HOW: 어떻게 동작하는지
from machine import Pin, PWM
import time
servo = PWM(Pin(16))
servo.freq(50)
def set_angle(angle):
min_duty = 1638
max_duty = 8192
duty = int(min_duty + (max_duty - min_duty) * angle / 180)
servo.duty_u16(duty)
print("🔧 부드러운 서보모터 스윕!")
print("Ctrl+C로 종료")
try:
while True:
# 0도에서 180도까지
print("→ 오른쪽으로...")
for angle in range(0, 181, 2): # 2도씩 증가
set_angle(angle)
time.sleep(0.02)
# 180도에서 0도까지
print("← 왼쪽으로...")
for angle in range(180, -1, -2): # 2도씩 감소
set_angle(angle)
time.sleep(0.02)
except KeyboardInterrupt:
set_angle(90) # 중앙으로 복귀
servo.deinit()
print("\n종료!")
📝 전체 코드: 감정 표현 장치¶
센서 없이 버튼으로 감정을 선택하고, RGB LED + 부저 + 서보모터로 표현하는 장치!
# === 감정 표현 장치 ===
# 버튼을 누를 때마다 다른 감정을 RGB LED, 부저, 서보모터로 표현해요
# 복사해서 바로 실행 가능!
from machine import Pin, PWM
from neopixel import NeoPixel
import time
# === 하드웨어 설정 ===
button = Pin(20, Pin.IN, Pin.PULL_DOWN) # D20에 버튼 (Grove 버튼이 없으면 주석처리)
rgb = NeoPixel(Pin(18), 1) # D18에 RGB LED
buzzer = PWM(Pin(16)) # D16에 부저
# servo = PWM(Pin(16)) # 서보모터 사용 시 (부저와 같은 핀이면 번갈아 사용)
# === 음계 정의 ===
NOTES = {
'C4': 262, 'D4': 294, 'E4': 330, 'F4': 349,
'G4': 392, 'A4': 440, 'B4': 494, 'C5': 523
}
# === 감정 정의 ===
emotions = [
{
'name': '😊 행복',
'color': (255, 255, 0), # 노랑
'melody': [('C5', 0.2), ('E4', 0.2), ('G4', 0.2), ('C5', 0.4)]
},
{
'name': '😢 슬픔',
'color': (0, 0, 255), # 파랑
'melody': [('E4', 0.4), ('D4', 0.4), ('C4', 0.6)]
},
{
'name': '😠 화남',
'color': (255, 0, 0), # 빨강
'melody': [('C4', 0.1), ('C4', 0.1), ('C4', 0.1)]
},
{
'name': '😌 평화',
'color': (0, 255, 100), # 연두
'melody': [('G4', 0.3), ('A4', 0.3), ('G4', 0.5)]
}
]
def play_tone(freq, duration):
"""음 재생"""
if freq > 0:
buzzer.freq(freq)
buzzer.duty_u16(32768)
time.sleep(duration)
buzzer.duty_u16(0)
time.sleep(0.02)
def express_emotion(emotion):
"""감정 표현"""
print(f"\n{emotion['name']}")
# RGB LED 색상
rgb[0] = emotion['color']
rgb.write()
# 멜로디 재생
for note, duration in emotion['melody']:
play_tone(NOTES.get(note, 0), duration)
time.sleep(0.5)
# LED 끄기
rgb[0] = (0, 0, 0)
rgb.write()
# === 메인 프로그램 ===
print("🎭 감정 표현 장치")
print("버튼을 누르면 감정이 바뀝니다!")
print("(버튼이 없으면 자동으로 순환)")
print("-" * 30)
current_emotion = 0
# 버튼이 있는 경우
if button:
print("버튼을 눌러보세요!")
while True:
if button.value() == 1:
express_emotion(emotions[current_emotion])
current_emotion = (current_emotion + 1) % len(emotions)
time.sleep(0.3) # 디바운싱
time.sleep(0.1)
else:
# 버튼이 없으면 자동 순환
print("자동 순환 모드")
while True:
express_emotion(emotions[current_emotion])
current_emotion = (current_emotion + 1) % len(emotions)
time.sleep(2)
⚠️ 자주 하는 실수¶
실수 1: PWM 주파수를 설정 안 함¶
증상: 서보모터가 떨리거나 이상하게 움직임 원인: 서보모터는 정확히 50Hz가 필요한데 기본값이 다를 수 있어 해결:
# 잘못된 코드
servo = PWM(Pin(16))
# 주파수 설정 안 함!
# 올바른 코드
servo = PWM(Pin(16))
servo.freq(50) # 서보모터는 반드시 50Hz!
실수 2: rgb.write() 호출 안 함¶
증상: RGB LED 색상이 안 바뀜 원인: 값만 설정하고 실제 전송을 안 함 해결:
# 잘못된 코드
rgb[0] = (255, 0, 0)
# write() 안 함 - LED는 그대로!
# 올바른 코드
rgb[0] = (255, 0, 0)
rgb.write() # 이걸 해야 LED가 바뀜!
실수 3: 부저 duty를 0으로 안 바꿈¶
증상: 소리가 계속 나거나 이상한 소음 원인: 음 사이에 소리를 끄지 않음 해결:
# 잘못된 코드
def play_tone(freq, duration):
buzzer.freq(freq)
buzzer.duty_u16(32768)
time.sleep(duration)
# 소리 안 끔!
# 올바른 코드
def play_tone(freq, duration):
buzzer.freq(freq)
buzzer.duty_u16(32768)
time.sleep(duration)
buzzer.duty_u16(0) # 반드시 소리 끄기!
실수 4: 서보모터 각도 범위 초과¶
증상: 서보모터가 부들부들 떨리거나 "윙~" 소리 원인: 0~180도 범위를 벗어난 값 입력 해결:
# 잘못된 코드
set_angle(200) # 180도 초과!
set_angle(-10) # 0도 미만!
# 올바른 코드
def set_angle(angle):
# 범위 제한 추가!
angle = max(0, min(180, angle))
# 이하 동일...
실수 5: NeoPixel 개수 잘못 설정¶
증상: LED가 안 켜지거나 이상한 색 원인: 연결된 LED 개수와 설정이 다름 해결:
# 잘못된 코드 (LED 1개인데 10개로 설정)
rgb = NeoPixel(Pin(18), 10)
# 올바른 코드 (실제 연결된 개수로!)
rgb = NeoPixel(Pin(18), 1) # Grove RGB LED는 보통 1개
✅ 스스로 점검하기¶
1. PWM의 듀티 사이클이 50%라면 LED 밝기는 어느 정도일까?¶
a) 최대 밝기
b) 절반 밝기
c) 꺼진 상태
d) 25% 밝기
2. RGB LED로 노란색을 만들려면 어떤 값을 설정해야 할까?¶
a) (255, 255, 0)
b) (255, 0, 255)
c) (0, 255, 255)
d) (255, 255, 255)
3. 서보모터의 PWM 주파수는 보통 몇 Hz로 설정할까?¶
a) 1000Hz
b) 100Hz
c) 50Hz
d) 10Hz
4. "라" 음의 주파수는?¶
a) 262Hz
b) 392Hz
c) 440Hz
d) 523Hz
5. duty_u16(65535)는 몇 %의 듀티 사이클일까?¶
a) 0%
b) 50%
c) 75%
d) 100%
정답 확인
1. **b) 절반 밝기** - 듀티 사이클 50%는 절반의 시간만 켜지므로 절반 밝기 2. **a) (255, 255, 0)** - 빨강 + 초록 = 노랑 3. **c) 50Hz** - 서보모터의 표준 PWM 주파수 4. **c) 440Hz** - 라(A4)는 음악의 기준음으로 440Hz 5. **d) 100%** - 65535는 최대값이므로 100% 듀티 사이클🚀 더 해보기¶
도전 1: 신호등 만들기 (쉬움)¶
RGB LED로 신호등을 만들어봐! 빨강 3초 → 노랑 1초 → 초록 3초 반복
# 힌트
colors = [(255,0,0), (255,255,0), (0,255,0)] # 빨, 노, 초
times = [3, 1, 3] # 각각의 지속 시간
도전 2: 피아노 키보드 (중간)¶
버튼 여러 개를 연결해서 각각 다른 음이 나는 피아노를 만들어봐! - 버튼 1 → 도 - 버튼 2 → 레 - 버튼 3 → 미 - ...
도전 3: 무드등 + BGM ⭐ (어려움)¶
RGB LED 무지개 그라데이션을 돌리면서 동시에 잔잔한 멜로디가 나오는 무드등을 만들어봐!
힌트: 한 번에 두 가지를 하려면 타이밍 조절이 중요해!
# 힌트: 멜로디를 잘게 쪼개서 색 변화 사이에 끼워넣기
for i in range(256):
rgb[0] = wheel(i)
rgb.write()
# 여기서 아주 짧은 음을 재생
if i % 32 == 0: # 가끔씩만
play_short_note()
time.sleep(0.02)
🔗 다음 장으로¶
이번 장에서 배운 것: - ⚡ PWM: 빠르게 껐다 켜서 중간값 만들기 - 🌈 RGB LED: 세 가지 색을 섞어 모든 색 표현 - 🎵 부저: 주파수로 음높이 조절 - 🔧 서보모터: 펄스 폭으로 정확한 각도 제어
다음 장에서는 조건문과 반복문을 배워서, 센서 값에 따라 자동으로 반응하는 "자동 야간등"을 만들어볼 거야!
"밝으면 LED 끄고, 어두우면 LED 켜기" - 진짜 스마트한 장치의 시작이야! 🌙