Первая радуга у меня рассыпалась на полосы. В примере из документации стояла дельта 8, я решил, что цвета будут «сочнее», и поставил 32 — шестнадцать пикселей превратились в конфетти из отдельных резко разных цветов, а не в радугу. Поменял на 1 — лента стала почти одноцветной, красно-оранжевой от начала до конца. Полчаса я тупо перебирал значения, пока не сел и не посчитал, что третий и четвёртый аргументы fill_rainbow вообще делают. Считать, а не перебирать, — тема этого урока.
Разберём сигнатуру fill_rainbow по аргументам, выведем условие, при котором радуга ложится на ленту без повторов, заставим её ползти по времени и соберём ручной вариант циклом — он выручает, когда стандартной заливке нужно что-то подправить: приглушить, ограничить отрезком круга, подмешать свою яркость. Всё крутится в симуляторах на этой странице.
Анатомия: стартовый оттенок и шаг
fill_rainbow(leds, 16, startHue, deltaHue) красит буфер так, что пиксель с номером i получает оттенок startHue + i * deltaHue. Первый аргумент — буфер, второй — сколько пикселей красим, третий — оттенок нулевого пикселя, четвёртый — на сколько шагов сдвигается оттенок от пикселя к пикселю. Никакой магии: это цикл с формулой внутри, и вся «настройка радуги» — два числа, которые вы ей даёте.
Отсюда сразу главное условие. Полный цветовой круг — 256 шагов оттенка. Если deltaHue, умноженное на число пикселей, даёт примерно 256, на ленту ложится ровно один круг без повторов и без швов: на шестнадцати пикселях это дельта 16. Дельта 8 — половина круга, растянутая на всю ленту: спокойные соседние оттенки, «лёд» или «закат», а не праздничный веер. Дельта 32 — круг дважды, соседние пиксели уже заметно разные; дельта 64 — круг четыре раза, и начинается то самое конфетти из моей истории. Таблицу «оттенок — цвет» мы заполняли в уроке про колесо HSV — держите её в голове, она делает подбор дельты осмысленным: дельта — это «сколько круга на пиксель», умножьте на число пикселей и прикиньте результат до запуска. На ленте нестандартной длины расчёт тот же, только дельта перестаёт быть круглой. Тридцать пикселей: 256 делим на 30, выходит примерно 8,5 — берём дельту 8 или 9; в обоих случаях круг ляжет на ленту целиком, максимум с крошечным нахлёстом на стыке, который глазу не виден. Шестьдесят пикселей — дельта 4. А если радуга нужна не на всей ленте, а на участке, fill_rainbow всё равно справится: она красит столько пикселей, сколько вы ей назвали вторым аргументом, — просто заливайте не весь буфер, а его начало, а хвост красьте отдельным циклом с границами из прошлого урока раздела.
Теперь движение. Пока startHue не меняется, радуга застыла картиной. Но достаточно в каждом кадре сдвигать стартовый оттенок на один шаг — и вся картина поедет по ленте: fill_rainbow перерисовывает буфер заново каждый вызов, картинка смещается на один оттенок. Переменную hue заводим как byte: после 255 байт переполнится и вернётся в 0 — тот самый замкнутый круг из урока про HSV, никаких закольцовывателей писать не нужно. Скорость считается честно: при кадре раз в 30 миллисекунд полный оборот оттенка — 256 шагов — занимает около 7,7 секунды; ускорили шаг до 2 — 3,8 секунды, замедлили кадр до 60 мс — 15 секунд. Каркас кадров на millis() разобран в уроке про millis вместо delay; в симуляторе ниже для простоты стоит delay(40), и оборот занимает около десяти секунд.
Отдельно подчеркну: дельта и скорость — независимые ручки, и новички их постоянно путают. Дельта решает, какая часть колеса лежит на ленте; сдвиг стартового оттенка за кадр решает, как быстро картинка едет. Можно иметь растянутый полукруг-«лёд», который несётся по ленте, а можно плотную радугу, застывшую на месте. Направление тоже переключается на лету: hue = hue - 1 гонит картинку в обратную сторону — я использую это, когда радуга-гирлянда должна «отражаться» от стены в коридоре.
Честные оговорки: палитра и яркость
Две вещи, которые лучше знать до встречи с настоящей лентой. Первая — про точные цвета. FastLED переводит CHSV в RGB не по «школьной» спектральной математике, а по собственной таблице hsv2rgb_rainbow: оттенки на круге разложены так, как выглядит приятная глазу радуга, а не как складываются длины волн. Симулятор курса считает по стандартной математике HSV, поэтому отдельные оттенки на виртуальной ленте могут отличаться на пару шагов от настоящей — суть эффектов и порядок цветов не меняются. Если когда-нибудь будете калибровать цвет под конкретную партию лент, вспомните эту оговорку: конвертеров в библиотеке два, и дефолтный — «радужный».
Вторая — про яркость. fill_rainbow красит на полной насыщенности и полной яркости, других настроек у неё нет. Приглушить — общим множителем FastLED.setBrightness(): в симуляторах этого урока он стоит в setup() именно поэтому. В настоящей библиотеке есть ещё nscale8 — поэкранное уменьшение яркости буфера, — но в симуляторе этой функции нет, и честнее об этом сказать, чем спрятать. Когда нужна своя яркость или свой отрезок круга, я не мучаюсь и собираю радугу руками — циклом из урока про циклы, одна строка формулы вместо вызова:
#include <FastLED.h> #define LED_PIN 6#define NUM_LEDS 16 CRGB leds[NUM_LEDS];byte hue = 0;unsigned long lastFrame = 0; void setup() { FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS); FastLED.setBrightness(120);} void loop() { if (millis() - lastFrame >= 30) { lastFrame = millis(); fill_rainbow(leds, NUM_LEDS, hue, 16); hue = hue + 1; FastLED.show(); }}Задачи на закрепление — решайте в симуляторах выше. Первая: «лёд» — стартовый оттенок 130, дельта 6, насыщенность 200; подберите задержку так, чтобы лента дышала, а не крутилась. Вторая: секундомер — при кадре 30 мс и шаге 1 оборот должен занимать около 7,7 секунды; поставьте шаг 2 и сверьте с расчётом 3,8 секунды. Третья: «две половины» — ручным циклом красите пиксели с 0 по 7 оттенком hue, с 8 по 15 — hue + 128, каждые полсекунды половины меняются местами; это заготовка контрастной индикации. Четвёртая: соедините радугу с затуханием из урока про эффекты — fadeToBlackBy поверх радуги с редкой подкраской даёт «тлеющий» перелив, который выглядит дороже, чем стоит.
И про питание, без него раздел неполный. Радуга на полной насыщенности берёт примерно две трети от максимума белой заливки: в каждом пикселе при чистом оттенке горят максимум два кристалла из трёх, полный ток белого мы считали в первом уроке раздела. Шестнадцать пикселей радуги — комфортно от Arduino; метр 60-пиксельной ленты на яркости 255 — уже отдельный блок питания, радуга тут ничего не отменяет. Ручная радуга из симулятора выше экономит ещё: насыщенность 150 — это примерно 60 процентов тока от полной при той же картинке, потому что приглушённые кристаллы горят слабее.
Последнее — про пресеты и вкус. Разбор дельты в начале урока — это скелет, а настроение делают стартовый оттенок и насыщенность: старт 0 с дельтой 6 — «закат», старт 130 с дельтой 6 — «лёд», старт 96 с дельтой 12 и насыщенностью 180 — «весенний сад». Я один раз потратил вечер на подбор этих троек для гостиной и с тех пор просто копирую их из проекта в проект — так и рождаются ваши собственные пресеты вместо чужих из интернета.
- «Лёд»: fill_rainbow(leds, 16, 130, 6) плюс насыщенность через ручной цикл s = 200. Подберите задержку, чтобы перелив стал медленным дыханием.
- Секундомер: измерьте время полного оборота при кадре 30 мс и шаге 1, затем при шаге 2. Сверьте с расчётом 7,7 и 3,8 секунды — линейность это лучшая проверка, что вы поняли механику.
- «Две половины»: пиксели 0–7 оттенком hue, 8–15 — hue + 128; по счётчику каждые 500 мс меняйте половины местами. Получится жёсткая двухцветная индикация без единой CRGB-тройки.
- «Тлеющий перелив»: каждый кадр fadeToBlackBy(leds, 16, 40), а fill_rainbow вызывайте раз в пять кадров. Радуга будет вспыхивать и таять волнами.
- fill_rainbow(leds, N, startHue, deltaHue): пиксель i получает оттенок startHue + i * deltaHue — цикл с формулой, магии нет
- Дельта на число пикселей ≈ 256 — один полный круг без повторов; 8 — полкруга-перелив, 32 и выше — «конфетти»
- Радуга едет, когда стартовый оттенок меняется в кадре; byte замыкает круг сам: 255 + 1 = 0
- fill_rainbow красит на полной насыщенности и яркости; приглушение — setBrightness, а своя яркость — ручной цикл leds[i] = CHSV(hue + i * d, s, v)
- Симулятор считает оттенки стандартной HSV-математикой, настоящая лента — через таблицу hsv2rgb_rainbow: цвета могут отличаться на пару шагов, порядок — нет
- 1. Что делает четвёртый аргумент в вызове fill_rainbow(leds, 16, 0, 16)?
- 2. Сколько полных цветовых кругов ляжет на 16 пикселей при deltaHue = 64?
- 3. Как заставить радугу ползти по ленте?
- 4. Как собрать fill_rainbow(leds, 16, hue, 5) вручную циклом?
- 5. Почему радуга берёт меньше тока, чем белая заливка той же яркости?
Частые вопросы по теме урока
- Что делает четвёртый аргумент в вызове fill_rainbow(leds, 16, 0, 16)?
- Порядок такой: буфер, число пикселей, стартовый оттенок, шаг оттенка. Пиксель i получает оттенок startHue + i * deltaHue. Задаёт сдвиг оттенка между соседними пикселями
- Сколько полных цветовых кругов ляжет на 16 пикселей при deltaHue = 64?
- 64 × 16 = 1024, это 1024 / 256 = 4 круга. Соседние пиксели резко разные — тот самый эффект «конфетти». Четыре
- Как заставить радугу ползти по ленте?
- fill_rainbow рисует картинку по startHue; сдвигайте его на шаг в каждом кадре — и картина поедет. byte сам замкнёт круг после 255. Менять стартовый оттенок в каждом кадре loop()
- Как собрать fill_rainbow(leds, 16, hue, 5) вручную циклом?
- Формула прямая: оттенок пикселя i — старт плюс шаг, умноженный на номер. Ручной вариант нужен, когда хочется свою насыщенность или яркость. leds[i] = CHSV(hue + i * 5, 255, 255)
- Почему радуга берёт меньше тока, чем белая заливка той же яркости?
- Белым горят все три кристалла, у чистого оттенка один канал выключен — примерно две трети от максимума. Это при полной насыщенности; приглушённая радуга берёт ещё меньше. В чистом оттенке горят максимум два кристалла из трёх