...

четверг, 26 февраля 2015 г.

Использование цветовых пространств в ATTiny13a для WS2811

image

Моя новая идея посвящена использованию цветовых пространств в микроконтроллерах.

То что моя новость кому-то таковой не покажется, я нисколько не удивлюсь.

Однако я предлагаю метод и его реализацию, подобных которому я не встречал.



Немного вступления, с чего все началось. Совсем недавно закончился год и в наследство от него у меня осталось около 300 светодиодов ws2811. Почему-то руки до них так и не доходили, но после празднования нового года у родственников я заметил, что у тётки стояла маленькая сувенирная ёлочка из стекла, которую она очень любит. Но она в этот раз совсем не сверкала и не искрилась по весьма банальной причине… сели батарейки. Вспомнив про свой набор светодиодов, пообещал сделать маленькую гирлянду для этой ёлочки, чтобы устранить эти недостатки раз и навсегда и сделать еще одного близкого мне человека хоть немного счастливее.

Разработка вертится в голове, постепенно ускоряясь, иногда превращаясь в вихрь мыслей, но до этих дней с места так и не сдвинулась. Останавливало то, что все те идеи, которые касались программы эффектов и их переключений, выглядели в голове очень громоздкими и страшно неудобными, при реализации их в цветовом пространстве RGB, к тому же я никак не мог из-за этого определиться, какой контроллер использовать. Но благодаря моему небольшому опыту работы дизайнером, я имею знания и о других пространствах, что натолкнуло меня на мысли о HSL и HSV. Изобретать новое смысла не было, реализаций полно нужно, лишь поискать… но я так и не нашел. Нет, я конечно нашел много интересных решений, и многие из них были Вашими, представленными прямо здесь, на Хабре, и за что я всем Вам бесконечно благодарен, Вы дали пищу для ума.


В итоге было решено остановиться на HSL, исключив из него одну компоненту S (Saturation), оставив ее константной (так как в реализации ЦДУ, этот параметр лишний), а контроллер решил использовать ATMega8U.


Набросав код и испытав прошивку, я понял что чего-то не хватает. И не хватило мне маленького несоответствия реалу.

Каждый охотник желает знать… И вновь я возвращаюсь к этому вопросу, и вновь осознаю, что нет его…

Нет оранжевого цвета в природе, как ни крути, он всего лишь оттенок.


Это и стало корнем и стержнем моей идеи, благодаря чему я полностью переписал код и придумал метод использования компактного описания цветового пространства, причем это уже совсем не HSL, HSV и не RGB, потому что я расширил диапазон оранжевого и вынес его в отдельный пространственный сектор.




Пространство можно представить как поверхность цилиндра в случае если оно замкнуто, с расположенными в углах, смещенными на 60 градусов базовыми цветами, между которыми заполнено градиентными переходами от одного базового цвета к другому:

image


Где высота цилиндра — это яркость, которая так же является составляющей градиента оттенков.

То же самое пространство представляет прямоугольник со сторонами «A x B», где «А» это угол определяющий базовый цвет и его оттенок, а «B» — яркость, в случае если пространство не замкнуто или развернуто из цилиндра.


Для поставленной задачи я решил использовать квадрат со стороной 255 х 255, тем самым уложившись в тип байт, где для угла, значения изменяются в пределах 0..255 (байт), а яркость: -127..127 (знаковый байт), благодаря этому получил возможность использования 8-ми базовых цветов и 32 градаций оттенков для каждого.


Пространство описывается как массив с RGB — компонентами базовых цветов, а градиенты оттенков рассчитываются на лету.

Пример описания:



{0,128,0}, {64,128,0}, {128,128,0}, {128,0,0}, {128,0,128}, {0,0,128}, {0,128,128}, {0,128,0}




здесь описана последовательность базовых цветов, назовем ее просто — радуга, где порядок компонент изменен согласно даташиту ws2811 (GRB), а последний — красный цвет, служит для замыкания пространства, выглядит это так:

image


Теперь, если взять некоторый индекс цвета, например 183, то можно сделать его отражение в пространство RGB таким образом:

Индекс базового цвета = 183 / 32 = 5 (синий, или {0,0,128})

Смещение оттенка = 183 % 32 = 23

Теперь вычисляем разницу между компонентами полученного базового цвета ({0,0,128}) и следующего за ним {0,128,128}, чтобы вычислить приращение (назовем его дельтой):



dG = 0 - 0 = 0, dR = 128 - 0 = 128, dB = 128 - 128 = 0;




Так как между цветами 32 градации, необходимо выполнить разбиение разности компонент:

dG= 0 / 32 = 0, dR= 128 / 32 = 4, dB= 0 / 32 = 0;




Теперь необходимо полученную дельту домножить на смещение оттенка и прибавить к компонентам текущего базового цвета ({0,0,128}):

G = 0 + 0 * 23 = 0, R = 0 + 4 * 23 = 92, B = 128 + 0 * 23 = 128;




Получили {0,92,128}, к которому теперь можно прибавить яркость, например 50: {50,142,178} — искомый цвет.

Как видно из примера, ничего сложного нет. В случае если дельта принимает отрицательное значение, то смещение оттенка при умножении даёт отрицательное дополнение, которое в сумме даст разность с конечной компонентой, это произойдет в случае, когда компонента градиента идет на спад.


И да, яркость применяется не пропорционально, а линейно, что дает некоторую погрешность, но в рамках описанной задачи это не страшно. Так же необходимо следить за нижним порогом чтобы не вызвать переполнение при отрицательной яркости.


Таким образом полученное пространство дает возможность использования 255 * 255 = 65535 оттенков.


Весь описанный метод был оптимизирован, устранены все умножения и деления, и приведен под упрощенную быструю математику, позволяет легко переписать его на ассемблер (лично меня скорость абсолютно устраивает: 200 ns между расчетами компонент для 7-и светодиодов), если нужна оптимизация для уменьшения размера кода.

В результате, первоначальное решение об использовании ATMega8u было отменено в пользу тиньки, так как полученная прошивка заняла меньше половины килобайта.


Нет, я не жлоб, я просто ленивый.


Итак, код ниже, выполняет инициализации, и содержит функцию вывода данных на линию ws2811:


image


А это код основного цикла и функция преобразования индекса пространства в цветовые составляющие с примером использования:


image


А вот видео с демонстрацией работы (правда цвета далеки от реальности):


Описывать подробней комментариев в тексте смысла нет, сам метод уже описан выше. Если есть вопросы, задавайте.


Ну вот, собственно, и все, что я хотел рассказать.




image

Давайте теперь на секунду представим, как можно использовать данный метод. Как вам, например, такое пространство, которое показано на этой картинке:


Правильно! Можно описывать разные цвета и градиенты между ними. И кто вначале описания решил что метод не позволяет использовать оттенки серого — не прав.




Массив, описывающий в памяти пространство, занимает 32 байта (из-за выравнивания), который хранится в программной памяти. Если создать несколько таких описаний пространств, и переключаться между ними на ходу, переключая указатель на массив, то можно выбирать текущее пространство для каждого нового светодиода в очереди, а так же позволяет расширить число градаций между оттенками. И если слегка модифицировать код, и увеличить число ступеней в описании компонент до 8-ми, то 32*8 даст 256 (в моем коде 3 ступени), то использование семи массивов (0..255 красный, желтый, зеленый, голубой, синий, фиолетовый, белый) дают комбинацию в 16m оттенков «одновременно на экране»! При использовании 224 байт прошивки для хранения. А если еще немного по-потеть и чуть переписать код, то можно уложиться и в 96 байт с тем же результатом.

Плюс, благодаря оптимизации и полученной скорости обработки, можно использовать так называемый метод дизеринга ((англ. dither от старо-английского didderen — дрожать) С помощью чего, можно добиться еще большего числа оттенков. Так же это позволяет создавать замыкания пространств друг на друга, чтобы устранить или сделать невидимыми эффекты перехода. В общем, все предложенное может быть модифицировано как Вашей душе угодно, на Ваш вкус и цвет, а может использоваться как есть, и удовольствие я Вам гарантирую!


Вот теперь я вновь с вами прощаюсь, а вам оставляю исходный код в безвозмездное пользование.

С нетерпением жду ваших комментариев, критики, вопросов и советов.

Спасибо за внимание, до новых встреч!


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


This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.


Комментариев нет:

Отправить комментарий