LVGL kontra rysowanie własne: dlaczego kreatory GUI wygrywają w produkcji
Opublikowano na Lopaka.app — bezpłatnym internetowym kreatorze GUI LVGL dla deweloperów embedded
Wprowadzenie
Jeśli budujesz GUI dla wyświetlacza embedded, stajesz przed fundamentalną decyzją: użyć frameworka takiego jak LVGL czy napisać własny kod rysowania?
Ta debata ciągle wraca w społecznościach embedded. Z jednej strony puryści twierdzą, że rysowanie własne daje maksymalną kontrolę i minimalny narzut. Z drugiej pragmatycy wskazują, że wynajdywanie koła na nowo to straszne wykorzystanie czasu inżynierskiego.
Ostatni rok spędziłem na budowaniu Lopaka — wizualnego kreatora GUI dla LVGL — i obserwowaniu, jak dziesiątki zespołów wypuszczają z nim produkty. Dane są jasne, ale odpowiedź jest bardziej niuansowa, niż możesz się spodziewać.
W tym wpisie rozbiorę prawdziwe kompromisy między LVGL a rysowaniem własnym, podzielę się benchmarkami wydajności i powiem ci dokładnie, kiedy używać każdego podejścia.
Czym jest LVGL?
LVGL (Light and Versatile Graphics Library) to najpopularniejsza otwarta biblioteka graficzna dla systemów embedded. Zapewnia:
- Widżety: przyciski, etykiety, suwaki, wykresy, mierniki, klawiatury i ponad 35 kolejnych
- Silniki układu: układy Flexbox i siatki (tak, jak CSS)
- System stylów: style podobne do CSS ze stanami, przejściami i dziedziczeniem
- Obsługę wejścia: dotyk, enkoder, klawiaturę, przyciski
- Animacje: wbudowany silnik animacji z funkcjami easing
- Zarządzanie pamięcią: zoptymalizowane pod MCU z zaledwie 32 KB RAM
Działa na wszystkim, od ESP32 po STM32 i Raspberry Pi, i jest na licencji MIT.
Czym jest rysowanie własne?
Rysowanie własne oznacza, że piszesz własny kod, żeby renderować piksele na wyświetlaczu:
// Custom drawing approach
tft.fillScreen(TFT_BLACK);
tft.drawString("Temperature", 10, 10);
tft.drawNumber(25, 10, 30);
tft.drawRect(10, 60, 300, 40, TFT_WHITE);
// ... repeat for every element, every frameObsługujesz wszystko: pozycjonowanie, odrysowywanie, wykrywanie wejścia, zarządzanie stanem, animacje.
Porównanie bezpośrednie
Czas tworzenia
| Metryka | LVGL | Rysowanie własne |
|---|---|---|
| Prosty ekran (3-5 elementów) | 15-30 min | 1-2 godziny |
| Złożony ekran (ponad 10 elementów) | 1-2 godziny | 4-8 godzin |
| Aplikacja wieloekranowa (5 ekranów) | 4-6 godzin | 20-40 godzin |
| Dodawanie animacji | 10 min | 2-4 godziny |
| Dodawanie wejścia dotykowego | 5 min | 1-2 godziny |
Zwycięzca: LVGL z ogromną przewagą.
Z wizualnym kreatorem takim jak Lopaka te czasy spadają jeszcze bardziej — większość prostych ekranów zajmuje poniżej 10 minut na zaprojektowanie i wyeksportowanie.
Utrzymywalność kodu
Podejście LVGL:
// Clear, semantic code
lv_obj_t *temp_label = lv_label_create(lv_scr_act());
lv_label_set_text(temp_label, "25°C");
lv_obj_align(temp_label, LV_ALIGN_CENTER, 0, -20);
// Easy to modify
void update_temp(float value) {
lv_label_set_text_fmt(temp_label, "%.1f°C", value);
}Podejście rysowania własnego:
// Manual pixel management
void draw_temp(int x, int y, float value) {
char buf[16];
sprintf(buf, "%.1f°C", value);
// Must clear old text first
tft.fillRect(x-5, y-5, 80, 20, TFT_BLACK);
tft.drawString(buf, x, y);
}Zwycięzca: LVGL. Semantyczny kod widżetów sam się dokumentuje. Kod rysowania własnego wymaga komentarzy, żeby wyjaśnić, co robi każdy prostokąt.
Wydajność
Tu robi się ciekawie. Zróbmy benchmark na ESP32 z wyświetlaczem ILI9341:
| Metryka | LVGL | Rysowanie własne |
|---|---|---|
| Zużycie RAM (prosty interfejs) | 15-25 KB | 2-5 KB |
| Zużycie RAM (złożony interfejs) | 40-80 KB | 10-20 KB |
| Rozmiar flash | 80-120 KB | 10-30 KB |
| Liczba klatek (prosty interfejs) | 30-60 fps | 50-60 fps |
| Liczba klatek (złożony interfejs) | 20-40 fps | 30-50 fps |
| Zużycie CPU (bezczynność) | 2-5% | 0-1% |
| Zużycie CPU (aktywność) | 15-30% | 5-15% |
Zwycięzca: rysowanie własne pod względem surowej wydajności, ale różnica jest mniejsza, niż myślisz.
W większości zastosowań wydajność LVGL jest więcej niż wystarczająca. 20-40 fps, które dostajesz na złożonych interfejsach, jest wizualnie gładkie, a zużycie CPU zostawia dużo zapasu na logikę aplikacji.
Gdzie wygrywa rysowanie własne:
- Urządzenia o ultra niskim poborze mocy (czujniki bateryjne, które śpią przez 99% czasu)
- MCU o skrajnie ograniczonych zasobach (poniżej 64 KB RAM)
- Wizualizacja danych z dużą prędkością (oscyloskopy, wykresy w czasie rzeczywistym przy ponad 100 fps)
Gdzie wygrywa LVGL:
- Wszystko z interakcją użytkownika (przyciski, menu, formularze)
- Aplikacje wieloekranowe
- Produkty, które muszą wyglądać profesjonalnie
- Zespoły z więcej niż jednym deweloperem
Doświadczenie tworzenia
To subiektywne, ale ważne. Zapytaj siebie:
- Czy chcesz spędzać czas na unikalnych funkcjach produktu, czy na rysowaniu prostokątów?
- Jak obsłużysz wejście dotykowe? Wykrywanie trafień? Debouncing przycisków?
- A co z nawigacją klawiaturą dla dostępności?
- Jak zaimplementujesz gładkie przejścia między ekranami?
- Kto będzie utrzymywał ten kod, gdy odejdziesz?
Zwycięzca: LVGL. Rozwiązuje problemy, o których jeszcze nawet nie pomyślałeś.
Analiza prawdziwych kosztów
Ujmijmy to w kategoriach biznesowych. Załóż, że deweloper embedded kosztuje 80 USD za godzinę:
| Podejście | Czas tworzenia | Koszt | Bieżące utrzymanie |
|---|---|---|---|
| Rysowanie własne (proste) | 40 godzin | 3200 USD | 400 USD/miesiąc |
| Rysowanie własne (złożone) | 160 godzin | 12 800 USD | 800 USD/miesiąc |
| LVGL (kodowane ręcznie) | 20 godzin | 1600 USD | 200 USD/miesiąc |
| LVGL + Lopaka | 8 godzin | 640 USD | 100 USD/miesiąc |
Wybór narzędzi, który oszczędza najwięcej pieniędzy, to nie ten z najmniejszym plikiem binarnym — to ten, który pozwala zespołowi szybciej wypuszczać produkt.
Kiedy używać każdego podejścia
Używaj rysowania własnego, gdy:
- Masz skrajne ograniczenia zasobów — poniżej 32 KB RAM, poniżej 128 KB flash
- Twój interfejs jest statyczny — jeden ekran, który nigdy się nie zmienia (np. odczyt temperatury)
- Potrzebujesz maksymalnej liczby klatek — oscyloskopy, analizatory logiczne, wykresy w czasie rzeczywistym
- Budujesz bibliotekę, a nie produkt — potrzebujesz zero zależności
- Lubisz to — niektórzy deweloperzy naprawdę lubią pisać kod renderujący
Używaj LVGL, gdy:
- Twój interfejs ma interakcję użytkownika — przyciski, menu, formularze, ekrany ustawień
- Masz wiele ekranów — nawigacja, karty, okna modalne
- Potrzebujesz profesjonalnego wyglądu — dema produktu, urządzenia dla klientów
- Masz harmonogram — wypuść w tygodnie, nie miesiące
- Jesteś zespołem — wielu deweloperów musi pracować nad interfejsem
- Chcesz, żeby dał się utrzymywać — ktoś inny dotknie tego kodu
Podejście hybrydowe
Najmądrzejsze zespoły, z którymi pracuję, używają podejścia hybrydowego:
- LVGL dla głównego interfejsu — menu, ustawienia, ekrany konfiguracji
- Rysowanie własne dla wyspecjalizowanych widoków — wykresy w czasie rzeczywistym, własne wizualizacje
- Lopaka do szybkiego prototypowania — projektuj części LVGL wizualnie, szybko iteruj
// Main screens use LVGL (designed in Lopaka)
lv_obj_t *main_screen = ui_MainScreen_create();
// Specialized view uses custom drawing
lv_obj_t *graph_canvas = lv_canvas_create(lv_scr_act());
lv_canvas_fill_bg(graph_canvas, lv_color_black(), LV_OPA_COVER);
// Custom rendering code for high-speed data visualization
draw_oscilloscope_trace(graph_canvas, samples, num_samples);Daje ci to najlepsze z obu światów: szybkie tworzenie 90% interfejsu i maksymalną kontrolę nad 10%, które jej potrzebuje.
Popularne zastrzeżenia (i dlaczego są błędne)
„LVGL jest za ciężkie”
Minimalna konfiguracja LVGL działa w 32 KB RAM i 80 KB flash. To mniej niż większość szkiców Arduino. Reputacja „ciężkości” pochodzi z domyślnych konfiguracji, które włączają każdą funkcję.
„Potrzebuję kontroli co do piksela”
LVGL daje ci kontrolę co do piksela — możesz ustawić wszystko dokładnie tam, gdzie chcesz. Różnica polega na tym, że nie jesteś zmuszony ręcznie obliczać każdej współrzędnej.
„Własny kod jest wydajniejszy”
Przy surowym renderowaniu tak. Przy pełnym doświadczeniu użytkownika (obsługa wejścia, zarządzanie stanem, animacje, dostępność) LVGL jest dramatycznie wydajniejsze, bo jest już napisane i przetestowane.
„Nie chcę zewnętrznych zależności”
LVGL jest na licencji MIT, ma zero zależności i jest używane w produkcji przez tysiące firm. To najbliżej „braku zależności”, jak możesz być przy bibliotece graficznej.
Podsumowanie
| Kryterium | Zwycięzca |
|---|---|
| Szybkość tworzenia | LVGL |
| Utrzymywalność kodu | LVGL |
| Surowa wydajność | Rysowanie własne |
| Zużycie zasobów | Rysowanie własne |
| Profesjonalny wygląd | LVGL |
| Współpraca zespołowa | LVGL |
| Długoterminowe utrzymanie | LVGL |
| Krzywa uczenia się | Rysowanie własne (początkowo) |
Dla 90% projektów GUI embedded LVGL to właściwy wybór. Kompromis wydajnościowy jest pomijalny w większości zastosowań, a oszczędności czasu tworzenia są ogromne.
Pozostałe 10% — urządzenia o skrajnych ograniczeniach, wizualizacje z dużą prędkością, wyświetlacze statyczne — lepiej obsłuży rysowanie własne.
A przy projektach LVGL? Użycie wizualnego kreatora takiego jak Lopaka sprawia, że decyzja jest jeszcze łatwiejsza. Dostajesz moc LVGL za ułamek czasu tworzenia.
Zasoby
- Lopaka.app — wizualny kreator GUI LVGL
- Dokumentacja LVGL — oficjalna dokumentacja LVGL
- LVGL na GitHubie — kod źródłowy i przykłady
- Discord Lopaka — społeczność i wsparcie
Wciąż się wahasz? Spróbuj zbudować ten sam ekran na oba sposoby i zmierz czas. Myślę, że będziesz zaskoczony.