Dot Light Pattern

빛을 손으로 직접 조절하고 나의 마음대로 표현할 수는 없을까? 라는 생각에서 시작하게 되었다. 직접 조절하여 원하는 색을 만들고 그러한 색들로 자신만의 패턴을 디자인하며 여러 애니메이션 효과들을 경험할 수 있는 도트 라이트 패턴(Dot Light Pattern)이다.

Step 1: Materials

  1. Arduino UNO x 13
  2. WS2901 or WS2811 pixel LED strip (130 LEDS)
  3. Button switch x 1
  4. Snap switch x 65
  5. Potentionmeter x 65
  6. Rainbow cable
  7. Power suffly SMPS
  8. Conductor cable
  9. Acrylic transparent round bar (50mm diameter)
  10. Black color Acrylic board (5T) (500mm*790mm) x 2, (500mm*35mm) x 2, (790mm*35mm) x 2

Step 2: Construction Plan

Step 3: Hardware : Circuit Design

  1. 아크릴판을 위 구조와 같이 커팅한다. (STEP2 참고)
  2. 아랫면 아크릴판에 낱개로 자른 네오픽셀 LED 를 가변저항 구멍의 위, 아래로 한 개씩 붙여 총 65쌍의 네오픽셀 LED를 붙인다.
  3. 한 쌍의 네오픽셀 LED는 하나의 Arduino 핀으로 쓸 수 있도록 와이어로 함께 연결하여 납댐한다.
  4. 65개의 가변저항을 가변저항 구멍에 맞게 끼워 붙인다. (네오픽셀을 붙인 면의 반댓면에서 끼운다.)
  5. 65개의 스냅 스위치를 스위치 구멍에 맞게 끼워 붙인다.
  6. 65개씩의 하드웨어를 5개씩 묶어 하나의 Arduino UNO에 연결하기 위해 총 13개의 Arduino UNO를 13개의 구역마다 붙인다.
  7. 첨부된 사진과 같이 가변저항, 스냅스위치 그리고 네오픽셀 LED를 와이어와 납댐하여 Arduino UNO의 핀에 각각 연결한다. (STEP2 참고)
  8. 여러개의 Arduino UNO의 GND와 5V 핀은 케이블 전선에 각각 모아 납댐 후 외부전력에 연결한다. (STEP2 참고)
  9. 에어프레서로 먼지를 제거해준다.

Step 4: Hardware : Acrylic Cutting

  1. 아크릴 봉의 길이는 50mm로 잘라준다.
  2. 아크릴 봉의 한 쪽 단면은 가변저항의 컨트롤러 부분과 맞는 크기와 깊이로 뚫어준다.
  3. 아크릴 봉이 가변저항에 잘 끼워질 수 있는 유격을 위해 구멍보다 살짝 넓게 다듬어준다.
  4. 다른 한 면은 빛이 깔끔하게 투과될 수 있도록 약간의 사포질을 해준다.

Step 5: Arduino Programming Code

https://www.kasperkamperman.com/blog/arduino/ardui...

'hsb to rgb' code를 참고한 사이트

//'adafruit_neopixel'헤더파일라는 외부 라이브러리를 포함
#include

//네오픽셀 연결 핀번호 선언 #define PIN1 2 #define PIN2 3 #define PIN3 4 #define PIN4 5 #define PIN5 6

#define NUMPIXELS 2 //네오픽셀 LED 갯수 #define NUM_LIGHTS 5 //작동 모듈갯수(네오픽셀 오브젝트 갯수)

//네오픽셀 오브젝트 Array 선언 Adafruit_NeoPixel pixels[] = { Adafruit_NeoPixel(NUMPIXELS, PIN1, NEO_GRB + NEO_KHZ800), Adafruit_NeoPixel(NUMPIXELS, PIN2, NEO_GRB + NEO_KHZ800), Adafruit_NeoPixel(NUMPIXELS, PIN3, NEO_GRB + NEO_KHZ800), Adafruit_NeoPixel(NUMPIXELS, PIN4, NEO_GRB + NEO_KHZ800), Adafruit_NeoPixel(NUMPIXELS, PIN5, NEO_GRB + NEO_KHZ800) }; ////네오픽셀을 사용하기 위해 객체 하나를 생성한다. //첫번째 인자값은 네오픽셀의 LED의 개수 //두번째 인자값은 네오픽셀이 연결된 아두이노의 핀번호 //세번째 인자값은 네오픽셀의 타입에 따라 바뀌는 flag

////////////////////////////////////////////////////////////// //////HSV 를 RGB로 변환하는 함수 getRGB()를 위한 변수와 함수 선언

const byte dim_curve[] = { 0, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 20, 20, 20, 21, 21, 22, 22, 22, 23, 23, 24, 24, 25, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 32, 32, 33, 33, 34, 35, 35, 36, 36, 37, 38, 38, 39, 40, 40, 41, 42, 43, 43, 44, 45, 46, 47, 48, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 68, 69, 70, 71, 73, 74, 75, 76, 78, 79, 81, 82, 83, 85, 86, 88, 90, 91, 93, 94, 96, 98, 99, 101, 103, 105, 107, 109, 110, 112, 114, 116, 118, 121, 123, 125, 127, 129, 132, 134, 136, 139, 141, 144, 146, 149, 151, 154, 157, 159, 162, 165, 168, 171, 174, 177, 180, 183, 186, 190, 193, 196, 200, 203, 207, 211, 214, 218, 222, 226, 230, 234, 238, 242, 248, 255, }; //

void getRGB(int hue, int sat, int val, int colors[5][3], int index) { val = dim_curve[val]; sat = 255 - dim_curve[255 - sat];

//색조, 채도 및 밝기 (HSB / HSV)를 RGB로 변환 //dim_curve는 밝기/값 및 채도 (반전)에서만 사용됩니다. //이것은 가장 자연스럽게 보입니다.

int r; int g; int b; int base;

if (sat == 0) { // 회색. 색조는 상관 없 colors[index][0] = val; colors[index][1] = val; colors[index][2] = val; } else {

base = ((255 - sat) * val) >> 8;

switch (hue / 60) { case 0: r = val; g = (((val - base) * hue) / 60) + base; b = base; break;

case 1: r = (((val - base) * (60 - (hue % 60))) / 60) + base; g = val; b = base; break;

case 2: r = base; g = val; b = (((val - base) * (hue % 60)) / 60) + base; break;

case 3: r = base; g = (((val - base) * (60 - (hue % 60))) / 60) + base; b = val; break;

case 4: r = (((val - base) * (hue % 60)) / 60) + base; g = base; b = val; break;

case 5: r = val; g = base; b = (((val - base) * (60 - (hue % 60))) / 60) + base; break; }

colors[index][0] = r; colors[index][1] = g; colors[index][2] = b; }

}

int rgb_colors[NUM_LIGHTS][3]; //네오픽셀 오브젝트갯수마다 rgb color 선언 int hue[NUM_LIGHTS]; //네오픽셀 오브젝트갯수마다 hue 선언 int sat[NUM_LIGHTS]; //네오픽셀 오브젝트갯수마다 명도 선언 int brignt[NUM_LIGHTS]; //네오픽셀 오브젝트갯수마다 밝기 서언

//일반 변수 선언 int startsSwitch[] = {8, 9, 10, 11, 12}; // on/off 버튼 핀번호 boolean startState[] = {false, false, false, false, false}; // on/off 상태변수

const int colorPin[] = {A0, A1, A2, A3, A4}; // 가변저항 핀번호 int colorVal[] = {0, 0, 0, 0, 0}; // 가변저항 초기값

int animationButton = 7; // 애니메이션 모드변환 버튼 핀번호

///////////////////////////////////////////////// //애니메이션 모든 변환을 위한 버튼 디바운싱 변수선언 //디바운싱? 짧은 시간내 많은 이벤트가 발생하는것에 대한 문제에 대해서 지정된 시간 간격으로 함수를 호출하여 해결 int buttonState; // 입력 핀으로부터의 현재 판독값 int lastButtonState = HIGH; // 이전의 판독값은 켜진상태로 unsigned long lastDebounceTime = 0; // 출력핀이 마지막으로 전환된 시간은 0으로 unsigned long debounceDelay = 50; // 디바운싱 타임설정;출력이 깜빡이면 증가한다 int MODE = 0; //애니메이션 모드변수

int B_Interval[5]; //블링킹을 위한 각 모듈의 랜덤 속도 변수 int B_Min = 100; //블링킹 최단속도; int B_Max = 500; //블링킹 최장속도; int R_Interval = 50; //레인보우 애니메이션 속도 변수 int D_Interval = 10; //디밍 속도 변수

boolean B_state[5]; //블링킹을 위한 각 모듈의 상태변수

/////////////////////////////////////////////////////// //멀티테스킹 애니메이션을 위한 시간변수 선언

unsigned long currentMillis; //현재시간 변수 unsigned long B_previousMillis[5]; //각 모듈의 블링킹 타이머 unsigned long DR_Millis[5]; //각 모듈의 디밍 랜덤 타이머(예비) unsigned long R_previousMillis; //레인보우 타이머 unsigned long D_previousMillis; //디밍 타이머

boolean firstRainbow = true; //레인보우 색상 초기화 상태변수

int RainbowSpeed; //레인보우 변환변수 int Bright = 100; //디밍 초기값 int BrightnessFactor = 1; //디밍 증감 값 ///////////////////////////////////////////////////////////////////////////////////

void setup() {

for (int i = 0; i < NUM_LIGHTS; i++) { pixels[i].begin(); //네오픽셀 오브젝트 초기화 }

//버튼 인풋 설정 for (int i = 0; i < NUM_LIGHTS; i++) { pinMode(startsSwitch[i], INPUT_PULLUP); //on/off 버튼 인풋 설정 } pinMode(animationButton, INPUT_PULLUP); //애니메이션 버튼 인풋 설정

for (int i = 0; i < NUM_LIGHTS; i++) { B_Interval[i] = int(random(B_Min, B_Max)); //모듈별 블링킹 랜덤 속도(인터발) 변수 생성 }

Serial.begin(9600); //통신 설정 }

void loop() {

MODE = CheckAnimMode(); //모드에 애니메이션체크모드함수를 넣는다

//버튼과 가변저항을 값을 각각 읽어 변수에 지정한다. for (int i = 0; i < NUM_LIGHTS; i++) { startState[i] = !digitalRead(startsSwitch[i]); //on/off 버튼에서 읽은 값의 반대값을 startState에 넣어준다 //startState[i] = digitalRead(startsSwitch[i]); colorVal[i] = analogRead(colorPin[i]); //가변저항에서 읽은 값을 가변저항 초기값에 넣는다 }

switch (MODE) { //애니메이션함수 스위치문 case 0: on(); //on함수 실행 break; //조건문에서 빠져나가라

case 1: rainbow(); //rainbow함수 실행 break;

case 2: dimming(); // dimming함수 실행 break;

case 3: blinking(); //blinking함수 실행 break; }

for (int i = 0; i < NUM_LIGHTS; i++) { pixels[i].show(); //네오픽셀 오브젝트 배열 켜 }

}

/////////////////////////////////////////////////////////////

int CheckAnimMode() {

//애니메이션 선택 버튼을 읽어 모드를 결정한다. ///////////////////////////////////////////////////// currentMillis = millis(); // 시간 측정 int reading = digitalRead(animationButton); if (reading != lastButtonState) { //입력핀으로부터 이전의 버튼의 상태와 판독값 비교 lastDebounceTime = millis(); //현재 시간을 출력핀이 마지막으로 전환된 시간에 넣음 }

if ((currentMillis - lastDebounceTime) > debounceDelay) {

if (reading != buttonState) { //입력핀으로부터 받은 현재값과 판독값과 비교 buttonState = reading; //판독값을 buttonState에 대입

if (buttonState == LOW) { //버튼상태가 꺼져있다면 MODE++; //버튼모드 1씩 증가 if (MODE > 3) { MODE = 0; firstRainbow = true; //레인보우 색상 초기화 상태 켜짐 BrightnessFactor = 1; //디밍 증감값 Bright = 15; //밝기는 15 } } } }

lastButtonState = reading; //판독값을 이전의 버튼상태에 대입 return MODE ; 함수를 종료하고 mode함수로 값을 리턴하라 }

//////////////////////////////////////////////////////////////////// //animation mode functuation

//on void on() { Serial.println("on"); //시리얼 모니터에 on을 써라 for (int i = 0; i < NUM_LIGHTS; i++) { color_set(i, colorVal[i]); //가변저항 값에 따라 컬러 셋팅 } }

//Rainbow void rainbow() { Serial.println("rain"); //시리얼 모니터에 rain을 써라 if (firstRainbow) { RainbowSpeed = 0; //레인보우 속도 초기화 firstRainbow = false; //레인보우 색상 초기화 상태 꺼짐 } if (millis() - R_previousMillis > R_Interval) { R_previousMillis = currentMillis; RainbowSpeed += 10; //레인보우 변환변수에 10을 더해라 }

for (int i = 0; i < NUM_LIGHTS; i++) { color_set(i, (colorVal[i] + RainbowSpeed) % 1023); }

}

//Dimming void dimming() { Serial.println("dimm"); //시리얼모니터에 dimm을 써라 Serial.println(Bright); //시리얼모니터에 Bright를 써라 if (currentMillis - D_previousMillis > D_Interval) { D_previousMillis = currentMillis; Bright += BrightnessFactor; //밝기에 디밍 증감값 1씩 올려라 } if (Bright < 100 || Bright > 254) { BrightnessFactor = -1 * BrightnessFactor; } Bright = constrain(Bright, 99, 254); //변수 밝기값을 최소값99~최대값254 사이의 값으로 한정한다

for (int i = 0; i < NUM_LIGHTS; i++) { dim_color_set(i, Bright); } }

//Blinking void blinking() { Serial.println("blink"); //시리얼모니터에 blink를 써라

for (int i = 0; i < NUM_LIGHTS; i++) { if (currentMillis - B_previousMillis[i] > B_Interval[i]) { //흐른 시간값이 블링크 인터벌 값보다 크면 B_previousMillis[i] = currentMillis; //현재시간을 이전의 블링크 시간에 넣어라 B_state[i] = !B_state[i]; //각 모듈의 블링킹 상태변수의 값의 반대값을 대입하라 } } for (int i = 0; i < NUM_LIGHTS; i++) { if (B_state[i]) { //모듈의 블링킹 상태가 읽히면 color_set(i, colorVal[i]); //가변저항 값에 따라 컬러 셋팅 } else { noColor_set(i); //읽히지 않으면 컬러 셋팅 하지않는 } }

}

//////////////////////////////////////////////////////////////////////////////////////// //core functuation

//color set

void color_set(int index, int colorSenser) { if (startState[index]) { hue[index] = map(colorSenser, 0, 1023, 0, 359); //가변저항 값을 0~359값으로 매핑한 값을 색상값을 지정 getRGB(hue[index], 255, 255, rgb_colors, index); for (int i = 0; i < NUMPIXELS; i++) { pixels[index].setPixelColor(i, pixels[index].Color(rgb_colors[index][0], rgb_colors[index][1], rgb_colors[index][2])); } //픽셀컬러 셋팅을 rgb_colors의 r,g,b으로 설정 } else noColor_set(index); //컬러셋팅 하지않음 }

//////noColor set

void noColor_set(int index) { //컬러셋팅 하지않는 함수 설정 for (int i = 0; i < NUMPIXELS; i++) { pixels[index].setPixelColor(i, pixels[index].Color(0, 0, 0)); } //픽셀컬러 세팅을 0,0,0으로 설정 }

////dimColor set

void dim_color_set(int index, int BC) { if (startState[index]) { hue[index] = map(colorVal[index], 0, 1023, 0, 359); getRGB(hue[index], 255, BC, rgb_colors, index); for (int i = 0; i < NUMPIXELS; i++) { pixels[index].setPixelColor(i, pixels[index].Color(rgb_colors[index][0], rgb_colors[index][1], rgb_colors[index][2])); } } else noColor_set(index); }

Step 6: A Finished Look

Share

    Recommendations

    • First Time Author

      First Time Author
    • Make it Glow Contest 2018

      Make it Glow Contest 2018
    • PCB Contest

      PCB Contest

    3 Discussions

    0
    None
    mindy_010

    1 day ago

    Cool. I hope you show more video clip because it feels so short.

    0
    None
    Hokeypokey123

    1 day ago

    Good. :-) I wanna see that really ! :-3