Пиксельная подсветка просто и быстро

от автора

Ролики с демонстрацией пиксельной подсветки выглядят довольно эффектно — куча разноцветных всплохов, динамичные отблески смотрятся просто замечательно и выглядят более подвижными по сравнению с другими типами подобной подсветки.
Желание поработать с управляемыми огоньками с помощью arduino побудили меня соорудить такую систему. Как оказалось, это довольно простое мероприятие, на которое в сумме было потрачено всего несколько часов (собственно, само сооружение — 10 минут, остальное — софт). Детали процесса сборки и программирования я и изложу в этой статье. Софт, выводы и демо прилагаются.

Аппаратная часть

Для такой подстветки нам понадобятся следующие предметы и устройства:

  • Светодиодная лента на микросхемах WS2801 (с индивидуальным управлением каждым пикселем) нужной длины. Выглядит эта лента приблизительно таким образом:

    Лучше покупать ленту в силиконовой оболочке. Я покупал на ebay, можно попробовать купить напрямую у китайцев, будет дешевле раза в полтора. Длина ленты должна быть достаточной, чтобы обернуть её по периметру вокруг монитора или телевизора.
  • Arduino nano (или один из многочисленных клонов) — например, вот это. Подойдёт и не nano, нужно будет лишь правильно подключить.
  • Провода, называемые DuPont — не знаю, как они называются по-русски, выглядят вот так:

    Эти провода нужны для припаивания к ленте и подключения к ардуино. Нужно всего 2шт — так как они обжаты с двух сторон, разрезав пополам получим нужные нам 4 провода с разъемами.
  • Блок питания 5V + разъем питания, подходящий к этому блоку — и то, и другое в обилии продается как в радиомагазинах, так и на ebay, любых цветов, размеров и исполнений.
    Лента потребляет около 2A / метр в максимально ярком режиме. В повседневной работе 2 метра ленты питаются от БП 3A без каких-либо проблем.
  • Паяльник (любой, в разумных пределах), паяльные принадлежности, нож для зачистки проводов, изолента/термоусадка по вкусу.

Схема (если это гордое слово подходит для соединения двух изделий четырьмя проводами) приведена на рисунке:

Процесс сборки прост до безобразия. Детально описывать его нет смысла (по этой же причине нет фотографий готового «изделия» — ардуин с четырьмя проводами в интернете полно).

  1. Припаять всё, как показано на схеме.
  2. Присоединить провода к arduino, саму ардуинку соединить с PC, подключить блок питания.
  3. Залить в ардуино скетч (см. ниже), запустить исполняемый файл на компьютере (ссылки на софт также см. ниже), установить в программе нужный порт COM.
    Если вы пользуетесь Windows Vista/7 — нужно обязательно отключить Aero. Иначе скорость работы просто плачевная, какого-то решения проблемы низкой скорости захвата экрана при включенном Aero, как я понял, не существует.
  4. Убедиться, что всё работает, выключить.
    Следует упомянуть, что работает софт в 32-битном режиме only. Это можно легко поправить, но большого смысла, на мой взгляд, в такой правке нет.
  5. Прикрепить ленту на монитор. Пустить ленту нужно от левого нижнего угла по периметру по часовой стрелке (ЛН->ЛВ->ПВ->ПН->ЛН). Разрезать ничего не нужно, лента хорошо гнется практически в любом месте, так что проблем быть не должно. Для закрепления ленты я использовал двухсторонний скотч — лента очень легкая и этого более чем достаточно.

На этом сборка закончена. Остаётся посчитать и задать количество пикселей по вертикали и горизонтали, и можно смотреть ролики, играть, etc. и радоваться.

Программная часть

Программная часть состоит из двух компонентов:

  • Скетч для Arduino;
  • Программа управления для PC.

Скетч для Arduino

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

/*** ARDUINO CODE FOR PIXEL LIGHT ***/ #include <SPI.h> #include <SmallUart.h>  unsigned long lastTime;  // Time strip was updated last time const unsigned long fadeTimeout = 3000;  //////////////////////////////////////////////////////////// // void setup() {   UART_Init(115200);     SPI.begin();   SPI.setBitOrder(MSBFIRST);   SPI.setDataMode(SPI_MODE0);   SPI.setClockDivider(SPI_CLOCK_DIV8);   blackoutAll();   delay(1);   lastTime = millis(); }  //////////////////////////////////////////////////////////// // void loop() {   uint8_t data;    UART_SendByte( 'R' ); // Byte "We're ready"   bool valid = false;   data = uartRead( valid );   if ( valid ) {     uint16_t pix_num = data * 3; // Total following bytes     for( uint16_t i=0; i < pix_num; i++ ) {       data = uartRead( valid );       if ( !valid )         break;       SPI.transfer( data ); // Transfer byte to SPI     }     lastTime = millis();   }      if ( millis() - lastTime > fadeTimeout )     blackoutAll(); }  //////////////////////////////////////////////////////////// // Turn off all possible 256 leds void blackoutAll() {   for ( int16_t i = 0; i < 768; i++ )     SPI.transfer( 0 ); //погасить все пикселы ленты }  //////////////////////////////////////////////////////////// // Read byte with timeout unsigned char uartRead( bool& valid ) {   uint8_t res = 0;   valid = false;   for ( uint8_t i = 0; i < 255; ++i ) { // Max timeout 256*10     if( UART_ReadByte( res ) ) {       valid = true;       break;     }     delayMicroseconds(10);   }    return res; } 

Тут всё предельно просто:

  1. Посылаем сигнал, что мы готовы принять данные о подсветке;
  2. В течение небольшого промежутка времени ожидаем данные;
  3. Если данные пришли, то первый байт из этих данных — число диодов, которые обслуживаются. Умножаем на 3 (RGB) для того, чтобы узнать количество последующих байт;
  4. Переправляем принимаемые данные в ленту;
  5. Обновляем метку времени о последнем обновлении ленты (это нужно для тайм-аута и гашения всех пикселей ленты).
Программа для PC

Вроде бы есть готовые решения для этого, но то, что я видел, мне не понравилось категорически, и вообще это неспортивно, зря что ли ардуино используется. Поэтому, пожевывая бутерброд, левой ногой была написана программа для захвата областей экрана, обработки их и передачи нужных данных в ленту. Вся программа с потрохами доступна на гитхабе по адресу github.com/sergrt/pixie (за код не пинайте).
Используется Qt 5.0.1 — интереса ради, никаких особенных вещей, присущих именно этой версии, не задействовано, так что вполне хорошо заработает и на 4. Поскольку большую часть своих развлечений я проделываю под Windows, проект сделан под неё — Visual Studio 2012, захват GDI или DirectX. Я честно пытался генерировать .pro файлы для Qt Creator, но этот процесс страшно глючит с новым VS Qt Add-in, в итоге сходу эти файлы не заработали, разбираться не стал.

Настройки программы

Основная настройка — это указание количества светодиодов по вертикали и горизонтали, а также задание размеров захвативаемых областей. В мои 22" поместилось 10 шт по вертикали и 17 по горизонтали:

Ограничение частоты кадров разумно установить около 30. Значение «0» используется для работы с максимально возможной скоростью.

Также нужно правильно указать порт для обмена с Arduino и скорость обмена. Скорость в скетче по умолчанию 115200:

Для настройки яркости, порога срабатывания и ограничителя сделана отдельная вкладка «Обработка». Параметры, там представленные, регулируются в реальном времени:

Для удобства работы с программой можно настроить на автозапуск захвата при старте, а также запускать свернутой в область уведомлений.

Немного про внутренности софта для интересующихся

Основная идея состоит в запуске потока, хватающего области по заданному механизму, с подстраиваемым fps, и передающий эти области на обработку и последующую передачу ленте. Области захватываются в соответствии с настройками (кто бы мог подумать), цвет пикселя определяется простым средним по трем каналам RGB соответствующей области экрана. Опционально можно включить (директивами препроцессора) преобразование в Lab и усреднение его силами, но этот кусок кода не оптимизирован никак (взят как есть с просторов интернета), тормозит, поэтому по умолчанию выключен. Более того, каких-то особенных преимуществ Lab не заметно в контексте данной задачи, так что это не повод печалиться.
Обработка областей осуществляется по вертикалям и горизонталям, а на ленту отсылается последовательность цветов, начиная с левого нижнего угла и далее по периметру по часовой стрелке (так, как мы наматывали ленту на монитор при сборке).
Захват DirectX по скорости примерно равен захвату с GDI, при том, что в первом случае захватывается экран целиком, а во втором — только нужные куски. Вероятно, тут есть запас по оптимизации.
Обильное использование memcpy связано в первую очередь со скоростью работы — все остальные методы показали себя медленнее в той или иной степени.

Выводы и впечатления

Запас яркости у ленты просто огромный, что хорошо — можно пользоваться даже при наличии других источников света. В полной темноте лучше подвигать бегунками и сделать помягче. Сама лента вполне может служить самостоятельным источником освещения, нужно лишь переделать скетч.
Полагаю, немалое значение имеет диагональ монитора/телевизора. Чем больше — тем лучше.
Также следует устанавливать экран так, чтобы поблизости не было поверхностей, от которых отражаются светодиоды (в моём случае это боковые поверхности колонок) — это не особо критично, но лучше, чтобы резко выделяющихся пикселей не было видно совсем — так как между ними изрядное расстояние, это не лучшим образом влияет на картинку.

Что понравилось:
Просмотр видео и игры с такой подсветкой субъективно разгружают глаза — пропадает жесткий фокус на картинке монитора. Ощущение усталости глаз наступает позже, если не переусердствовать с яркостью. Смотреть видео как минимум необычно, для полноты эффекта лучше делать это с некоторого расстояния.

Что не понравилось:
К самой системе подсветки как таковой особенных претензий нет, но, как уже говорилось, для полноты удовольствия нужно правильное окружение — отстутсвие бликующих поверхностей, равномерный цветовой фон за экраном, etc. В процессе эксплуатации выяснилось, что дизайнерские изыски моего монитора несколько мешают нормальной работе ленты — передняя панель выполнена из прозрачного пластика и выступает над задней крышкой по всему периметру на несколько миллиметров, особенно выдаваясь в нижней части. Поэтому несмотря на то, что лента закреплена относительно далеко, на гранях этой панели видны отдельные светодиоды. Полагаю, мало кто с таким столкнется, но всё же пусть информация будет доступна заранее.

Ниже — ролик, как это выглядит в динамике. Оператор приносит свои извинения за заваленный горизонт.

Ссылки

Проект на гитхабе — github.com/sergrt/pixie
Архив с исполняемым файлом — rghost.net/43638571

ссылка на оригинал статьи http://habrahabr.ru/post/168657/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *