На днях в сети появилось описание оригинального DIY-проекта на основе Raspberry Pi и светодиодных панелей. Цель проекта — визуализировать уровень загрузки процессора ПК. Для этого используются анимация на LED-панелях самодельного устройства.
Чем выше нагрузка на CPU, тем выше температура чипа и тем более «горячими» становятся цвета светодиодных панелей. Минимальная нагрузка — голубой и синий цвета, максимальная — оранжевый и красный. Общее количество задействованных светодиодов достигает 12 000. Под катом — описание проекта, его элементов, плюс исходный код ПО, которое обеспечивает работу гаджета.
Вот как все это выглядит:
Как возникла идея проекта
В прошлом году автор принял участие в 36th Chaos Communication Congress (36C3), где увидел огромное количество DIY-проектов, включая светодиодные кубы. Его это очень впечатлило.
Большая часть этих проектов заключалась в реагировании устройства на внешние факторы. Так, при вращении устройства в руке оно переливалось всеми цветами радуги, показывая красочные картинки.
Себастиан Стаакс (Sebastian Staacks) решил разработать собственный проект — устройство, которое сможет показывать уровень нагрузки процессора ПК. Особого практического смысла нет, это проект just for fun.Общая стоимость системы в сборке составила $150.
Реализация проекта
То, как выглядит и работает светодиодный куб, показано выше. Теперь немного подробностей. Устройство включается автоматически после загрузки ПК, к которому оно подключено.
Автор говорит, что постарался сделать цвета и анимацию максимально нейтральными, чтобы не отвлекать внимание пользователя ПК во время работы (или игры).
Железо и ПО
Конструкция устройства очень простая. Вот, что увидит человек, который захочет разобрать девайс.
У «куба» только три грани. Это сделано для того, чтобы удешевить и несколько упростить конструкцию. Если бы работали все грани, проект получился бы слишком дорогим.
Светодиодные панели автор заказал с Aliexpress, выбрав лучшее сочетание цены и качества. По его словам, это было непросто, поскольку поставщики редко прописывали подробные технические характеристики своего товара. Соответственно, не всегда было понятно, подходят ли эти панели для проекта. В итоге разработчик купил панели с 64x64 RGB LED и 5В питанием.
Для питания этих панелей был использован 50W блок с 10А и 5В. Адаптер питает драйвер матрицы Adafruit, который подключен к панелям через Raspberry Pi. Главное — чтобы характеристики блока питания перекрывали потребление системы.
Управление панелями
Что касается «малинки», разработчик использовал Raspberry Pi 2. На данный момент этот одноплатник нельзя считать слишком устаревшим морально, для подобных целей его вполне хватает. Кроме того, он почти не нагревается в процессе работы, чего нельзя сказать о третьем и четвертом поколениях.
К плате был подключен внешний WiFi-модуль, чтобы избавиться от кабелей для подключения к сети. Паять почти ничего не нужно было, за исключением пары операций с Adafruit RGB Matrix Bonnet.
Вот так финальная конструкция выглядит в собранном виде. Для того, чтобы придать всему этому форму, автор использовал корпус, распечатав его на 3D-принтере.
Панели не приклеиваются, чтобы их в любой момент можно было снять с корпуса. Предусмотрены также крепления для Raspberry Pi. Еще можно распечатать основу для куба, но, в целом, все выглядит неплохо и так.
Теперь о программном обеспечении. С «железом» все проще, а вот с управляющим ПО придется повозиться. Для анимации используется OpenGL-шейдер. Кроме того, на ПК запущен скрипт, который передает характеристики работы процессора на «малинку».
Самый важный элемент программного обеспечения — небольшая программа на С++, которая управляет кубом. Она использует специальную библиотеку rpi-rgb-led-matrix. В частности, она нужна для открытия UDP-порта, чтобы получить характеристики работы процессора с ПК, а также OpenGL для рендеринга анимации. Подробности работы библиотеки — здесь.
Для установки нужен скрипт от Adafruit. Инструкция по установке доступна по указанной ссылке.
Вот параметры для настройки панелей
//LED Matrix settings
RGBMatrix::Options defaults;
rgb_matrix::RuntimeOptions runtime;
defaults.hardware_mapping = "adafruit-hat-pwm";
defaults.led_rgb_sequence = "RGB";
defaults.pwm_bits = 11;
defaults.pwm_lsb_nanoseconds = 50;
defaults.panel_type = "FM6126A";
defaults.rows = 64;
defaults.cols = 192;
defaults.chain_length = 1;
defaults.parallel = 1;
Обратите внимание, pwm_bits и pwm_lsb_nanoseconds выглядят не слишком важными, но они критичны — в первую очередь для качества изображения. В частности, pwm_bits определяет количество битов ШИМ, которое задает количество цветовых шагов. Обратной стороной увеличения этого значения является уменьшение частоты обновления светодиодной панели. Улучшить параметр можно, уменьшив настройки pwm_lsb_nanoseconds — если ваши панели поддерживают такие низкие значения. Если собираетесь снимать куб на камеру, лучше увеличить частоту обновления, чтобы все выглядело красиво.
Важно, чтобы Pi непрерывно работал с RGB Bonnet, в противном случае могут появиться артефакты. Для этого рекомендуется зарезервировать целое ядро процессора.
В проекте можно найти cpu-stats-gl.cpp, чтобы использовать это в собственном проекте. Для использования потребуются библиотеки g++ -g -o cpu-stats-gl cpu-stats-gl.cpp -std=c++11 -lbrcmEGL -lbrcmGLESv2 -I/opt/vc/include -L/opt/vc/lib -Lrpi-rgb-led-matrix/lib -lrgbmatrix -lrt -lm -lpthread -lstdc++ -Irpi-rgb-led-matrix/include/. Ну а для того, чтобы добавить поддержку OpenGl, стоит воспользоваться инструкциями от Matus Novak.
Шейдер OpenGl
Хорошо, на этом этапе полностью готово «железо», плюс важный код для управления панелями. В частности, уже можно выводить текст, изображения и гифки. Но для красочной визуализации необходимо добавить OpenGL.
Анимация, которая отображает статус процессора, реализуется путем фрагментного шейдера, т.е. небольшого участка кода, который работает параллельно с «коллегами». Такие участки нужны для каждого пикселя панели.
Чтобы правильно спроецировать изображение на куб, автор визуализирует три пары треугольников, каждый из которых покрывает одну грань куба. Дело в том, что если вы смотрите на куб как на трехмерный объект и хотите показать двухмерную форму, такую как круг, вы можете назначить координаты воображаемого двухмерного холста перед вашим лицом на каждый край куба.
Если мы теперь «развернем» куб в прямоугольный массив пикселей, который мы фактически адресуем, мы можем покрыть этот массив несколькими треугольниками. Мы также можем сопоставить координаты «виртуального холста» с каждой вершиной, чтобы получить отображение координат нашего холста на фактические пиксели в массиве панели.
Для шейдеров это просто — нужно предоставить координаты холста для каждой вершины в качестве дополнительного буфера массива для графического процессора, позволив ему интерполировать эти координаты для каждого пикселя.
Получаем статус процессора
Информацию о режиме работы процессора можно получить по протоколу UDP скриптом на питоне.
#!/usr/bin/python3
import psutil
import socket
import time
TARGET_IP="192.168.2.45"
TARGET_PORT=1234
while True:
temperature = 0.0
time.sleep(0.5)
temperature += psutil.sensors_temperatures()["k10temp"][0].current
time.sleep(0.5)
temperature += psutil.sensors_temperatures()["k10temp"][0].current
time.sleep(0.5)
temperature += psutil.sensors_temperatures()["k10temp"][0].current
time.sleep(0.5)
temperature += psutil.sensors_temperatures()["k10temp"][0].current
time.sleep(0.5)
temperature += psutil.sensors_temperatures()["k10temp"][0].current
temperature /= 5.0
cores = psutil.cpu_percent(percpu=True)
out = str(temperature) + "," + ",".join(map(str, sorted(cores, reverse=True)))
socket.socket(socket.AF_INET, socket.SOCK_DGRAM).sendto(out.encode("utf-8"), (TARGET_IP, TARGET_PORT))
На ПК автора скрипт запускается автоматически, для работы используется статический IP, зарезервированный под светодиодный куб.
На этом этапе все должно работать так, как и задумано.
Понравился ли вам этот проект? Возможно, вы разрабатывали нечто похожее или, наоборот, уникальное? Расскажите об этом в комментариях.
Kidar
Много лет назад делал многопроцессорный светодиодный куб, который показывает время.