- PVSM.RU - https://www.pvsm.ru -

Использование цветовых пространств в 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 [1]

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

image [2]

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

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

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

… шутка — не все!

image

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

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

В заключении — самое вкусное

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

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

Вот теперь я вновь с вами прощаюсь, а вам оставляю исходный код [4] в безвозмездное пользование.
С нетерпением жду ваших комментариев, критики, вопросов и советов.
Спасибо за внимание, до новых встреч!

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

Автор: DolphinSoft

Источник [5]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/algoritmy/84138

Ссылки в тексте:

[1] Image: http://habrastorage.org/files/2f2/8f2/f8d/2f28f2f8da394430828d2fb9f71f2727.png

[2] Image: http://habrastorage.org/files/4f8/4b6/b49/4f84b6b499cf4cc78173fb99582e3371.png

[3] дизеринга : https://ru.wikipedia.org/wiki/%D0%94%D0%B8%D0%B7%D0%B5%D1%80%D0%B8%D0%BD%D0%B3)

[4] исходный код: https://drive.google.com/file/d/0B3cBf1lTmLD2VFhtZUxFckR4MTg/view?usp=sharing

[5] Источник: http://habrahabr.ru/post/251615/