Animacja na wyświetlaczu 16x16 | ESP32 CAM

Typ_projektu
Arduino
Zdjecie główne
Krótki opis projektu

Projekt polega na wyświetlaniu animowanej grafiki na matrycy LED, która składa się z 256 diod RGB, ułożonych w formie siatki 16x16 sterowanej przez ESP32-CAM. Dzięki bibliotece Adafruit NeoPixel możliwe jest sterowanie każdym pikselem z osobna, co umożliwia tworzenie dowolnych wzorów i animacji. 

W kodzie zaprogramowano kolejne klatki animacji przez przypisanie kolorów konkretnym pikselom. Animacja odtwarzana jest w pętli, co daje efekt ruchomego obrazu. 

Niezbędne elementy

Ramka SIC PixelArt

Sprzęt

Komputer PC z Arduino IDE

Opis projektu

Inicjalizacja

Na początku programu definiowane są podstawowe parametry, takie jak numer pinu, do którego podłączona jest taśma NeoPixel, oraz liczba diod (w tym przypadku 256, czyli matryca 16x16). Tworzony jest obiekt Adafruit_NeoPixel, który służy do zarządzania wszystkimi diodami RGB. W funkcji setup() wywoływana jest metoda begin(), która inicjuje komunikację z matrycą, oraz show(), dzięki której diody zostają wyłączone i wyzerowane przed rozpoczęciem animacji.

Projektowanie animacji – przygotowanie graficzne

Na etapie planowania animacji kluczowym krokiem było zaprojektowanie wyglądu postaci oraz poszczególnych klatek ruchu. Do tego celu wykorzystaliśmy program graficzny Krita, który pozwala na precyzyjne rysowanie pikselowej grafiki w siatce odpowiadającej rozdzielczości naszej matrycy LED (16x16 pikseli). W pierwszej kolejności stworzyliśmy statyczny wizerunek bohatera – postaci z mieczem. Następnie, bazując na tej sylwetce, opracowaliśmy kolejne klatki animacji, które odwzorowywały jego ruch. Dzięki temu mogliśmy wcześniej zaplanować zarówno dynamikę, jak i estetykę całej sekwencji. Pozwoliło nam to dokładnie rozplanować, które piksele powinny się świecić w danym momencie oraz w jakim kolorze. Przekładanie rysunków z programu Krita na konkretne współrzędne i kolory diod RGB w kodzie Arduino było dzięki temu znacznie łatwiejsze i bardziej intuicyjne. Cały ten proces nie tylko usprawnił realizację projektu, ale również zapewnił spójność graficzną i czytelność animacji, mimo ograniczeń wynikających z niewielkiej rozdzielczości.

Utworzenie własnej animacji

Animacja zrealizowana została w formie pętli w funkcji loop(). Składa się ona z dwudziestu trzech klatek – każda z nich to zestaw instrukcji przypisujących konkretne kolory do wybranych pikseli matrycy. Po ustawieniu kolorów dla jednej klatki, wywoływana jest metoda show(), która aktualizuje stan diod, a następnie krótka pauza (delay) umożliwia widoczność efektu. Dzięki przechodzeniu przez kolejne klatki w zapętleniu, powstaje wrażenie ruchu – w tym przypadku chodzi o przedstawienie bohatera z mieczem.

Użyte kolory

W animacji zastosowano szeroką paletę barw w formacie RGB, co pozwala na szczegółowe odwzorowanie wyglądu postaci. Kolor bordowy RGB(145, 21, 11) został użyty do przedstawienia włosów bohatera. Beżowe odcienie RGB(213, 179, 141) symbolizują skórę postaci. Zieleń RGB(9, 128, 64) symbolizuje spodnie bohatera, a granatowy RGB(33, 11, 145) oraz jasnoniebieski RGB(123, 106, 198) jego koszulkę. Kolor turkusowy RGB(82, 167, 164) został użyty do przedstawienia miecza. Dzięki temu nawet przy ograniczonej rozdzielczości 16x16 uzyskano czytelną i wyrazistą sylwetkę.

Opis poszczególnych funkcji

Funkcja setup() odpowiada za jednorazową inicjalizację matrycy. Funkcja loop() działa nieustannie i odpowiada za odtwarzanie animacji – to tu znajdują się kolejne klatki, które nadają postaci ruch. W każdej klatce funkcje pixels.setPixelColor(index, color) przypisują odpowiedni kolor do konkretnego piksela, a pixels.show() aktualizuje cały obraz na matrycy. Funkcja delay(ms) dodaje przerwę między kolejnymi klatkami, co pozwala widzowi dostrzec animację w odpowiednim tempie.

 

Zdjęcia
wizualizacja z programu Krita
kod programu
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h> 
#endif
#define PIN        15 
#define NUMPIXELS 256
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
#define DELAYVAL 500 
void setup() {
#if defined(__AVR_ATtiny85__) && (F_CPU == 16000000)
  clock_prescale_set(clock_div_1);
#endif
  pixels.begin();
}
void loop() {
  pixels.clear();
  pixels.setPixelColor(43, pixels.Color(159, 54, 45));
  pixels.setPixelColor(42, pixels.Color(159, 54, 45));
  pixels.setPixelColor(52, pixels.Color(159, 54, 45));
  pixels.setPixelColor(53, pixels.Color(159, 54, 45));
  pixels.setPixelColor(54, pixels.Color(159, 54, 45));
  pixels.setPixelColor(55, pixels.Color(159, 54, 45));
  pixels.setPixelColor(74, pixels.Color(159, 54, 45));
  pixels.setPixelColor(73, pixels.Color(203, 167, 145));
  pixels.setPixelColor(72, pixels.Color(203, 167, 145));
  pixels.setPixelColor(66, pixels.Color(128, 186, 187));
  pixels.setPixelColor(85, pixels.Color(159, 54, 45));
  pixels.setPixelColor(86, pixels.Color(203, 167, 145));
  pixels.setPixelColor(87, pixels.Color(203, 167, 145));
  pixels.setPixelColor(92, pixels.Color(128, 186, 187));
  pixels.setPixelColor(107, pixels.Color(133, 116, 197));
  pixels.setPixelColor(106, pixels.Color(133, 116, 197));
  pixels.setPixelColor(105, pixels.Color(46, 27, 147));
  pixels.setPixelColor(104, pixels.Color(46, 27, 147));
  pixels.setPixelColor(103, pixels.Color(46, 27, 147));
  pixels.setPixelColor(100, pixels.Color(128, 186, 187));
  pixels.setPixelColor(115, pixels.Color(133, 116, 197));
  pixels.setPixelColor(116, pixels.Color(133, 116, 197));
  pixels.setPixelColor(117, pixels.Color(133, 116, 197));
  pixels.setPixelColor(118, pixels.Color(46, 27, 147));
  pixels.setPixelColor(119, pixels.Color(46, 27, 147));
  pixels.setPixelColor(120, pixels.Color(46, 27, 147));
  pixels.setPixelColor(121, pixels.Color(46, 27, 147));
  pixels.setPixelColor(122, pixels.Color(128, 186, 187));
  pixels.setPixelColor(140, pixels.Color(203, 167, 145));
  pixels.setPixelColor(139, pixels.Color(203, 167, 145));
  pixels.setPixelColor(138, pixels.Color(46, 27, 147));
  pixels.setPixelColor(137, pixels.Color(46, 27, 147));
  pixels.setPixelColor(136, pixels.Color(46, 27, 147));
  pixels.setPixelColor(135, pixels.Color(46, 27, 147));
  pixels.setPixelColor(134, pixels.Color(203, 167, 145));
  pixels.setPixelColor(133, pixels.Color(203, 167, 145));
  pixels.setPixelColor(147, pixels.Color(203, 167, 145));
  pixels.setPixelColor(148, pixels.Color(203, 167, 145));
  pixels.setPixelColor(149, pixels.Color(46, 27, 147));
  pixels.setPixelColor(150, pixels.Color(46, 27, 147));
  pixels.setPixelColor(151, pixels.Color(46, 27, 147));
  pixels.setPixelColor(152, pixels.Color(46, 27, 147));
  pixels.setPixelColor(153, pixels.Color(203, 167, 145));
  pixels.setPixelColor(154, pixels.Color(203, 167, 145));
  pixels.setPixelColor(171, pixels.Color(25, 134, 76));
  pixels.setPixelColor(170, pixels.Color(25, 134, 76));
  pixels.setPixelColor(169, pixels.Color(25, 134, 76));
  pixels.setPixelColor(168, pixels.Color(25, 134, 76));
  pixels.setPixelColor(167, pixels.Color(25, 134, 76));
  pixels.setPixelColor(166, pixels.Color(25, 134, 76));
  pixels.setPixelColor(180, pixels.Color(25, 134, 76));
  pixels.setPixelColor(181, pixels.Color(25, 134, 76));
  pixels.setPixelColor(182, pixels.Color(25, 134, 76));
  pixels.setPixelColor(183, pixels.Color(25, 134, 76));
  pixels.setPixelColor(184, pixels.Color(25, 134, 76));
  pixels.setPixelColor(185, pixels.Color(25, 134, 76));
  pixels.setPixelColor(186, pixels.Color(25, 134, 76));
  pixels.setPixelColor(204, pixels.Color(25, 134, 76));
  pixels.setPixelColor(203, pixels.Color(25, 134, 76));
  pixels.setPixelColor(202, pixels.Color(25, 134, 76));
  pixels.setPixelColor(201, pixels.Color(25, 134, 76));
  pixels.setPixelColor(200, pixels.Color(25, 134, 76));
  pixels.setPixelColor(199, pixels.Color(25, 134, 76));
  pixels.setPixelColor(198, pixels.Color(25, 134, 76));
  pixels.setPixelColor(197, pixels.Color(25, 134, 76));
  pixels.setPixelColor(211, pixels.Color(25, 134, 76));
  pixels.setPixelColor(212, pixels.Color(25, 134, 76));
  pixels.setPixelColor(213, pixels.Color(25, 134, 76));
  pixels.setPixelColor(216, pixels.Color(25, 134, 76));
  pixels.setPixelColor(217, pixels.Color(25, 134, 76));
  pixels.setPixelColor(218, pixels.Color(25, 134, 76));
  pixels.setPixelColor(236, pixels.Color(203, 167, 145));
  pixels.setPixelColor(235, pixels.Color(203, 167, 145));
  pixels.setPixelColor(230, pixels.Color(203, 167, 145));
  pixels.setPixelColor(229, pixels.Color(203, 167, 145));
  pixels.show();
  delay(50);
Pliki_projektu
Schemat
Youtube
Tagi
animacja miecz wyswietlacz matrycaLED ESP32 ESP32CAM