Однажды, смотря на матричное табло, я подумал, что было бы не плохо, если бы смена текста была анимированной. Стало интересно попробовать. Прототип анимации.

Изображение сконвертировано в анимированный GIF из реально снятого видео
Изображение сконвертировано в анимированный GIF из реально снятого видео

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

Разработка точечного шрифта

Каждый символ описывается координатами точек. Первые 10 символов, представляющих цифры, плюс пара дополнительных для показа градусов, я сделал самостоятельно. За основу символов изображения погоды я взял шрифт, содержащий иконки символов погоды и руками их доработал в редакторе FontCreator. Для того, чтобы анимация символов не выглядела как беспорядочное перемещение точек от одних координат к другим, их необходимо расположить в определённом порядке, чтобы неизменяемые части при переходе оставались на тех же местах, а изменяемые менялись желательно так, чтобы меньше пересекаться с другими точками при движении. FontCreator позволяет при редактировании символа указать индекс каждой точки. Каждая точка у меня это матрица восьмибитных полутонов. Для небольшого размера такие матрицы я подготовил руками, после 8 рисуется автоматически из заполненных кругов понижая яркость от центра к краю.

Не смотря на размеры моих символов 7х14, они очень хорошо масштабируются. Один и тот же шрифт я использовал для больших цифр и для цифр меньшего размера и это смотрелось заметно лучше, чем обычные варианты, предлагаемые готовыми библиотеками для микроконтроллеров.

Применение в часах

Первое же место, где можно применить этот шрифт, конечно же - часы. Как раз понадобилось на замену сделать что-то, чтобы было удобно с дивана смотреть. Предыдущий опыт с часами у меня уже был, там тоже был мой эксперимент с анимированным шрифтом. Там использовался шрифт на кривых Безье, когда каждая цифра описывалась ровно 3-мя кривыми. Впоследствии, я развил тему редактора таких шрифтов и эффектов с ними, но так и не воплотил это в какую‑то законченную библиотеку. Надо сказать, постоянная анимация секунд несколько отвлекает, взгляд прямо таки залипает на ней. Поэтому, в новых часах секундам отведено намного меньше места, надо близко подойти, чтобы их посмотреть.

Морфинг

Для анимационного перехода одного символа в другой выполняется несколько шагов. Создаётся два массива координат точек каждого символа: из которого происходит преобразование и в который происходит преобразование. Затем, количество элементов в этих массивах выравнивается, дополняя недостающие элементы размножением последнего элемента в соответствующем массиве. Функция, выполняющая преобразование, расчитывает сдвиг каждой точки по линии от старых координат к новым в зависимости от параметра `t ∈ [0, 1]`, где `t = 0` означает координаты исходного символа, а `t = 1` - координаты конечного символа. Параметр `t` расчитывается по времени так, чтобы весь промежуток от 0 до 1 пройти за половину секунды. Начальная точка отсчёта подбирается за пол секунды до наступления следующей секунды.

Выбор железа

Выбрал микроконтроллер ESP32, поскольку у него есть WiFi, что позволяет синхронизировать часы с серверами времени и получать информацию о текущей погоде и прогнозе. Микроконтроллер очень универсальный, мощный и стоит не дорого.

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

Я воспользовался тем, что информация на экране может быть разделена пополам -- с одной стороны часы, с другой минуты. Таким образом, экран часов состоит из двух OLED дисплеев размером 1,5" и разрешением 128х128 каждый. OLED SSD1351. На переднем фоне пишется время и температура, на заднем фоне рисуется символ погоды. Слева погода "сейчас", справа погода "через три часа". С погодой идея в том, чтобы утром увидеть тренд перед выходом на улицу.

Экспериментальная сборка из двух дисплеев
Экспериментальная сборка из двух дисплеев

Дополнительно решил воспользоваться фоторезистором для замера окружающей освещённости, чтобы автоматически подстраивать яркость изображения под освещённость.

Платформа

Программа написана с использованием фирменного фреймворка ESP-IDF от Espresiff на чистом Си. Так же использовалась библиотека mjson для разбора принятых ответов от API сервисов. Пришлось воспользоваться сторонней даже не портированной на ESP32 библиотекой, поскольку поставляемый вместе с ESP-IDF компонент cJSON при разборе ответа прогноза погоды объёмом 16 килобайт мог потребовать больше памяти, чем было свободно в куче.

Для работы с дисплеями я написал свой собственный компонент. При написании упор был на универсальность, эффективность, лёгкость и расширяемость. Добавление виртуального экрана, изображение с которого выводится на два физических экрана одновременно, заняло несколько десятков строк. Частота кадров с учётом, что информацию надо сначала нарисовать на виртуальном экране, состаяляет примерно 58,5 кадров/сек. Компонент поддерживает так же шрифты представленные в различных форматах, типа BITSTREAM, как в библиотеках от Adafruit, а так же символы, заданные координатами точек в матрице.

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

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

Функционирование

При первом включении программа обнаружит, что нет данных для подключения к сети и выведет QR-код для программы ESP SoftAP Provisioning, которая есть как в Google Play Market, так и в App Store. После настройки Wifi программа захочет получить данные о своём местоположении, чтобы узнать временную зону и местонахождение, чтобы правильно показывать время и погоду. Поскольку данных изначально нет, их надо ввести через веб-интерфейс. Для включения веб-интерфейса надо нажать кнопку снизу часов, на левом экране появится QR-код с адресом вебсайта, а на правом этот же адрес в обычной символьной форме. Пройдя по адресу и заполнив данные по ключу API от сайта погоды openweathermap.org, а так же либо руками введя местоположение и выбрав временную зону или ввести ключ от API ipinfo.io, тогда программа будет определять своё местоположение автоматически. Сразу после отправки данных веб-интерфейс выключается и часы переходят в обычный режим.

Определив своё местоположение и подстроив соответственно временную зону, часы регулярно опрашивают сайт погоды, по информации от которого получают время восхода и заката для местоположения. От этого вычисляется цвет цифр времени. Ночью цвет должен быть медным, днём белым, переход от одного к другому плавный. Цвет символов погоды и цифр температуры вычисляется от температуры. Когда холодно, то цвет уходит в синий; когда умеренно тепло, то зелёный; жаркая погода показывается красным. Формулы преобразования температуры в цвет придуманы самостоятельно, почему-то нигде ничего готового нет.

Внутреннее устройство

Все компоненты установлены на макетной плате. Готовая плата разработчика похожая на NodeMCU ESP-WROOM-32 установлена в кроватку, над платой находятся два дисплея. Питание осуществляется через внешний USB-C разъём. Резисторами выставлен режим потребления 5В. Дополнительна установлена кнопка для включения режима конфигурирования через веб-интерфейс и фоторезистор для подстройки яркости под окружающее освещение. Использовался готовый корпус для самодельных устройств.

Код проекта выложен на github, лицензия MIT.

Галерея

Дисплеи сверху
Дисплеи сверху
Вид изнутри
Вид изнутри
Вид сбоку
Вид сбоку
Вид часов в сборе на стене
Вид часов в сборе на стене

Комментарии (41)


  1. exTvr
    29.05.2024 08:34
    +5

    Красивое :)) и устройство и статья.


  1. JerryI
    29.05.2024 08:34
    +2

    Интересно наблюдать развитие за последние 20 лет. Сначала было на к155ла3, потом на Attiny/PIC, затем …делаем на Atmega16, потом …на Arduino, а теперь на …ESP32.


    1. Javian
      29.05.2024 08:34
      +1

      Такие часики неплохо бы смотрелись на экране от смартфона. Но там с железом всё намного проще - нужен просто старый рабочий телефон https://habr.com/ru/articles/443052/


    1. fiego Автор
      29.05.2024 08:34
      +1

      Есть разница в источниках точного времени. Либо руками выставлять, опираясь на сигналы точного времени, переданные радиостанцией "Маяк", либо по радиосигналу синхронизироваться с атомными часами, либо просто по NTP. В последнем случае ESP32 я вижу очень даже оправданным.


  1. digitalm
    29.05.2024 08:34
    +2

    Отличная идея и реализация. Украшение интерьера =)


  1. x89377
    29.05.2024 08:34

    Жаль не могу поставить 5 плюсов ! Красота просто неземная !


  1. Jury_78
    29.05.2024 08:34

    Переход цифр только последовательный или из любой в любую?


    1. fiego Автор
      29.05.2024 08:34
      +2

      Из любой в любую. Динамически строятся траектории перехода.


    1. voldemar_d
      29.05.2024 08:34
      +1

      В начале статьи GIF, в которой виден ответ на вопрос.


  1. rnadyrshin
    29.05.2024 08:34

    Очень прикольный эффект получился


  1. Ken-Sei
    29.05.2024 08:34

    Офигенно!


  1. Antohin
    29.05.2024 08:34
    +1

    Ваши часы надо запретить - они превращают людей в котов с того мема ;-)


  1. Iwan95
    29.05.2024 08:34
    +3

    Вот таким и должны быть статьи- где есть и идея и исполнение и результат и описание. Порадовал, спасибо!"


  1. ptr128
    29.05.2024 08:34

    Спасибо. Редки здесь статьи от эмбедеров. А такие качественные - тем более.


    1. fiego Автор
      29.05.2024 08:34
      +4

      Это моя первая статья тут, боялся, что наоборот, мало написал :)


  1. voldemar_d
    29.05.2024 08:34
    +1

    Вроде было где-то упоминание про часы с морфингом на МК, только там каждая цифра была векторной.


    1. fiego Автор
      29.05.2024 08:34
      +3

      Есть подозрение, что то тоже мои были. Следующую статью про них напишу


      1. voldemar_d
        29.05.2024 08:34

        Было видео в каком-то комментарии не помню к чему, ссылку не могу сходу найти.


        1. fiego Автор
          29.05.2024 08:34
          +3

          Спойлер следующей статьи: Bezier Curves Clock with weather, там рядом есть мои видео и с тонкими линиями. Толстые кривые сложнее сделать.


          1. voldemar_d
            29.05.2024 08:34
            +2

            Ссылка ведёт непонятно куда.


            1. fiego Автор
              29.05.2024 08:34
              +1

              Извиняюсь, не проверил. Вы, должно быть видели одно из этих моих видео: Bezier Curves Clock with weather, Digital clock with handwritten numbers


              1. voldemar_d
                29.05.2024 08:34

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


  1. NutsUnderline
    29.05.2024 08:34
    +2

    Прямо как старые демосцены с морфигами

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

    Такую штуку уже можно показывать в номинации wild, только музыку добавить надо


    1. fiego Автор
      29.05.2024 08:34
      +2

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


  1. NickDoom
    29.05.2024 08:34
    +4

    Вот ещё древняя темка, если интересно. Работает только с движущимся текстом. Замечали, как на табло прямой шрифт превращается в курсив, если низ запаздывает с обновлением?

    Берём табло крайне паршивого разрешения (допустим, 6 строк высотой) и…

    1. Вычертите пиксельный глиф таким, каким он будет эстетичен и легкочитаем.

    2. Обведите пиксельный глиф более плавным и эстетичным векторным глифом так, чтобы при пикселизации он обращался именно в такой пиксельный глиф (т. е. не заходя за центры пикселов там, где не надо, и как минимум слегка заходя за них там, где надо).

    3. Согласно векторному глифу, задайте данные для кернинга (двух-трёх высот достаточно).

    4. Разбейте векторный глиф на отдельные вектора, проходящие через пикселы.

    5. Не пытайтесь сначала строить векторный глиф, а потом пикселизовать его. Обычно он пикселизуется в какую-то дрянь.

    Итак, теперь у нас получен векторно-растровый глиф с кернинговыми данными, который при нахождении в целой пиксельной позиции (т. е. при неподвижном тексте) даёт желаемое пиксельное отображение.
    Если теперь начать скроллить текст горизонтально, включая и выключая СД сообразно началам и концам векторных интервалов, преимущество субпиксельного разрешения будет в полной мере реализовано, значительно сглаживая грубый глиф до полученного в п. 2 векторного глифа.

    В случае, если метод применяется для шахматного расположения СД, за один столбец считается полностью повторяемый по горизонтали паттерн. Так, на рисунке показано знакоместо не 8х5, а 4х10: ширина в 4 СД и высота в 10. Просто эти 10 в каждом столбце расположены не вертикально, а "змейкой".
    Кернинг в целых столбцах уже даёт слишком большие ошибки округления и следует использовать дробные величины.

    Позиция следующего символа берётся с точностью до целого столбца такой, чтобы суммы левого и правого интервалов соответствующих символов на всех трёх высотах лежали в заданных пределах. Пороги могут быть заданы как для отдельных интервалов, так и для среднего (например, где-то можно допустить "почти сливающиеся" соседние символы на уровне, скажем, "ножки", если они значительно отстоят на других уровнях, т. е. визуально по-прежнему хорошо разделены).
    Поскольку кернинг всё равно округляется до столбца, при бедном алфавите можно просто хранить сочетания кернингов между любой парой символов.

    Кратко резюмируя это писево — просто храним шрифт не растром X x Y, а в виде дробных величин «начало свечения/конец свечения» для каждого Y. Когда надо показывать текст — зажигаем и гасим светодиоды сообразно началу и концу свечения в нужные моменты, не обрубая их до кратности целому пикселу.

    Зрительный аппарат при слежении глазами за движущимся объектом прекрасно сам всё достраивает до полноценной «механической развёртки» (как минимум, за счёт саккад), в результате чего мы получаем по горизонтали разрешение практически в четверть светодиода, то есть виртуальное разрешение увеличивается вчетверо, а шрифт типа «сложено из кирпича» — в плавный и аккуратненький.


    1. fiego Автор
      29.05.2024 08:34

      Идея интересная, спвсибо, учту на будущее.


  1. Robastik
    29.05.2024 08:34
    +2

    Совершенно бомбически!

    Требую DIY инструкцию для реализации на старом планшете → чтобы настенные, это же арт-объект))) а то 1,5 дюйма только на стол.


    1. fiego Автор
      29.05.2024 08:34

      1,5" там каждый дисплей, когда они там два рядом, то это уже 2.74". В текущем виде на уровне глаз мне хватает в зале, но я согласен, думаю наверх в другой комнате надо побольше что-то.


  1. Earthsea
    29.05.2024 08:34
    +1

    для реалистичной анимации движения точек

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

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


  1. vladkorotnev
    29.05.2024 08:34
    +3

    Прикольно вышло, в коде правда чорт ногу сломит :-)

    Надо будет порефакторить и сдёрнуть к себе в плазменные часы :-)

    С погодой я бы ещё подумал что-нибудь, чтобы точки перемещались не рандомно или в порядке отрисовки, а по близости координат. Т.е. чтобы в примере на видео, например, солнце хвосты "отращивало", а они не прилетали откуда-то снизу.


    1. fiego Автор
      29.05.2024 08:34

      Вы первый, кто обратил внимание на код :) Есть такая проблема, согласен. В своё оправдание скажу, что идея развивалась итеративно, постоянно шли эксперименты что как и где показывать, как организовать структуры данных. И делалось это урывками по паре часов в неделю, когда надо какое-то время потратить на мысль "а на чём я остановился и что запланировано дальше". После нескольких месяцев такого режима хочется уже наконец просто дописать проект до результата и не париться о рефакторинге :) Программа работает стабильно, работает как надо - задача выполнена. Рефакторинг оставлен на следующий проект в котором потребуется этот код.

      Идея чтобы у солнышка отрастали лучики или наоборот сворачивались у меня была. Планировал решить именно тем способом, что и с цифрами - лучики делать последними точками в списке, тогда все общие будут оставаться на своих местах, а убираться или появляться будут автоматически. Но надо правильный порядок. Потратил много времени на эти символы и на войну с редактором, в котором их делал. Простой символ облака порядка 70 точек, расставлять индексы у более чем 20 иконок так чтобы переходы получились "плавными" -- я быстро устал, поэтому оставил просто в порядке сканирования, эффект тоже прикольный.

      На счёт по близости координат -- такая идеяу меня тоже была, но там слишком много вопросов по крайним случаям, отказался от реализации.


    1. fiego Автор
      29.05.2024 08:34
      +1

      Надо будет порефакторить и сдёрнуть к себе в плазменные часы :-)

      Я, кстати, читал эту статью, круто вышло!


  1. amaranth
    29.05.2024 08:34

    Здравствуйте!

    В качестве платы какую плату от WeAct Studio можно использовать?


    1. NutsUnderline
      29.05.2024 08:34
      +1

      у автора используется плата с процом ESP32S который уже не актуален, как бы не должно быть особых проблем с прочими ESP32, но для спокойствия ESP32 без букв или ESP32-S3. При сборке прошивки нужно будет указать правильный тип проца и скорее всего указать GPIO


    1. fiego Автор
      29.05.2024 08:34

      Главное, чтобы было 2 свободных SPI, по одному на каждый дисплей. Если я правильно помню, то серия -C имеет всего один свободный. Я пользовался обычным ESP32, без -S, -C и прочих вариантов. Серия -S обычно более навороченная, но и более дорогая. Программа на флешке занимает чуть больше мегабайта. Сам удивился, но большая часть занятого места -- стандартные части от ESP-IDF. Для работы после загрузки OS остаётся примерно 300кБ свободной RAM, программа при нормальной работе оставляет в куче 65-75кБ свободными, так что RAM хотя бы 450кБ должно быть. Из представленных на сайте я вижу только ESP32-S3 и ESP32 удовлетворяют требованиям, хотя -S3, я считаю перебором.


      1. NutsUnderline
        29.05.2024 08:34

        Так судя по картинке на NodeMCU-P32S модуль с -S ?

        И тут в любом случае есть такая штука что на git частенько есть How To Compile там же ведь нужно указать terget


        1. fiego Автор
          29.05.2024 08:34

          Мой модуль называется NodeMCU-32S, но чип на нём ESP32, без -S.


          1. NutsUnderline
            29.05.2024 08:34

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


            1. fiego Автор
              29.05.2024 08:34
              +1

              Можно за счёт потери параллельности пересылки, FPS упадёт в два раза.


  1. KonstantineZ
    29.05.2024 08:34
    +2

    Красивый эффект, но резкое исчезновение двойки во втором видео - не айс. Может сделать движение всех пикселей в одну точку с исчезновением после достижения конечной точки?


    1. fiego Автор
      29.05.2024 08:34

      Действительно, пропадает. На самом деле, исчезновение предусмотрено. Скорее всего, случайно его сломал и не заметил из-за редкости возникающего случая.