Я расскажу про свой первый световой прибор под управлением DMX-512.
История началась с того, что мой знакомый Dj отдал мне со школы сканер(stardance).
У него, к моему сожалению вылетели мозги, были они сделаны на микроконтроллере pic.
Я долго думал что с ним сделать, читал форумы и наткнулся на тему Антона Н - Прибор "Поворотная голова" , на этом форуме.
Идея Антона меня заинтересовала. Мой проект собран полностью на его основе, за исключением еще одного канала для вращения чашки с зеркалами.
Сканер работает с тремя шаговыми двигателями: 1)Двигатель панорамы (1 канал dmx); 2)Двигатель тилта (2 канал dmx); 3) Двигатель чашки с зеркалами, именно он вращает "лунный цветок" (3 канал dmx).
Я использовал для двигателей драйвер a4988, мне показались они довольно шумными, лучше поискать что то подороже.
Каждый мотор останавливается по датчику(на фото будут видны) и ходит в своем диапазоне.
Этот диапазон, прошу прощение за тавтологию, настраивается в прошивке, в подпункте двигатель(1,2,3)>Слежение>Получение заданного положения>(NUM_STEPS_MOTOR - 1) / 127) ;
А еще в скетче я настраивал делитель частоты, для настройки моторов (myMotor1.setDivider(5); // делитель частоты) и число шагов (#define NUM_STEPS_MOTOR 806 // число шагов двигателя на оборот).
В качестве мозгов использовал Arduino Pro Mini на Atmega 168. Все паял на макетной платке.
Намотал торик с тремя обмотками для раздельного питания. Для лампы использовал электронный трансформатор, после тестов добавил фильтр от компьютерного блока
питания, чтобы убрать помехи по сети.
Пока что все, если возникнут вопросы - спрашивайте.
Я добавлю свои фото, и с темы "Прибор поворотная голова", если так можно.
От себя скажу, что не стоит заниматься данным делом. Я потратил много времени, но желаемого результата не добился, зато опыт получил.
Если тянет к свету, лучше поискать сканеры/головы на вторичке, с клубов, можно найти реально хорошие приборы, подделать и работать на них.
Вот скетч:
=====================================================================================
Код: Выделить всё
#include <TimerOne.h>
#include <StepDirDriver.h>
#include <DMXSerial.h>
#include <Button.h>
#define NUM_STEPS_MOTOR 806 // число шагов двигателя на оборот
#define DMX_CHANEL_MOTO_1 1 // канал DMX для двигателя 1
#define DMX_CHANEL_MOTO_2 2 // канал DMX для двигателя 2
#define DMX_CHANEL_MOTO_3 3 // канал DMX для двигателя 2
unsigned int currentStep1=0; // текущее положение двигателя
unsigned int setStep1=0; // заданное положение двигателя
int stepsToDo1; // сколько шагов надо сделать
byte mode1=0; // режим: 0 - пауза, 1 - синхронизация датчик закрыт, 2 - синхронизация датчик открыт, 3 - слежение
unsigned int currentStep2=0; // текущее положение двигателя
unsigned int setStep2=0; // заданное положение двигателя
int stepsToDo2; // сколько шагов надо сделать
byte mode2=0; // режим: 0 - пауза, 1 - синхронизация датчик закрыт, 2 - синхронизация датчик открыт, 3 - слежение
unsigned int currentStep3=0; // текущее положение двигателя
unsigned int setStep3=0; // заданное положение двигателя
int stepsToDo3; // сколько шагов надо сделать
byte mode3=0; // режим: 0 - пауза, 1 - синхронизация датчик закрыт, 2 - синхронизация датчик открыт, 3 - слежение
byte timer=0; // таймер
StepDirDriver myMotor1(11, 10, 5); // создаем объект типа StepDirDriver, задаем выводы для сигналов STEP, DIR, ENABLE
StepDirDriver myMotor2(13, 12, 6); // создаем объект типа StepDirDriver, задаем выводы для сигналов STEP, DIR, ENABLE
StepDirDriver myMotor3(2, 3, 9); // создаем объект типа StepDirDriver, задаем выводы для сигналов STEP, DIR, ENABLE
Button sens1 (7, 11); // создание объекта для датчика 1
Button sens2 (8, 13); // создание объекта для датчика 2
Button sens3 (4, 2); // создание объекта для датчика 3
void setup() {
DMXSerial.init(DMXReceiver);
Timer1.initialize(250); // инициализация таймера 1, период 250 мкс
Timer1.attachInterrupt(timerInterrupt, 250); // обработчик прерываний
myMotor1.setMode(0, false); // шаговый режим, без фиксации при остановке
myMotor1.setDivider(5); // делитель частоты 30
myMotor2.setMode(0, false); // шаговый режим, без фиксации при остановке
myMotor2.setDivider(2); // делитель частоты 30
myMotor3.setMode(0, false); // шаговый режим, без фиксации при остановке
myMotor3.setDivider(8); // делитель частоты 30
}
void loop() {
//--------------------------------- двигатель 1 ---------------------------
if( mode1 == 0 ) {
// ожидание фильтрации датчиков
if( timer > 40 ) {
if( sens1.flagPress == true ) mode1=2;
else mode1=1;
}
}
else if( mode1 == 1 ) {
// синхронизация датчик закрыт
myMotor1.step(-10); // по часовой
if( sens1.flagPress == true ) {
myMotor1.step(0);
mode1=3;
}
}
else if( mode1 == 2 ) {
// синхронизация датчик открыт
myMotor1.step(10); // против часовой
if( sens1.flagPress == false ) {
myMotor1.step(0);
mode1=3;
}
}
else if( mode1 == 3 ) {
// слежение
// ------------------------------------ СЛЕЖЕНИЕ
// проверка остановки двигателя
if( myMotor1.readSteps() == 0) {
// двигатель остановился
// получение заданного положения
setStep1 = (unsigned int)((unsigned long)DMXSerial.read(DMX_CHANEL_MOTO_1) * (NUM_STEPS_MOTOR - 1) / 255) ;
// определение сколько шагов надо сделать
stepsToDo1 = currentStep1 - setStep1; // ошибка рассогласования
// if( abs(stepsToDo1) >= (NUM_STEPS_MOTOR / 2) ) {
// if((stepsToDo1) > 0) stepsToDo1 -= NUM_STEPS_MOTOR;
// else stepsToDo1 += NUM_STEPS_MOTOR;
// }
myMotor1.step(stepsToDo1); // запуск двигателя
currentStep1 = setStep1; // перегрузка текущего положения
}
}
else mode1=0;
//--------------------------------- двигатель 2 ---------------------------
if( mode2 == 0 ) {
// ожидание фильтрации датчиков
if( timer > 40 ) {
if( sens2.flagPress == true ) mode2=2;
else mode2=1;
}
}
else if( mode2 == 1 ) {
// синхронизация датчик закрыт
myMotor2.step(-10); // по часовой
if( sens2.flagPress == true ) {
myMotor2.step(0);
mode2=3;
}
}
else if( mode2 == 2 ) {
// синхронизация датчик открыт
myMotor2.step(10); // против часовой
if( sens2.flagPress == false ) {
myMotor2.step(0);
mode2=3;
}
}
else if( mode2 == 3 ) {
// слежение
// ------------------------------------ СЛЕЖЕНИЕ
// проверка остановки двигателя
if( myMotor2.readSteps() == 0) {
// двигатель остановился
// получение заданного положения
setStep2 = (unsigned int)((unsigned long)DMXSerial.read(DMX_CHANEL_MOTO_2) * (NUM_STEPS_MOTOR - 1) / 800) ;
// определение сколько шагов надо сделать
stepsToDo2 = currentStep2 - setStep2; // ошибка рассогласования
// if( abs(stepsToDo2) >= (NUM_STEPS_MOTOR / 2) ) {
// if((stepsToDo2) > 0) stepsToDo2 -= NUM_STEPS_MOTOR;
// else stepsToDo2 += NUM_STEPS_MOTOR;
// }
myMotor2.step(stepsToDo2); // запуск двигателя
currentStep2 = setStep2; // перегрузка текущего положения
}
}
else mode2=0;
//--------------------------------- двигатель 3 ---------------------------
if( mode3 == 0 ) {
// ожидание фильтрации датчиков
if( timer > 40 ) {
if( sens3.flagPress == true ) mode3=2;
else mode3=1;
}
}
else if( mode3 == 1 ) {
// синхронизация датчик закрыт
myMotor3.step(-10); // по часовой
if( sens3.flagPress == true ) {
myMotor3.step(0);
mode3=3;
}
}
else if( mode3 == 2 ) {
// синхронизация датчик открыт
myMotor3.step(10); // против часовой
if( sens3.flagPress == false ) {
myMotor3.step(0);
mode3=3;
}
}
else if( mode3 == 3 ) {
// слежение
// ------------------------------------ СЛЕЖЕНИЕ
// проверка остановки двигателя
if( myMotor3.readSteps() == 0) {
// двигатель остановился
// получение заданного положения
setStep3 = (unsigned int)((unsigned long)DMXSerial.read(DMX_CHANEL_MOTO_3) * (NUM_STEPS_MOTOR - 1) / 255) ;
// определение сколько шагов надо сделать
stepsToDo3 = currentStep3 - setStep3; // ошибка рассогласования
// if( abs(stepsToDo3) >= (NUM_STEPS_MOTOR / 2) ) {
// if((stepsToDo3) > 0) stepsToDo3 -= NUM_STEPS_MOTOR;
// else stepsToDo3 += NUM_STEPS_MOTOR;
// }
myMotor3.step(stepsToDo3); // запуск двигателя
currentStep3 = setStep3; // перегрузка текущего положения
}
}
else mode3=0;
}
//-------------------------------------- обработчик прерывания 250 мкс
void timerInterrupt() {
timer++;
myMotor1.control(); // управвление двигателем
myMotor2.control(); // управвление двигателем
myMotor3.control(); // управвление двигателем
sens1.filterAvarage(); // вызов метода фильтрации по среднему для датчика 1
sens2.filterAvarage(); // вызов метода фильтрации по среднему для датчика 2
sens3.filterAvarage(); // вызов метода фильтрации по среднему для датчика 3
}
==============================================================================
// программа следящего электропривода без обратной связи
#include <TimerOne.h>
#include <StepDirDriver.h>
#include <DMXSerial.h>
#include <Button.h>
#define NUM_STEPS_MOTOR 400 // число шагов двигателя на оборот
#define DMX_CHANEL_MOTO_1 1 // канал DMX для двигателя 1
#define DMX_CHANEL_MOTO_2 2 // канал DMX для двигателя 2
#define DMX_CHANEL_MOTO_3 3 // канал DMX для двигателя 2
unsigned int currentStep1=0; // текущее положение двигателя
unsigned int setStep1=0; // заданное положение двигателя
int stepsToDo1; // сколько шагов надо сделать
byte mode1=0; // режим: 0 - пауза, 1 - синхронизация датчик закрыт, 2 - синхронизация датчик открыт, 3 - слежение
unsigned int currentStep2=0; // текущее положение двигателя
unsigned int setStep2=0; // заданное положение двигателя
int stepsToDo2; // сколько шагов надо сделать
byte mode2=0; // режим: 0 - пауза, 1 - синхронизация датчик закрыт, 2 - синхронизация датчик открыт, 3 - слежение
unsigned int currentStep3=0; // текущее положение двигателя
unsigned int setStep3=0; // заданное положение двигателя
int stepsToDo3; // сколько шагов надо сделать
byte mode3=0; // режим: 0 - пауза, 1 - синхронизация датчик закрыт, 2 - синхронизация датчик открыт, 3 - слежение
byte timer=0; // таймер
StepDirDriver myMotor1(11, 10, 5); // создаем объект типа StepDirDriver, задаем выводы для сигналов STEP, DIR, ENABLE
StepDirDriver myMotor2(13, 12, 6); // создаем объект типа StepDirDriver, задаем выводы для сигналов STEP, DIR, ENABLE
StepDirDriver myMotor3(2, 3, 9); // создаем объект типа StepDirDriver, задаем выводы для сигналов STEP, DIR, ENABLE
Button sens1 (7, 11); // создание объекта для датчика 1
Button sens2 (8, 13); // создание объекта для датчика 2
Button sens3 (4, 2); // создание объекта для датчика 3
void setup() {
DMXSerial.init(DMXReceiver);
Timer1.initialize(250); // инициализация таймера 1, период 250 мкс
Timer1.attachInterrupt(timerInterrupt, 250); // обработчик прерываний
myMotor1.setMode(1, false); // шаговый режим, без фиксации при остановке
myMotor1.setDivider(3); // делитель частоты 30
myMotor2.setMode(1, false); // шаговый режим, без фиксации при остановке
myMotor2.setDivider(6); // делитель частоты 30
myMotor3.setMode(1, false); // шаговый режим, без фиксации при остановке
myMotor3.setDivider(4); // делитель частоты 30
}
void loop() {
//--------------------------------- двигатель 1 ---------------------------
if( mode1 == 0 ) {
// ожидание фильтрации датчиков
if( timer > 40 ) {
if( sens1.flagPress == true ) mode1=2;
else mode1=1;
}
}
else if( mode1 == 1 ) {
// синхронизация датчик закрыт
myMotor1.step(-10); // по часовой
if( sens1.flagPress == true ) {
myMotor1.step(0);
mode1=3;
}
}
else if( mode1 == 2 ) {
// синхронизация датчик открыт
myMotor1.step(10); // против часовой
if( sens1.flagPress == false ) {
myMotor1.step(0);
mode1=3;
}
}
else if( mode1 == 3 ) {
// слежение
// ------------------------------------ СЛЕЖЕНИЕ
// проверка остановки двигателя
if( myMotor1.readSteps() == 0) {
// двигатель остановился
// получение заданного положения
setStep1 = (unsigned int)((unsigned long)DMXSerial.read(DMX_CHANEL_MOTO_1) * (NUM_STEPS_MOTOR - 1) / 127) ;
// определение сколько шагов надо сделать
stepsToDo1 = currentStep1 - setStep1; // ошибка рассогласования
// if( abs(stepsToDo1) >= (NUM_STEPS_MOTOR / 2) ) {
// if((stepsToDo1) > 0) stepsToDo1 -= NUM_STEPS_MOTOR;
// else stepsToDo1 += NUM_STEPS_MOTOR;
// }
myMotor1.step(stepsToDo1); // запуск двигателя
currentStep1 = setStep1; // перегрузка текущего положения
}
}
else mode1=0;
//--------------------------------- двигатель 2 ---------------------------
if( mode2 == 0 ) {
// ожидание фильтрации датчиков
if( timer > 40 ) {
if( sens2.flagPress == true ) mode2=2;
else mode2=1;
}
}
else if( mode2 == 1 ) {
// синхронизация датчик закрыт
myMotor2.step(-10); // по часовой
if( sens2.flagPress == true ) {
myMotor2.step(0);
mode2=3;
}
}
else if( mode2 == 2 ) {
// синхронизация датчик открыт
myMotor2.step(10); // против часовой
if( sens2.flagPress == false ) {
myMotor2.step(0);
mode2=3;
}
}
else if( mode2 == 3 ) {
// слежение
// ------------------------------------ СЛЕЖЕНИЕ
// проверка остановки двигателя
if( myMotor2.readSteps() == 0) {
// двигатель остановился
// получение заданного положения
setStep2 = (unsigned int)((unsigned long)DMXSerial.read(DMX_CHANEL_MOTO_2) * (NUM_STEPS_MOTOR - 1) / 425) ;
// определение сколько шагов надо сделать
stepsToDo2 = currentStep2 - setStep2; // ошибка рассогласования
// if( abs(stepsToDo2) >= (NUM_STEPS_MOTOR / 2) ) {
// if((stepsToDo2) > 0) stepsToDo2 -= NUM_STEPS_MOTOR;
// else stepsToDo2 += NUM_STEPS_MOTOR;
// }
myMotor2.step(stepsToDo2); // запуск двигателя
currentStep2 = setStep2; // перегрузка текущего положения
}
}
else mode2=0;
//--------------------------------- двигатель 3 ---------------------------
if( mode3 == 0 ) {
// ожидание фильтрации датчиков
if( timer > 40 ) {
if( sens3.flagPress == true ) mode3=2;
else mode3=1;
}
}
else if( mode3 == 1 ) {
// синхронизация датчик закрыт
myMotor3.step(-10); // по часовой
if( sens3.flagPress == true ) {
myMotor3.step(0);
mode3=3;
}
}
else if( mode3 == 2 ) {
// синхронизация датчик открыт
myMotor3.step(10); // против часовой
if( sens3.flagPress == false ) {
myMotor3.step(0);
mode3=3;
}
}
else if( mode3 == 3 ) {
// слежение
// ------------------------------------ СЛЕЖЕНИЕ
// проверка остановки двигателя
if( myMotor3.readSteps() == 0) {
// двигатель остановился
// получение заданного положения
setStep3 = (unsigned int)((unsigned long)DMXSerial.read(DMX_CHANEL_MOTO_3) * (NUM_STEPS_MOTOR - 1) / 130) ;
// определение сколько шагов надо сделать
stepsToDo3 = currentStep3 - setStep3; // ошибка рассогласования
// if( abs(stepsToDo3) >= (NUM_STEPS_MOTOR / 2) ) {
// if((stepsToDo3) > 0) stepsToDo3 -= NUM_STEPS_MOTOR;
// else stepsToDo3 += NUM_STEPS_MOTOR;
// }
myMotor3.step(stepsToDo3); // запуск двигателя
currentStep3 = setStep3; // перегрузка текущего положения
}
}
else mode3=0;
}
//-------------------------------------- обработчик прерывания 250 мкс
void timerInterrupt() {
timer++;
myMotor1.control(); // управвление двигателем
myMotor2.control(); // управвление двигателем
myMotor3.control(); // управвление двигателем
sens1.filterAvarage(); // вызов метода фильтрации по среднему для датчика 1
sens2.filterAvarage(); // вызов метода фильтрации по среднему для датчика 2
sens3.filterAvarage(); // вызов метода фильтрации по среднему для датчика 3
}
===================================================================================