STM32 з нуля без HAL: Я змусив Luckfox думати: NPU, RetinaFace і перший inference. Частина 9.

Я змусив Luckfox думати: NPU, RetinaFace і перший inference

Серія «STM32 з нуля без HAL» · Частина 9 · Місяць 3


Місяць 3 добігає кінця. За цей час ми розібрали Device Tree, навчили Linux керувати STM32 через UART, і закрили GStreamer — стрімінг з Luckfox працює. Залишилась одна тема яку я відкладав бо вона здавалась складною: NPU.

20 травня я опублікував спецвипуск про TinyML на Pi Pico — там ми запускали нейромережу на мікроконтролері через TFLite Micro. Програмний inference, без спеціалізованого заліза, все на Cortex-M0+. Це було чесно і повільно.

Luckfox Pico Pro — інша історія. RV1106 має окремий апаратний блок для нейромереж — RKNPU. Сьогодні розберемось що це таке, як його запустити, і чому перший очевидний шлях виявився хибним.

Спойлер: до живих координат обличчя з камери в реальному часі ми дійдемо. Але спочатку — граблі.


◆ Що таке NPU і навіщо він потрібен

CPU вміє робити все. Але «все» — це дорого з точки зору енергії і часу. Нейромережа — це мільйони операцій множення матриць. CPU робить їх послідовно, витрачаючи такти і гріючись.

NPU (Neural Processing Unit) — це спеціалізований блок який робить тільки одне: матричні операції. Швидко і з мінімальним енергоспоживанням. Саме тому його ставлять у смартфони, відеокамери, і embedded плати для edge AI.

На RV1106 стоїть RKNPU від Rockchip. Перевіряємо що він живий:

Драйвер версії v0.9.2 від 2023-08-25 — живий. /dev/rknpu є. Але це тільки ядро — userspace частина інша історія.


◆ Знаходимо частини пазлу

Для роботи з NPU потрібні три речі: драйвер (є), runtime бібліотека (librknnmrt.so), і модель (.rknn файл). Шукаємо:

Є — але не там де очікуєш. Стандартний /usr/lib порожній. Бібліотека живе в /oem/usr/lib.

⚠ Якщо будеш шукати через strings /usr/lib/librknnmrt.so — отримаєш No such file or directory. Не лякайся, шукай в /oem/usr/lib.

Перевіряємо версію:

І одразу бачимо в тих самих рядках тривожне:

Rockchip вбудував попередження про версійний конфлікт прямо в бібліотеку. Це натяк — версії драйвера і runtime мають збігатись. Запам’ятовуємо: драйвер v0.9.2, runtime v1.6.0.

Чи знайде її лінкер? Перевіряємо:

Пощастило — наш кастомний Buildroot образ вже має /oem/usr/lib в LD_LIBRARY_PATH. Нічого додатково налаштовувати не треба.

Шукаємо моделі:

Порожньо. Моделей на платі немає. Вони є в SDK на PC — але туди ще дістанемось.


◆ Перша спроба — rk_smart_door. І чому це хибний шлях

В SDK Luckfox є папка project/app/rk_smart_door. Там лежать готові .rknn моделі: detection.rknn, recognition.rknn, headpose.rknn, fas_ir.rknn. Здається — ось воно, бери і запускай.

Відкриваємо CMakeLists.txt і бачимо:

rk_smart_door — це повноцінний продакшн додаток для розумного дверного замка. З UVC, ISP pipeline, RTSP стрімінгом, аудіо детекцією і SmartIR підсвічуванням. 10+ залежностей, збірка тільки в контексті повного SDK build.

Нам не потрібен дверний замок. Нам потрібен мінімальний inference. Йдемо далі.


◆ Правильний шлях — luckfox_pico_rknn_example

Rockchip і LuckfoxTECH мають окремий репозиторій з мінімальними прикладами:

Три приклади. Нас цікавить перший — RetinaFace + FaceNet. RetinaFace детектує обличчя (знаходить bounding box), FaceNet розпізнає (порівнює з еталоном).

Перевіряємо версію бібліотеки в репо:

⚠ Версія 1.6.0 збігається з платою. Але білди різні: репо 2023-12-13, плата 2024-01-17. Той самий мажорний реліз але місяць різниці. Запам’ятовуємо як потенційне джерело проблем — перевіримо при запуску.


◆ Збираємо

CMakeLists бере toolchain з змінної оточення LUCKFOX_SDK_PATH. Встановлюємо і збираємо:

Скрипт запитає інтерактивно:

  1. uclibc або glibc → вибираємо 1 (uclibc — наш Buildroot образ)
  2. який приклад → вибираємо 1 (luckfox_pico_retinaface_facenet)

Зібралось з першого разу. Порівняй з rk_smart_door де треба весь SDK build — різниця відчутна.

Що отримали:

Копіюємо на плату:

⚠ Прапор -o PubkeyAuthentication=no обов’язковий якщо SSH видає Too many authentication failures. Це відбувається коли в ~/.ssh/ накопичилось багато ключів і сервер відхиляє з’єднання до перебору всіх.


◆ Запускаємо. І одразу перший сюрприз

Заходимо на плату і запускаємо:

⚠ Програма очікує три окремі аргументи — не папку і фото. test.jpg це не вхідне зображення для детекції, це еталонне фото для FaceNet (reference face для порівняння). Детекція іде з камери в реальному часі.

Правильний синтаксис:

Але перед запуском — обов’язковий крок.


◆ RkLunch-stop.sh — завжди перед NPU

rkipc — це процес який керує камерою і ISP при звичайному завантаженні. Він тримає /dev/video* і може блокувати доступ до NPU або камери. Завжди зупиняй його перед запуском NPU демо через RkLunch-stop.sh.


◆ NPU живе

Запускаємо з правильними аргументами і наводимо камеру на обличчя:

Моделі завантажились без помилок. Версійного конфлікту не сталось — 1.6.0 з репо і 1.6.0 з плати спрацювали разом.

Камера ініціалізується через rkaiq ISP, і починається детекція:

Кожен рядок — знайдене обличчя:

x1 y1 — верхній лівий кут bounding box. x2 y2 — нижній правий. score — впевненість моделі. Значення 1.1–1.5 означає що модель впевнена.

Детекція стабільна, реальний час. NPU робить те для чого створений.


◆ Що далі — Стаття 10

Зараз програма виводить координати в консоль. У Статті 10 ці координати стануть командами:

«Luckfox думає, STM32 діє» — повний пайплайн.

До речі, поки розбирався з підключенням Luckfox по ethernet — задумався: а як в реальних автономних системах з’єднують vision модулі з мозком? CAN? Automotive Ethernet? Окремий SPI? Якщо є досвід з роботизованих систем або automotive — цікаво почути в коментарях.


◆ Гайд-шпаргалка

Всі команди в одному місці.

На PC:

На платі:

Перевірка NPU і бібліотеки:


Блог серії: nodejs.jdymora.com/category/embedded/stm32
Репозиторій: github.com/pipicosim800-maker/stm32F103

Опубліковано в Linux

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *