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

Процесс сборки прост до безобразия. Детально описывать его нет смысла (по этой же причине нет фотографий готового «изделия» — ардуин с четырьмя проводами в интернете полно).
На этом сборка закончена. Остаётся посчитать и задать количество пикселей по вертикали и горизонтали, и можно смотреть ролики, играть, etc. и радоваться.
Программная часть состоит из двух компонентов:
В ардуино нужно залить код, приведенный ниже. Используется библиотека SmallUART (которая, впрочем, ничего особенно выдающегося не делает, при желании можно обойтись стандартными средствами).
Тут всё предельно просто:
Вроде бы есть готовые решения для этого, но то, что я видел, мне не понравилось категорически, и вообще это неспортивно, зря что ли ардуино используется. Поэтому, пожевывая бутерброд, левой ногой была написана программа для захвата областей экрана, обработки их и передачи нужных данных в ленту. Вся программа с потрохами доступна на гитхабе по адресу github.com/sergrt/pixie (за код не пинайте).
Используется Qt 5.0.1 —интереса ради, никаких особенных вещей, присущих именно этой версии, не задействовано, так что вполне хорошо заработает и на 4 последние правки сделаны с использованием новых классов, так что теперь с версией 4 исходный код несовместим. Поскольку большую часть своих развлечений я проделываю под Windows, проект сделан под неё — Visual Studio 2012, захват GDI или DirectX. Я честно пытался генерировать .pro файлы для Qt Creator, но этот процесс страшно глючит с новым VS Qt Add-in, в итоге сходу эти файлы не заработали, разбираться не стал. Но всё можно без проблем скомпилировать под linux, см. UPD #3.
Основная настройка — это указание количества светодиодов по вертикали и горизонтали, а также задание размеров захвативаемых областей. В мои 22" поместилось 10 шт по вертикали и 17 по горизонтали:

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

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

Для удобства работы с программой можно настроить на автозапуск захвата при старте, а также запускать свернутой в область уведомлений.
Основная идея состоит в запуске потока, хватающего области по заданному механизму, с подстраиваемым fps, и передающий эти области на обработку и последующую передачу ленте. Области захватываются в соответствии с настройками (кто бы мог подумать), цвет пикселя определяется простым средним по трем каналам RGB соответствующей области экрана. Опционально можно включить (директивами препроцессора) преобразование в Lab и усреднение его силами, но этот кусок кода не оптимизирован никак (взят как есть с просторов интернета), тормозит, поэтому по умолчанию выключен. Более того, каких-то особенных преимуществ Lab не заметно в контексте данной задачи, так что это не повод печалиться.
Обработка областей осуществляется по вертикалям и горизонталям, а на ленту отсылается последовательность цветов, начиная с левого нижнего угла и далее по периметру по часовой стрелке (так, как мы наматывали ленту на монитор при сборке).
Захват DirectX по скорости примерно равен захвату с GDI, при том, что в первом случае захватывается экран целиком, а во втором — только нужные куски. Вероятно, тут есть запас по оптимизации.
Обильное использование memcpy связано в первую очередь со скоростью работы — все остальные методы показали себя медленнее в той или иной степени.
Запас яркости у ленты просто огромный, что хорошо — можно пользоваться даже при наличии других источников света. В полной темноте лучше подвигать бегунками и сделать помягче. Сама лента вполне может служить самостоятельным источником освещения, нужно лишь переделать скетч.
Полагаю, немалое значение имеет диагональ монитора/телевизора. Чем больше — тем лучше.
Также следует устанавливать экран так, чтобы поблизости не было поверхностей, от которых отражаются светодиоды (в моём случае это боковые поверхности колонок) — это не особо критично, но лучше, чтобы резко выделяющихся пикселей не было видно совсем — так как между ними изрядное расстояние, это не лучшим образом влияет на картинку.
Что понравилось:
Просмотр видео и игры с такой подсветкой субъективно разгружают глаза — пропадает жесткий фокус на картинке монитора. Ощущение усталости глаз наступает позже, если не переусердствовать с яркостью. Смотреть видео как минимум необычно, для полноты эффекта лучше делать это с некоторого расстояния.
Что не понравилось:
К самой системе подсветки как таковой особенных претензий нет, но, как уже говорилось, для полноты удовольствия нужно правильное окружение — отстутсвие бликующих поверхностей, равномерный цветовой фон за экраном, etc. В процессе эксплуатации выяснилось, что дизайнерские изыски моего монитора несколько мешают нормальной работе ленты — передняя панель выполнена из прозрачного пластика и выступает над задней крышкой по всему периметру на несколько миллиметров, особенно выдаваясь в нижней части. Поэтому несмотря на то, что лента закреплена относительно далеко, на гранях этой панели видны отдельные светодиоды. Полагаю, мало кто с таким столкнется, но всё же пусть информация будет доступна заранее.
Ниже — ролик, как это выглядит в динамике. Оператор приносит свои извинения за заваленный горизонт.
P. S. Дабы соблюсти приличия, привожу ссылку на отправную точку, откуда я начинал — compcar.ru/forum/showthread.php?t=9462
UPD #1 На гитхабе обновилось ПО (включая исполняемый файл) — добавлена возможность группировать светодиоды для смягчения эффекта при просмотре не особенно динамичны фильмов.
UPD #2 Добавил поддержку захвата экрана силами Qt (при помощи QScreen), так что теперь можно строить кроссплатформенное приложение. Наличие желающих помочь потестировать приветствуется.
UPD #3 Благодаря помощи eugenis (https://github.com/eugenis) появился полноценный файл проекта pro, исправлены неточности для правильной компиляции под linux, немного оптимизирован код. Все эти радости доступны на гитхабе.

Желание поработать с управляемыми огоньками с помощью arduino побудили меня соорудить такую систему. Как оказалось, это довольно простое мероприятие, на которое в сумме было потрачено всего несколько часов (собственно, само сооружение — 10 минут, остальное — софт). Детали процесса сборки и программирования я и изложу в этой статье. Софт, выводы и демо прилагаются.
Аппаратная часть
Для такой подсветки нам понадобятся следующие предметы и устройства:
- Светодиодная лента на микросхемах WS2801 (с индивидуальным управлением каждым пикселем) нужной длины. Выглядит эта лента приблизительно таким образом:
Лучше покупать ленту в силиконовой оболочке. Я покупал на ebay, можно попробовать купить напрямую у китайцев, будет дешевле раза в полтора. Длина ленты должна быть достаточной, чтобы обернуть её по периметру вокруг монитора или телевизора. - Arduino nano (или один из многочисленных клонов) — например, вот это. Подойдёт и не nano, нужно будет лишь правильно подключить.
- Провода, называемые DuPont — не знаю, как они называются по-русски, выглядят вот так:
Эти провода нужны для припаивания к ленте и подключения к ардуино. Нужно всего 2шт — так как они обжаты с двух сторон, разрезав пополам получим нужные нам 4 провода с разъемами. - Блок питания 5V + разъем питания, подходящий к этому блоку — и то, и другое в обилии продается как в радиомагазинах, так и на ebay, любых цветов, размеров и исполнений.
Лента потребляет около 2A / метр в максимально ярком режиме. В повседневной работе 2 метра ленты питаются от БП 3A без каких-либо проблем. - Паяльник (любой, в разумных пределах), паяльные принадлежности, нож для зачистки проводов, изолента/термоусадка по вкусу.
Схема (если это гордое слово подходит для соединения двух изделий четырьмя проводами) приведена на рисунке:

Процесс сборки прост до безобразия. Детально описывать его нет смысла (по этой же причине нет фотографий готового «изделия» — ардуин с четырьмя проводами в интернете полно).
- Припаять всё, как показано на схеме.
- Присоединить провода к arduino, саму ардуинку соединить с PC, подключить блок питания.
- Залить в ардуино скетч (см. ниже), запустить исполняемый файл на компьютере (ссылки на софт также см. ниже), установить в программе нужный порт COM.
Если вы пользуетесь Windows Vista/7 — нужно обязательно отключить Aero. Иначе скорость работы просто плачевная, какого-то решения проблемы низкой скорости захвата экрана при включенном Aero, как я понял, не существует. - Убедиться, что всё работает, выключить.
Следует упомянуть, что работает софт в 32-битном цвете only. Это можно легко поправить, но большого смысла, на мой взгляд, в такой правке нет.
- Прикрепить ленту на монитор. Пустить ленту нужно от левого нижнего угла по периметру по часовой стрелке (ЛН->ЛВ->ПВ->ПН->ЛН). Разрезать ничего не нужно, лента хорошо гнется практически в любом месте, так что проблем быть не должно. Для закрепления я использовал двухсторонний скотч — лента очень легкая и этого более чем достаточно.
На этом сборка закончена. Остаётся посчитать и задать количество пикселей по вертикали и горизонтали, и можно смотреть ролики, играть, 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;
}
Тут всё предельно просто:
- Посылаем сигнал, что мы готовы принять данные о подсветке;
- В течение небольшого промежутка времени ожидаем данные;
- Если данные пришли, то первый байт из этих данных — число диодов, которые обслуживаются. Умножаем на 3 (RGB) для того, чтобы узнать количество последующих байт;
- Переправляем принимаемые данные в ленту;
- Обновляем метку времени о последнем обновлении ленты (это нужно для тайм-аута и гашения всех пикселей ленты).
Программа для PC
Вроде бы есть готовые решения для этого, но то, что я видел, мне не понравилось категорически, и вообще это неспортивно, зря что ли ардуино используется. Поэтому, пожевывая бутерброд, левой ногой была написана программа для захвата областей экрана, обработки их и передачи нужных данных в ленту. Вся программа с потрохами доступна на гитхабе по адресу github.com/sergrt/pixie (за код не пинайте).
Используется Qt 5.0.1 —
Настройки программы
Основная настройка — это указание количества светодиодов по вертикали и горизонтали, а также задание размеров захвативаемых областей. В мои 22" поместилось 10 шт по вертикали и 17 по горизонтали:

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

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

Для удобства работы с программой можно настроить на автозапуск захвата при старте, а также запускать свернутой в область уведомлений.
Немного про внутренности софта для интересующихся
Основная идея состоит в запуске потока, хватающего области по заданному механизму, с подстраиваемым fps, и передающий эти области на обработку и последующую передачу ленте. Области захватываются в соответствии с настройками (кто бы мог подумать), цвет пикселя определяется простым средним по трем каналам RGB соответствующей области экрана. Опционально можно включить (директивами препроцессора) преобразование в Lab и усреднение его силами, но этот кусок кода не оптимизирован никак (взят как есть с просторов интернета), тормозит, поэтому по умолчанию выключен. Более того, каких-то особенных преимуществ Lab не заметно в контексте данной задачи, так что это не повод печалиться.
Обработка областей осуществляется по вертикалям и горизонталям, а на ленту отсылается последовательность цветов, начиная с левого нижнего угла и далее по периметру по часовой стрелке (так, как мы наматывали ленту на монитор при сборке).
Захват DirectX по скорости примерно равен захвату с GDI, при том, что в первом случае захватывается экран целиком, а во втором — только нужные куски. Вероятно, тут есть запас по оптимизации.
Обильное использование memcpy связано в первую очередь со скоростью работы — все остальные методы показали себя медленнее в той или иной степени.
Выводы и впечатления
Запас яркости у ленты просто огромный, что хорошо — можно пользоваться даже при наличии других источников света. В полной темноте лучше подвигать бегунками и сделать помягче. Сама лента вполне может служить самостоятельным источником освещения, нужно лишь переделать скетч.
Полагаю, немалое значение имеет диагональ монитора/телевизора. Чем больше — тем лучше.
Также следует устанавливать экран так, чтобы поблизости не было поверхностей, от которых отражаются светодиоды (в моём случае это боковые поверхности колонок) — это не особо критично, но лучше, чтобы резко выделяющихся пикселей не было видно совсем — так как между ними изрядное расстояние, это не лучшим образом влияет на картинку.
Что понравилось:
Просмотр видео и игры с такой подсветкой субъективно разгружают глаза — пропадает жесткий фокус на картинке монитора. Ощущение усталости глаз наступает позже, если не переусердствовать с яркостью. Смотреть видео как минимум необычно, для полноты эффекта лучше делать это с некоторого расстояния.
Что не понравилось:
К самой системе подсветки как таковой особенных претензий нет, но, как уже говорилось, для полноты удовольствия нужно правильное окружение — отстутсвие бликующих поверхностей, равномерный цветовой фон за экраном, etc. В процессе эксплуатации выяснилось, что дизайнерские изыски моего монитора несколько мешают нормальной работе ленты — передняя панель выполнена из прозрачного пластика и выступает над задней крышкой по всему периметру на несколько миллиметров, особенно выдаваясь в нижней части. Поэтому несмотря на то, что лента закреплена относительно далеко, на гранях этой панели видны отдельные светодиоды. Полагаю, мало кто с таким столкнется, но всё же пусть информация будет доступна заранее.
Ниже — ролик, как это выглядит в динамике. Оператор приносит свои извинения за заваленный горизонт.
Ссылки
- Проект на гитхабе — github.com/sergrt/pixie
- Архив с исполняемым файлом для Win7/Vista etc — rghost.net/43638571 (VS 2012, Qt5)
- Архив с исполняемым файлом для Windows XP — www.filedropper.com/pixiexp (VS 2010, Qt4 — работает на XP, отключен кроссплатформенный захват — т. к. часть необходимых классов в Qt4 отсутствует)
- Ссылка на Visual Studio 2012 Update 1 Redistributable Package (на случай ошибок с отсуствием файлов msvcp110.dll и т.п.) — www.microsoft.com/en-us/download/details.aspx?id=30679
- Ссылка на Visual C++ 2010 SP1 Redistributable Package (x86) (для версии под Windows XP) — www.microsoft.com/en-us/download/details.aspx?id=8328
P. S. Дабы соблюсти приличия, привожу ссылку на отправную точку, откуда я начинал — compcar.ru/forum/showthread.php?t=9462
UPD #1 На гитхабе обновилось ПО (включая исполняемый файл) — добавлена возможность группировать светодиоды для смягчения эффекта при просмотре не особенно динамичны фильмов.
UPD #2 Добавил поддержку захвата экрана силами Qt (при помощи QScreen), так что теперь можно строить кроссплатформенное приложение. Наличие желающих помочь потестировать приветствуется.
UPD #3 Благодаря помощи eugenis (https://github.com/eugenis) появился полноценный файл проекта pro, исправлены неточности для правильной компиляции под linux, немного оптимизирован код. Все эти радости доступны на гитхабе.
Комментарии 66
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.