14.2.2.2. Создание образа ROMFS

Образ ROMFS – это доступная только для чтения файловая система, размещённая во флеш-памяти, которую среда выполнения автоматически монтирует в /rom. Он решает проблему ресурсов, на которой закончилась предыдущая страница: файлы моделей машинного обучения, таблицы меток, конфигурация JSON, шаблоны изображений – всё, что приложение открывает и читает, но никогда не записывает – попадает в сборку, не платя за встраивание в виде литералов Python.

Три вещи делают ROMFS правильным инструментом для поставляемых ресурсов:

  • Файловая система является частью образа прошивки. Конечные пользователи не могут удалить файл из /rom, отредактировать его или заменить своим собственным.

  • Файлы в /rom доступны на месте. Потребители, такие как модуль ml, загружающий файл модели, получают прямое представление во флеш-памяти без копии в RAM – многомегабайтная модель в /rom «загружается» по сути бесплатно, тогда как тот же файл на /sdcard считывается в RAM во время загрузки и остаётся там на всё время жизни ссылки. Обычная связка open() + read копирует по запросу: каждый вызов read(n) копирует n байт из флеш-памяти в RAM в момент вызова, а голый read() запрашивает весь файл.

  • /rom и /rom/lib добавляются в sys.path при загрузке. Пакеты Python, помещённые в образ, импортируются по имени; на стороне вызова не требуется ничего особенного.

14.2.2.2.1. Создание образа

Образы ROMFS создаются, редактируются и прошиваются через IDE. Используйте её как источник истины для содержимого каждого поставляемого раздела ROMFS.

Причина, по которой это важно: файлы моделей имеют требования к выравниванию, которые загрузчик во время выполнения принудительно соблюдает. Файлы .tflite должны быть дополнены до границ в 16 байт, а NPU процессора N6 требует выравнивания в 32 байта для скомпилированных моделей. IDE применяет это дополнение автоматически при записи образа. Инструменты, которые обходят дерево исходного кода без применения дополнения – в частности, mpremote romfs – создают образ, который монтируется без проблем, но чьи модели дают сбой при первом же вызове вывода.

Редактор ROMFS в IDE – это интерактивное представление содержимого образа. Файлы и папки можно добавлять, переименовывать и удалять в памяти; сохранение записывает результат в виде файла .img, готового к прошивке. Типичная структура для приложения, которое поставляет модель вместе с некоторыми ресурсами и пакетом Python, выглядит так:

model.tflite
labels.txt
config.json
templates/
    calibration.jpg
lib/
    mylib/
        __init__.py
        helpers.py

Совет

И IDE, и mpremote кросс-компилируют файлы .py в байт-код .mpy на пути в образ ROMFS, поэтому камера импортирует их, не платя за разбор во время загрузки. Исходные файлы в редакторе остаются .py; образ содержит .mpy.

После прошивки образа дерево видно из MicroPython в /rom/:

>>> import os
>>> os.listdir('/rom')
['model.tflite', 'labels.txt', 'config.json', 'templates', 'lib']
>>> import mylib
>>> mylib.helpers
<module 'mylib.helpers' from '/rom/lib/mylib/helpers.mpy'>

14.2.2.2.2. Большая часть приложения живёт в ROMFS

ROMFS – это правильный дом почти для всего, что поставляет приложение: библиотек, которые оно импортирует, файлов моделей, которые оно загружает, конфигурации, которую оно читает, любого ресурса, чей вывод получен из инструмента сборки, генерирующего дерево файлов (конвертеров моделей, конвейеров обработки изображений, упаковщиков ресурсов), и – что важно – самого кода приложения.

Сторона замороженных модулей должна оставаться небольшой: boot.py для настройки перед REPL, main.py как тонкая точка входа и только те библиотеки, без которых камера действительно не может загрузиться. Всё остальное идёт в ROMFS, где итерация над ним – это свежий .img, сохранённый из IDE и перепрошитый – без необходимости пересборки прошивки, без наличия под рукой инструментария для этого.

Возникающий из этого шаблон – это main.py, который не делает ничего, кроме делегирования в приложение, размещённое в ROMFS:

# main.py (frozen)
import app
app.run()

# /rom/app/__init__.py (in ROMFS)
def run():
    ...

Изменение в app – это правка ROMFS и перепрошивка. Сборка прошивки остаётся неизменной на всё время жизни продукта, если только что-то на замороженной стороне действительно не должно измениться.