안녕하세요, 이미 집 안에 DMX 제어 조명을 많이 설치해뒀는데 바깥에도 설치하고 싶었습니다. 근데 RGB DMX 조명이 꽤 비싸더군요(개당 약 200-300유로). 그래서 대안을 찾아봤습니다.
찾아낸 게 IR 리모컨으로 제어하는 아주 저렴한 RGB LED 플러드라이트입니다. 10W RGB 기준 약 8유로/10달러 정도 합니다.
이걸 DMX를 이해하도록 개조하기만 하면 됩니다.
비용과 PCB 공간을 아끼기 위해 5개 플러드라이트 모두 별도 박스에 있는 아두이노 하나만 두뇌로 쓰게 했습니다. 각 라이트엔 3채널 PWM 트리거드 정전류 소스 PCB와 D-Sub 9핀 커넥터 케이블이 있습니다. 이 PCB는 라이트 바닥의 작은 수납함에 딱 들어맞습니다. LED 각 채널은 350mA로 설정했습니다.
모든 5개 라이트가 아두이노와 무선 DMX 수신기가 있는 중앙 박스에 연결됩니다.
박스 내부 구성:
12V 3.5A 파워 서플라이
12V-5V 휴대폰 충전기 모듈
DMX(RS485) 컨버터용 자체 PCB 위의 아두이노 나노
아다프루트 16채널 PWM 익스텐션 (I2C)
무선 DMX 수신기
D-Sub 리본 케이블용 분배 PCB
방수를 위한 대량의 글루건 접착제
폭우 속에서도 3주째 버티고 있어 박스와 실링이 방수되는 것 같습니다.
나노를 올린 PCB는 제 모든 DMX 프로젝트에 범용으로 쓰는 건데, DMX 버스 신호를 아두이노로 변환해주고 I2C 버스나 6개 PWM 채널(MOSFET BUZ11 포함) 브레이크아웃 역할도 합니다. 이 MOSFET 버전으로 실내 조명도 DMX로 업그레이드했었습니다.
이렇게 해서 5개 개별 제어 램프(유리 난간용)가 완성됐고, PC/휴대폰으로 무선 DMX 제어합니다.
다운로드 섹션에 PCB 이글 파일, 복붙 아두이노 스케치, PC 제어 소프트웨어 Freestyler용 픽스처 정의 파일이 있습니다.
DMX 주소는 시작 주소 200으로 하드코딩되어 있고, 5개 × 3채널(R, G, B) 구성으로 디머 채널은 없습니다.
아두이노 스케치에서 빨간 채널 값 조정이 필요했는데, 빨간 LED가 녹색/파랑보다 훨씬 밝아 순수한 흰색이 안 나왔기 때문입니다.
대신 아두이노 IDE 터미널에서 직접 RGB 값 설정하는 테스트/디버그용 스케치도 하나 있습니다.
총 5개 램프 비용 약 110유로, 모든 부품(라이트 제외)은 Reichelt.de에서, 모든 PCB는 platinenbelichter.de에서 제작(강력 추천!).
자유롭게 수정하고 최적화하세요!
안녕,
세바스찬
코드
DMX 버전
USB 입력 버전 (디버그용)
Freestyler용 픽스처 정의
DMX 버전 (아두이노)
5개 × 3채널 RGB 라이트 제어 프로그램
// 15 PWM on 5 RGBs LEDs / DMX Start-Address 200 / 5x 3channel R G B
#include <Conceptinetics.h>
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
#define DMX_SLAVE_CHANNELS 15
DMX_Slave dmx_slave ( DMX_SLAVE_CHANNELS );
int channel[16];
int channelOut[16];
int value[16];
int ch = 0;
int red = 0;
int green = 0;
int blue = 0;
void setup() {
Wire.begin();
pwm.begin();
pwm.setPWMFreq(120); // 최대 PWM 주파수
#ifdef TWBR
uint8_t twbrbackup = TWBR;
TWBR = 12; // 400KHz로 업그레이드!
#endif
// DMX 설정
dmx_slave.enable ();
dmx_slave.setStartAddress (200);
// 모든 PWM 하이로 -> LED 끄기
for (int i = 0; i <= 14; i++) {
pwm.setPWM(i, 4096, 0 );
}
}
void loop() {
// DMX 입력
for (int j = 0; j <= 14; j++) {
channel[j] = dmx_slave.getChannelValue (j+1);
}
// 색상 미세 조정 (빨간 LED가 더 밝아 보정 필요)
channelOut[0] = map(channel[0], 0, 255, 0, 1400); // 빨강 1 감소
channelOut[1] = map(channel[1], 0, 255, 0, 4095);
channelOut[2] = map(channel[2], 0, 255, 0, 4095);
channelOut[3] = map(channel[3], 0, 255, 0, 1400); // 빨강 2 감소
channelOut[4] = map(channel[4], 0, 255, 0, 4095);
channelOut[5] = map(channel[5], 0, 255, 0, 4095);
channelOut[6] = map(channel[6], 0, 255, 0, 1400); // 빨강 3 감소
channelOut[7] = map(channel[7], 0, 255, 0, 4095);
channelOut[8] = map(channel[8], 0, 255, 0, 4095);
channelOut[9] = map(channel[9], 0, 255, 0, 1400); // 빨강 4 감소
channelOut[10] = map(channel[10], 0, 255, 0, 4095);
channelOut[11] = map(channel[11], 0, 255, 0, 4095);
channelOut[12] = map(channel[12], 0, 255, 0, 1400); // 빨강 5 감소
channelOut[13] = map(channel[13], 0, 255, 0, 4095);
channelOut[14] = map(channel[14], 0, 255, 0, 4095);
// 값 할당
for (int i = 0; i <= 14; i++) {
if (channelOut[i] == 0) {
pwm.setPWM(i, 4096, 0 );
} else {
pwm.setPWM(i, 0, 4095 - channelOut[i] );
}
}
}
USB 입력 버전 (아두이노)
램프 번호와 R,G,B 값을 직접 입력하는 디버그 버전
// 15 PWM on 5 RGBs LEDs
#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();
int channel[15];
int channelOut[15];
int value[15];
int ch = 0;
int red = 0;
int green = 0;
int blue = 0;
void setup() {
Wire.begin();
Serial.begin(9600);
Serial.println("Waiting for input: LED, R, G, B, [each 0-255]");
pwm.begin();
pwm.setPWMFreq(120);
#ifdef TWBR
uint8_t twbrbackup = TWBR;
TWBR = 12;
#endif
// 모든 PWM 하이로 -> LED 끄기
for (int i = 0; i <= 14; i++) {
pwm.setPWM(i, 4096, 0 );
}
}
void loop() {
// 입력 받기
while (Serial.available() > 0) {
ch = Serial.parseInt();
red = Serial.parseInt();
green = Serial.parseInt();
blue = Serial.parseInt();
if (Serial.read() == '\n') {}
ch = constrain(ch, 0, 4);
red = constrain(red, 0, 255);
green = constrain(green, 0, 255);
blue = constrain(blue, 0, 255);
// 값 출력
Serial.print("new values:");
Serial.print(" LED=");
Serial.print(ch, DEC);
Serial.print(" R=");
Serial.print(red, DEC);
Serial.print(", G=");
Serial.print(green, DEC);
Serial.print(", B=");
Serial.println(blue, DEC);
}
switch (ch) {
case 0: channel[0] = red; channel[1] = green; channel[2] = blue; break;
case 1: channel[3] = red; channel[4] = green; channel[5] = blue; break;
case 2: channel[6] = red; channel[7] = green; channel[8] = blue; break;
case 3: channel[9] = red; channel[10] = green; channel[11] = blue; break;
case 4: channel[12] = red; channel[13] = green; channel[14] = blue; break;
}
// 색상 미세 조정 (위와 동일)
channelOut[0] = map(channel[0], 0, 255, 0, 1400);
channelOut[1] = map(channel[1], 0, 255, 0, 4095);
channelOut[2] = map(channel[2], 0, 255, 0, 4095);
channelOut[3] = map(channel[3], 0, 255, 0, 1400);
channelOut[4] = map(channel[4], 0, 255, 0, 4095);
channelOut[5] = map(channel[5], 0, 255, 0, 4095);
channelOut[6] = map(channel[6], 0, 255, 0, 1400);
channelOut[7] = map(channel[7], 0, 255, 0, 4095);
channelOut[8] = map(channel[8], 0, 255, 0, 4095);
channelOut[9] = map(channel[9], 0, 255, 0, 1400);
channelOut[10] = map(channel[10], 0, 255, 0, 4095);
channelOut[11] = map(channel[11], 0, 255, 0, 4095);
channelOut[12] = map(channel[12], 0, 255, 0, 1400);
channelOut[13] = map(channel[13], 0, 255, 0, 4095);
channelOut[14] = map(channel[14], 0, 255, 0, 4095);
// 값 할당
for (int i = 0; i <= 14; i++) {
if (channelOut[i] == 0) {
pwm.setPWM(i, 4096, 0 );
} else {
pwm.setPWM(i, 0, 4095 - channelOut[i] );
}
}
}