Для танцевальной новогодней вечеринки решил сделать простую лазерную установку, которая бы в такт музыке что-нибудь демонстрировала. Под рукой была лазерная указка с набором сменных вращающихся колпачков, которые позволяли получать симпатичные эффекты на потолке. Добавив пару сервоприводов и arduino mini pro — получил искомое.


Схема очень простая (один ключ, управляющий лазерной указкой; пара кремниевых диодов, для понижения напряжения для указки; резистор для электретного микрофона и готовый модуль DC-DC преобразователя напряжения от аккумулятора в пять вольт), выполнил на отрезке макетной платы.

Микрофон при таком простейшем включении — имеет довольно низкую чувствительность, так что устройство нужно ставить достаточно близко к колонкам.


Надо заметить, что несмотря на наличие ключа для управления лазерной указкой — он у меня фактически не используется (всегда включен), так что можно просто выкинуть. Ну или добавить какое-нибудь моргание, если хочется.

Теоретически, гораздо лучше было бы использовать двигатель с редуктором для вращения колпачка (чтобы избежать заметного дрожания), но с сервоприводом получилось проще (напечатал пару шестеренок на принтере и все).

Сервоприводы — Turnigy TGY-R5180MG (180 градусов, для вращения колпачка) и какая-то старая 9 граммовая серва (для вращения самого устройства). Подставка — треножник от вентилятора, которые hobbyking продавала как-то за копейки.

Видео работы:





Скетч:

#include <Servo.h>
// yaw servo - PWM
#define SERVO_YAW 5
// roll servo - PWM
#define SERVO_ROLL 6
// Laser pin - PWM or DO
#define LASER 9

// Microphone input - A0
#define MIC A0

// Yaw servo period (in ms)
#define YAW_PERIOD 40

// Roll servo period (in ms)
#define ROLL_PERIOD 100

// MIN value for yaw servo
#define MIN_YAW 40
// MAX value for yaw servo
#define MAX_YAW 130
// MIN value for roll servo
#define MIN_ROLL 10
// MAX value for roll servo
#define MAX_ROLL 150

Servo yaw_servo;
Servo roll_servo;

// Current position and direction for servos
int16_t roll_pos = MIN_ROLL;
int8_t roll_dir = 1;
int16_t yaw_pos = MIN_YAW;
int8_t yaw_dir = 1;

// Sound peak detected
boolean flag_sound = false;

// Internal sound volume average stuff
int16_t arr_vol[32];
int8_t arr_pos = 0;

unsigned long last_sound = 0;

// Detect sound volume peaks
void check_sound() {
  int16_t volume = analogRead(MIC);
  int i;
  int32_t sum;
  int16_t average;

  // Calculate average from last reads
  arr_vol[arr_pos] = volume;
  arr_pos++;
  if (arr_pos > (sizeof(arr_vol) / sizeof(arr_vol[0])))
    arr_pos = 0;
  sum = 0;
  for (i = 0; i < (sizeof(arr_vol) / sizeof(arr_vol[0])); i++)
    sum += arr_vol[i];
  average = sum / (sizeof(arr_vol) / sizeof(arr_vol[0]));

  if (flag_sound && ((millis() - last_sound) > 200))
    flag_sound = false;
  if ((millis() - last_sound) < 300)
    return;
  if (volume > (average + 4)) {
    flag_sound = true;
    last_sound = millis();
  }
} // void check_sound()

unsigned long last_yaw = 0;

// Rotate yaw servo
void rotate_yaw() {
  if ((millis() - last_yaw) < YAW_PERIOD)
    return;
  last_yaw = millis();
  yaw_pos += yaw_dir;
  // Change rotate direction when reached limit
  if ((yaw_pos >= MAX_YAW) || (yaw_pos <= MIN_YAW))
    yaw_dir = -yaw_dir;
  yaw_servo.write(yaw_pos);
} // void rotate_yaw()


unsigned long last_roll = 0;

// Rotate roll servo
void rotate_roll() {
  if ((millis() - last_roll) < ROLL_PERIOD)
    return;
  last_roll = millis();
  roll_pos += roll_dir;

  // Rotate faster when we detect sound peaks
  if (flag_sound) {
    roll_pos += (8 * roll_dir);
    if (roll_pos < MIN_ROLL)
      roll_pos = MIN_ROLL;
    if (roll_pos > MAX_ROLL)
      roll_pos = MAX_ROLL;
  }
  
  // Change rotate direction when reached limit
  if ((roll_pos >= MAX_ROLL) || (roll_pos <= MIN_ROLL))
    roll_dir = -roll_dir;
  roll_servo.write(roll_pos);
} // void rotate_roll()

void setup() {
  // put your setup code here, to run once:
  pinMode(LASER, OUTPUT);
  digitalWrite(LASER, HIGH);

  yaw_servo.attach(SERVO_YAW);
  yaw_servo.write(yaw_pos);
  roll_servo.attach(SERVO_ROLL);
  roll_servo.write(roll_pos);
  
  Serial.begin(115200);
  delay(300);
} // void setup()

void loop() {
  // put your main code here, to run repeatedly:

  check_sound();
  rotate_yaw();
  rotate_roll();

  delay(10);
} // void loop()

Спасибо за внимание!
Поделиться с друзьями
-->

Комментарии (23)


  1. Rumlin
    28.12.2016 08:16

    резковато движется. Думаю два лазера давали бы интереснее эффекты


    1. Mistx
      28.12.2016 11:47

      А если три, да еще и разных цветов, то вообще дисплей получится


    1. vasimv
      28.12.2016 13:36

      Скорость движения можно уменьшать (повышая задержки YAW_PERIOD/ROLL_PERIOD), хотя там есть выраженная ступенчатость из-за ограничений ардуиновской библиотеки Servo (шаг в один градус только).


  1. madf
    28.12.2016 12:09
    +1

    Ничего непонятно, расскажите нормально про механику (схемы и скейчи — вторичны).


    1. vasimv
      28.12.2016 13:25

      Да, наверное стоило бы более подробно разобрать. Там один сервопривод вращает шестеренку, которая вращает другую шестеренку на колпачке указки. На валу второго сервопривода прикреплена платформа, на которой закреплены упомянутые элементы.


      1. madf
        28.12.2016 14:03

        на фото точно ничего не разобрать


        1. vasimv
          28.12.2016 14:05

          Я добавил второе видео, где видно как что крутится.


          1. madf
            28.12.2016 15:25

            спасибо
            рисунок выцарапан на стекле просто?


            1. vasimv
              28.12.2016 19:48

              В колпачке — стекляшки и линзы какие-то. Китайцы продают такие указки, с наборами колпачков для разных рисунков.


  1. sp01
    28.12.2016 19:46

    Можно сделать колесо-кассету со стеклами и вращать его. Будет смена картинки.


  1. dudedimon
    28.12.2016 19:46
    +1

    лет 5 назад делал что-то похожее но без ардуинки


    1. vasimv
      28.12.2016 19:54

      Красиво, но тут механика точная нужна, не для меня. :)


      1. dudedimon
        28.12.2016 20:39

        Все очень просто!!! Все из хлама. Лазер из DVD RW привода, линза из лазерной указки, 3 моторчика из CD и DVD приводов, три круглых зеркала из точилок купленных в кацтоварах, маленькая схема управления двигателями и… и все


    1. 4ebriking
      28.12.2016 21:09

      тоже делал, только лет 20 назад, естесственно тоже без ардуины. Тупо до невозможности — два зеркальца, два моторчика и указка.
      http://impetus.obninsk.ru/pricol/prazdn.html
      тоже — «на соплях».
      всё хотел лазер зелёный помощнее и в небо на облака, но пока тормозил — лазеры в небо запретили.
      imageimage


      1. dudedimon
        28.12.2016 21:36
        +1

        Я с начала тоже так собрал. Потом прицепил третий моторчик и схему управления моторами по аналогии с цветомузыкой, только с моторами вместо лампочек.image


    1. unxed
      31.12.2016 05:58


  1. crasheg
    28.12.2016 23:59

    Для повышения точности управления сервоприводом можно использовать полушаговый режим (выше токи, выше разрешение), самому набросать функцию шагания не так тяжело.
    image


    1. vasimv
      29.12.2016 00:01

      Это сервы для моделей, с управлением PWM, там к мотору не подкопаться. На самом деле можно ардуину заставить более точные импульсы выдавать, точность раза в четыре возрастет.


      1. vasimv
        29.12.2016 01:14
        +1

        Сделать оказалось проще чем написать, заменил везде write на writeMicroseconds, уменьшил задержки в несколько раз и минимум/максимум на микросекунды, оно двигаться гораздо плавнее стало (не идеально все равно).


        1. crasheg
          05.01.2017 21:19

          Нет там PWM, вместо включения A-B-C-D включается A-AB-B-BC-C-CD-D-DA-A, прямо вручную через digitalWrite и какой-нибудь ULN2004


          1. crasheg
            05.01.2017 21:23

            image


  1. Psychosynthesis
    29.12.2016 01:03

    У вас микрофон как-то странно подключен.

    Включение электретного микрофона. Вам надо было сигнал через кондёр снимать.


    1. vasimv
      29.12.2016 01:22

      У меня там постоянная составляющая все равно отфильтровывается процедурой вычисления среднего уровня, так что лишняя деталь. :)