아두이노와 주소 지정 LED 스트립으로 만드는 DIY 홀리데이 그림자 극장
부품 및 소모품
| 아두이노 101 (블루투스 내장) |
1개 |
| SparkFun 주소 지정 RGB LED 스트립 (타입 무관, 미세 조정 필요) |
1개 |
| SparkFun 수컷 배럴 잭 어댑터 (전자상가에서 구매 가능) |
1개 |
| SparkFun 암컷 배럴 잭 어댑터 |
1개 |
| SparkFun 3xAA 배터리 홀더 (스위치 포함) |
1개 |
| AA 배터리 (일반, 3개 필요) |
3개 |
| Pololu 스텝업 레귤레이터 12V (LED 스트립과 같은 배터리로 아두이노 101 구동용) |
1개 |
| A4 일반 프린터 용지 4장 |
1세트 |
| 카드스톡 100lb, A4 4장 |
1세트 |
| 흰색 3/16인치 폼 코어, A4 4장 분량 |
1세트 |
필요한 도구 및 장비
- 핫글루 건
- 납땜 인두
- 엑스액토 칼
- 여분 엑스액토 칼날 (#11)
- 와이어 스트리퍼 (12-20 AWG)
- 카드스톡 인쇄 가능한 프린터
- 배럴 잭 커넥터 단자 조일 소형 드라이버
앱 및 온라인 서비스
- 아두이노 IDE
- 블링크 (Blynk) - 스마트폰 원격 제어용
- Adafruit 네오픽셀 라이브러리
프로젝트 소개
개요
아두이노 101, 주소 지정 LED 스트립, 폼 코어, 카드스톡으로 스마트폰 제어 애니메이션 그림자 극장을 만듭니다. 전자 부품은 비파괴적으로 사용해 나중에 다른 프로젝트에 재사용 가능합니다. 스파크펀 위시리스트에 전자 부품 99%가 들어있습니다.
작동 원리: LED 스트립 한 개를 그림자 극장 중앙 폼 코어에 감습니다. 아래쪽 LED는 순차적으로 점등해 핀홀을 통해 빛을 내보내 애니메이션 그림자(눈 내리는 효과)를 만듭니다. 위쪽 LED는 건물 속으로 빛을 보내고, 스트립 마지막 LED는 전체 장면에 빛을 비춰 메인 그림자를 만듭니다.
아두이노 101에 내장된 블루투스 라디오로 블링크(Blynk) 앱과 연동해 원격 제어합니다. 예제 코드로 건물 색상 변경, 깜빡이는 불 효과, 메인 그림자 빛 밝기 조절이 가능합니다.
1부: 전자 부품 설정
1단계 LED 스트립 끝 하네스를 약 1cm 남기고 자르고 피복을 벗깁니다.
2단계 전압 레귤레이터에 동봉된 구부러진 헤더 핀을 펴서 녹색, 노란 선 끝에 납땜합니다. 아두이노 101 핀에 쉽게 꽂기 위함.
3단계 빨간 선을 레귤레이터 VIN 단자에, GND와 VOUT 단자엔 직각 헤더 핀을 납땜합니다.
4단계 배럴 잭 어댑터 연결: 배터리 케이스 선 끝을 벗겨 수컷 배럴 잭 단자에 연결(빨강=+, 검정=-). 암컷 배럴 잭 어댑터는 LED 스트립 선에 연결(노랑=-, 빨강=+).
5단계 하네스를 아두이노 101에 연결: 녹색→6번 핀, 노랑→13번 근처 GND. 레귤레이터 헤더 핀: GND→GND, VOUT→아두이노 Vin. 절대 반대로 꽂지 마세요! 타버립니다.
2부: 폼 코어 무대 조립
폼 코어 패턴은 일반 용지(4장)에, 카드스톡 패턴은 카드스톡(4장)에 인쇄하세요.
1단계 인쇄한 패턴을 폼 코어 위에 대고 취미용 칼로 가볍게 선을 그어 자르기 선을 전사하세요.
2단계 LED 스트립 홀더 조립 후 첫 LED를 바닥부터 테이프/핫글루로 고정하고 사진처럼 감습니다. 너무 팽팽할 필요 없습니다. 세 바퀴 감고 남은 꼬리는 자유롭게 둔 채 위쪽을 고정.
3단계 이 LED 스트립은 주소 지정 가능해 "중간 너 빨개져!" 같은 제어 가능합니다. 하지만 "야 너"라곤 안 부르니 LED 번호를 알아야 합니다. 주름 아래 LED는 뒤쪽 핀홀로 빠져나가 애니메이션용(내 예: 0,1,2,20,21,22,40,41,42). 위쪽 두 LED는 건물로 빛 보냄(23번: 뒷건물, 25번: 앞건물 불빛). 본인 설정대로 LED 번호 매기고 간단한 참조 맵을 그려 코드에 반영하세요. 컴퓨터는 0부터 셉니다.
4단계 LED 홀더를 폼 코어 바닥 조각에 핫글루로 고정(긴 줄무늬가 길이 방향 중앙쯤 오게). 양끝에 곡선 폼 코어 사이드 조각 붙이기.
5단계 빛 차단막과 폼 코어 상단 조각 추가. 차단막은 애니메이션 빛이 건물로 새는 것 방지. 큰 차단막은 LED 홀더 주름 근처, 작은 차단막은 그 위에 최소 한 개 LED 간격 두고 배치. 상단 조각은 바닥과 직각 되게 놓고 핫글루 고정.
6단계 LED 스트립 끝을 앞쪽 상단 모서리에 핫글루로 고정해 마지막 LED가 장면 전체를 비추게 합니다(메인 그림자 LED).
3부: 아두이노 101 프로그래밍 & 블링크 설정
USB 프로그래밍 케이블을 아두이노 101에 연결하고, LED 스트립, 배터리 팩, 아두이노 101을 모두 연결하세요(배터리 팩 스위치는 'off').
아두이노 IDE 설치 필요(인텔 퀴리 코어 포함, 아두이노 101 시작 가이드 참조). Adafruit 네오픽셀 라이브러리와 블링크 라이브러리도 설치하세요. 아두이노 초보면 기본 예제부터 돌려보세요.
1단계 스마트폰에 블링크 앱 설치. 블링크는 빠른 프로토타이핑과 아두이노 101 원격 제어에 최고입니다(BLE 버그 좀 있지만).
2단계 예제 코드를 아두이노 IDE에 불러와 앞서 만든 LED 맵에 맞게 픽셀 번호 수정.
// 눈 애니메이션 LED
int pos[] = {0, 1, 2, 20, 21, 22, 40, 41, 42}; // 애니메이션용 LED 번호, 왼쪽→오른쪽 순서로 호출
int numLeds = 9; // 위 배열에 몇 개?
int shadowPixel = 59; // 스트립 끝 메인 그림자 LED (60픽셀 스트립이면 59번)
int lightHousePixel = 23; // 뒷건물 조명용 픽셀 (두 빛 차단막 사이)
int firePixel = 24; // 앞건물 깜빡이는 불빛용 픽셀 (작은 차단막 앞)
수정 후 컴파일/업로드. USB 케이블 분리하고 배터리 팩 스위치 'on'. shadowPixel 켜지고 애니메이션 픽셀이 순차 점등. 집/불 픽셀은 블링크로 제어 전까지 꺼짐.
3단계 블링크 앱 실행, 우상단 '스캔' 버튼 눌러 QR 코드 스캔하면 컨트롤러 인터페이스 자동 로드.
4단계 BLE 위젯 탭해 아두이노 101 연결('ShadowTheatre' 표시). 우상단 '재생' 화살표로 제어 시작. 폰 절전 모드 후 재연결 필요할 수 있음.
4부: 카드스톡 실루엣, 건물, 마무리
1단계 인쇄된 카드스톡 4장에서 배경 실루엣 오려내기. 칼날 자주 교체하세요! 무딘 칼은 최악. 실루엣 자르는 데 3번 갈았습니다.
2단계 집 조각 오려서 뒷면 핫글루로 붙이기(인쇄면이 뒤쪽으로 가게).
3단계 집을 무대에 배치. 빛이 집 안으로만 들어가고 옆으로 새지 않게 틈새 막기.
4단계 실루엣 시트 양옆 접어 바닥을 무대 뒷면에 핫글루로 고정(인쇄면이 관객 반대쪽).
5단계 벽에 투영할 눈 씬 오려내기(핀/이쑤시개로 구멍 내거나 정교하게 오리기). 완료되면 곡선 모서리에 핫글루로 붙여 투영면 만들기.
6단계 왼쪽/앞쪽 시트 핫글루로 붙이기. 오른쪽 시트는 테이프로 느슨하게 붙여 배터리 케이스 전원 온/오프 가능하게.
완성! 어두운 곳 벽 근처에서 시험해 보세요. 전원 켜면 장면 그림자와 내리는 눈. 블링크 앱으로 메인 라이트, 건물 조명 제어 가능.
코드
/* Copyright (c) 2016 Intel Corporation. All rights reserved. */
///////////////////////본인 그림자 극장 설정에 맞게 변경할 변수들////////////////////////
// 눈 애니메이션 LED
int pos[] = {0, 1, 2, 20, 21, 22, 40, 41, 42};
int numLeds = 9;
int shadowPixel = 59; // 스트립 끝 메인 그림자 LED
int lightHousePixel = 23; // 뒷건물 조명 픽셀
int firePixel = 24; // 앞건물 깜빡이는 불빛 픽셀
////////////////////////////////////////////////////////////////////////////////////////
#include <Adafruit_NeoPixel.h>
#include <BlynkSimpleCurieBLE.h>
#include <CurieBLE.h>
#define PIN 6
int v0 = 0, v1 = 0, v2 = 0; // 블링크에서 들어오는 값 저장
int fadeup = 0, fadedown = 0; // 조명 애니메이션 스무딩용
int firetimer = 0, fireinterval = 50, flicker = 0; // 불 깜빡임용
unsigned long lightcounter = 0; // 애니메이션 LED 무한 순환 카운터
int stp = 0, stpOld = 0; // 애니메이션 스텝(현재 켤 것, 이전 끌 것)
unsigned long timer = 0;
int interval = 0;
char auth[] = "YourAuthToken"; // 블링크 BLE용 인증 토큰(현재 미사용, 향후 대비)
BLEPeripheral blePeripheral;
Adafruit_NeoPixel strip = Adafruit_NeoPixel(60, PIN, NEO_GRB + NEO_KHZ800); // 픽셀 수 60으로 설정(본인 스트립에 맞게 변경)
void setup() {
delay(1000);
timer = millis();
strip.begin();
strip.show(); // 모두 끔
blePeripheral.setLocalName("ShadowTheatre");
blePeripheral.setDeviceName("ShadowTheatre");
blePeripheral.setAppearance(384);
Blynk.begin(auth, blePeripheral);
blePeripheral.begin();
interval = 350; // 눈 애니메이션 간격 350ms
}
void loop() {
Blynk.run();
blePeripheral.poll();
//// 메인 그림자 픽셀 켜기 & 블링크로 제어
strip.setPixelColor(shadowPixel, 200 - v2, 160 - v2, 160 - v2); // v2(블링크 슬라이더)로 밝기 조절
// 불 효과
if ((millis() - firetimer) > fireinterval) {
firetimer = millis();
flicker = random(0, 40); // 일정 간격마다 불 밝기 0~40 랜덤 변경
}
if (v0 > 1) {
strip.setPixelColor(firePixel, 80 + v0 + flicker, v0 + flicker, 0); // 불 = 블링크 슬라이더 밝기 + flicker, 빨강 위주
} else {
strip.setPixelColor(firePixel, 0, 0, 0); // 블링크 슬라이더 0 이하면 끔
}
// 집 조명
if (v1 > 1) {
strip.setPixelColor(lightHousePixel, 200 - v1, v1, 0); // 뒷건물 조명 제어
} else {
strip.setPixelColor(lightHousePixel, 0, 0, 0);
}
// 눈 애니메이션
if ((millis() - timer) > interval) {
stpOld = stp;
timer = millis();
lightcounter++;
stp = (lightcounter % numLeds); // 0~numLeds-1 반복
fadeup = 0; fadedown = 170; // 페이드 값 리셋
}
fadeup += 2; fadeup = constrain(fadeup, 0, 170);
fadedown -= 2; fadedown = constrain(fadedown, 0, 170);
for (int i = 0; i < numLeds; i++) strip.setPixelColor(pos[i], 0, 0, 0); // 모든 애니메이션 LED 끔
strip.setPixelColor(pos[stp], fadeup, fadeup, fadeup); // 현재 스텝 LED 페이드 인
strip.setPixelColor(pos[stpOld], fadedown, fadedown, fadedown); // 이전 스텝 LED 페이드 아웃
strip.show(); // 스트립에 전송 표시
}
// 블링크에서 새 신호 들어오면 전역 변수 업데이트
BLYNK_WRITE(V0) { v0 = param.asInt(); } // 벽난로 슬라이더 → V0
BLYNK_WRITE(V1) { v1 = param.asInt(); } // 집 조명 슬라이더 → V1
BLYNK_WRITE(V2) { v2 = param.asInt(); } // 메인 그림자 LED 슬라이더 → V2
회로도 및 패턴 파일
- 폼 코어 자르기용 패턴 (일반 용지 4장 인쇄, 위에 대고 칼로 선 전사)
- 카드스톡 패턴 (카드스톡 4장 인쇄, 집/측면/실루엣용)
- 레이저/비닐 커터용 SVG 패턴: 30bn6Le68V1Lpp2spRMw.svg