Bỏ qua, đến nội dung chính
Nastrotek
Bài viếtEmbedded UI

Cách hiển thị GIF biểu cảm trên ESP32 bằng LVGL

Hướng dẫn ngắn để đưa GIF biểu cảm vào firmware ESP32: chuyển GIF thành asset, bật LV_USE_GIF, chọn lưu trong flash hoặc filesystem và hiển thị bằng lv_gif.

Chia sẻ

LinkedInFacebookX
Real ESP32 display prototype running an LVGL interface during development

Trong bài này, mình sẽ cùng bạn đi từ khâu chuẩn bị GIF đến lúc kiểm tra bộ nhớ và hiển thị animation ổn định trên ESP32.

GIF là một cách nhanh để làm giao diện nhúng có cảm xúc hơn: một khuôn mặt vui, mắt chớp, trạng thái đang nghĩ, hoặc phản hồi nhỏ khi robot nhận lệnh. Với ESP32 và LVGL, phần khó không nằm ở việc gọi widget, mà là chuẩn bị asset đúng cách và không làm firmware thiếu RAM.

Bài này ghi lại luồng làm việc gọn: chuẩn bị GIF, bật decoder, chọn nơi lưu, rồi hiển thị bằng lv_gif.

Luồng tổng quát

Với một GIF biểu cảm, bạn thường có hai cách đưa vào firmware:

  • Chuyển GIF thành C array rồi build thẳng vào app.
  • Giữ file .gif trong filesystem, ví dụ SPIFFS, LittleFS hoặc thẻ SD, rồi đưa đường dẫn cho LVGL.

Cách đầu đơn giản khi số lượng animation ít và muốn mọi thứ nằm trong binary. Cách thứ hai hợp hơn khi có nhiều biểu cảm, muốn thay asset mà không build lại toàn bộ firmware, hoặc muốn chia bộ GIF theo pack.

Bật GIF trong LVGL

Trong lv_conf.h, bật GIF widget:

#define LV_USE_GIF 1

Theo tài liệu LVGL, lv_gif dùng GIF decoder để phát GIF động. Sau khi bật cấu hình này, bạn có thể tạo widget bằng lv_gif_create() và đặt nguồn bằng lv_gif_set_src().

Cách 1: nhúng GIF vào flash dưới dạng C array

Nếu muốn GIF đi cùng firmware, hãy chuyển file .gif thành asset C. Với LVGL, hướng phổ biến là dùng script converter của LVGL và để color format ở dạng raw:

python ./scripts/LVGLImage.py --cf RAW --ofmt C -o . --name mochi_smile mochi-smile.gif

Sau đó khai báo và hiển thị:

LV_IMAGE_DECLARE(mochi_smile);

void show_mochi_smile(void)
{
    lv_obj_t * gif = lv_gif_create(lv_screen_active());
    lv_gif_set_color_format(gif, LV_COLOR_FORMAT_RGB565);
    lv_gif_set_src(gif, &mochi_smile);
    lv_obj_center(gif);
}

Nếu GIF có nền trong suốt, LV_COLOR_FORMAT_ARGB8888 giữ alpha tốt hơn, nhưng tốn RAM hơn. Với nhiều màn TFT RGB565, dùng LV_COLOR_FORMAT_RGB565 có thể giảm bước chuyển đổi màu và nhẹ hơn cho ESP32. Nên gọi lv_gif_set_color_format() trước lv_gif_set_src() để tránh cấp phát framebuffer mặc định rồi lại đổi sau.

Cách 2: lưu GIF trong filesystem

Khi GIF nằm trong SPIFFS, LittleFS hoặc SD card, bạn truyền đường dẫn file cho lv_gif_set_src():

void show_mochi_eyes(void)
{
    lv_obj_t * gif = lv_gif_create(lv_screen_active());
    lv_gif_set_color_format(gif, LV_COLOR_FORMAT_RGB565);
    lv_gif_set_src(gif, "S:/emoji/mochi-eyes.gif");
    lv_obj_center(gif);
}

Điểm quan trọng là LVGL phải có filesystem driver tương ứng. Nếu driver chưa được đăng ký, widget sẽ không mở được file dù đường dẫn nhìn có vẻ đúng. Với ESP-IDF, phần này thường nằm ở lớp mount partition và bridge sang lv_fs_drv.

RAM là phần cần tính trước

GIF động không chỉ là vài byte ảnh trong flash. LVGL cần RAM cho decoder và framebuffer của frame hiện tại. Tài liệu LVGL ghi chú công thức gần đúng là khoảng 25 kB cộng thêm (pixel_size + 1) x width x height byte.

Ví dụ một GIF 128x128:

  • RGB565: khoảng 25 kB + 3 x 128 x 128, tức gần 74 kB.
  • ARGB8888: khoảng 25 kB + 5 x 128 x 128, tức hơn 106 kB.

Con số thực tế còn phụ thuộc cấu hình LVGL, heap, driver màn hình và task khác trong firmware. Nhưng nó đủ để nhắc một điều: với ESP32 nhỏ, đừng bắt đầu bằng GIF quá lớn.

Gợi ý chuẩn bị GIF biểu cảm

Một pipeline đơn giản cho robot face UI:

  • Thiết kế hoặc chọn GIF ở kích thước đúng với vùng hiển thị, ví dụ 128x128 hoặc 240x240.
  • Giảm số frame nếu animation không cần quá mượt.
  • Giảm số màu nếu phong cách hình ảnh cho phép.
  • Test từng GIF riêng trước khi load cả bộ biểu cảm.
  • Đặt tên file theo trạng thái, ví dụ idle.gif, happy.gif, thinking.gif, sleepy.gif.

Nếu đang thử giao diện cho Mochi hoặc robot nhỏ, bạn có thể bắt đầu bằng các bộ emoji GIF đang chia sẻ trên Nastrotek như Smile 3D Emoji GIF Pack, Eyes Emoji GIF Pack, Pepe Emoji GIF Pack, hoặc Shiba GIF Pack.

Một ví dụ đổi biểu cảm

Thay vì tạo nhiều widget GIF chồng lên nhau, bạn có thể giữ một widget và đổi source theo trạng thái:

static lv_obj_t * face_gif;

void face_ui_create(void)
{
    face_gif = lv_gif_create(lv_screen_active());
    lv_gif_set_color_format(face_gif, LV_COLOR_FORMAT_RGB565);
    lv_obj_center(face_gif);
}

void face_ui_set_idle(void)
{
    lv_gif_set_src(face_gif, "S:/emoji/idle.gif");
}

void face_ui_set_happy(void)
{
    lv_gif_set_src(face_gif, "S:/emoji/happy.gif");
}

Với asset C array, ý tưởng tương tự, chỉ khác source là con trỏ tới image descriptor thay vì đường dẫn file.

Lỗi dễ gặp

  • Quên bật LV_USE_GIF.
  • Dùng file path nhưng chưa đăng ký filesystem driver cho LVGL.
  • GIF quá lớn so với RAM còn lại.
  • Dùng ARGB8888 cho mọi trường hợp dù màn hình không cần alpha.
  • Đổi source liên tục trong nhiều task khác nhau mà không đồng bộ với thread/task LVGL.
  • GIF có kích thước lớn hơn giới hạn LV_GIF_MAX_WIDTH hoặc LV_GIF_MAX_HEIGHT trong lv_conf.h.

Kết luận

Để hiển thị GIF biểu cảm trên ESP32 bằng LVGL, hãy bắt đầu nhỏ: bật LV_USE_GIF, thử một GIF 128x128, chọn giữa C array và filesystem, rồi đo RAM trước khi mở rộng thành nhiều biểu cảm. Khi pipeline đã ổn, các bộ Emoji trên Nastrotek có thể trở thành nguồn asset nhanh để thử nghiệm robot face UI mà không phải tự vẽ mọi thứ từ đầu.

Tham khảo

Chia sẻ

LinkedInFacebookX

Tiếp tục khám phá

Đọc tiếp

Bài viết liên quan

Xem thêm trong Bài viết

Nastrotek sử dụng cookie để phân tích truy cập và cá nhân hóa quảng cáo, giúp hiểu cách website được sử dụng. Bạn có thể chấp nhận hoặc từ chối các cookie không thiết yếu.