14.2.2.2. Criar uma imagem ROMFS¶
Uma imagem ROMFS é um sistema de ficheiros residente em flash, de leitura apenas, que o runtime monta automaticamente em /rom. Resolve o problema dos recursos com que a página anterior terminou: ficheiros de modelos de machine learning, tabelas de etiquetas, configuração JSON, modelos de imagem – qualquer coisa que a aplicação abre e lê mas nunca escreve – entra na compilação sem pagar o custo de ser incorporada como literais Python.
Três aspetos fazem da ROMFS a ferramenta certa para recursos expedidos:
O sistema de ficheiros é parte da imagem de firmware. Os utilizadores finais não podem apagar um ficheiro de
/rom, editá-lo nem substituí-lo pelo seu.Os ficheiros em
/romsão acessíveis no local. Consumidores como o módulomla carregar um ficheiro de modelo obtêm uma vista direta para a flash sem cópia em RAM – um modelo de vários megabytes em/rom«carrega» essencialmente de graça, enquanto o mesmo ficheiro em/sdcardé lido para RAM no momento do carregamento e fica lá durante o tempo de vida da referência. Oopen()comum +readcopia a pedido: cada chamadaread(n)copianbytes da flash para RAM no momento da chamada, sendo que umread()simples pede o ficheiro inteiro./rome/rom/libsão adicionados asys.pathno arranque. Os pacotes Python colocados na imagem são importáveis pelo nome; nada de especial no local de chamada.
14.2.2.2.1. Criar uma imagem¶
As imagens ROMFS são criadas, editadas e gravadas através do IDE. Utilize-o como fonte de verdade para o conteúdo de cada partição ROMFS expedida.
O motivo pelo qual isto é importante: os ficheiros de modelo vêm com requisitos de alinhamento que o carregador em runtime impõe. Os ficheiros .tflite têm de ser preenchidos para limites de 16 bytes, e o NPU do N6 exige alinhamento de 32 bytes para modelos compilados. O IDE aplica esse preenchimento automaticamente quando escreve a imagem. Ferramentas que percorrem a árvore de código-fonte sem aplicar o preenchimento – mpremote romfs em particular – produzem uma imagem que monta corretamente mas cujos modelos falham na primeira chamada de inferência.
O editor ROMFS do IDE é uma vista interativa do conteúdo da imagem. Ficheiros e pastas podem ser adicionados, renomeados e eliminados em memória; guardar escreve o resultado como um ficheiro .img pronto a gravar. Uma estrutura típica para uma aplicação que expede um modelo junto com alguns recursos e um pacote Python tem este aspeto:
model.tflite
labels.txt
config.json
templates/
calibration.jpg
lib/
mylib/
__init__.py
helpers.py
Dica
Tanto o IDE como o mpremote compilam cruzadamente ficheiros .py para bytecode .mpy ao inseri-los numa imagem ROMFS, pelo que a câmara os importa sem pagar o custo de análise no momento do carregamento. Os ficheiros de código-fonte no editor ficam como .py; a imagem contém .mpy.
Depois de a imagem ser gravada, a árvore é visível a partir do MicroPython em /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. A maior parte da aplicação reside em ROMFS¶
A ROMFS é o lugar certo para quase tudo o que uma aplicação expede: as bibliotecas que importa, os ficheiros de modelo que carrega, a configuração que lê, qualquer recurso cuja saída veio de uma ferramenta de compilação que emite uma árvore de ficheiros (conversores de modelos, pipelines de imagem, empacotadores de recursos) e – importantly – o próprio código da aplicação.
O lado dos módulos congelados deve permanecer pequeno: boot.py para configuração pré-REPL, main.py como ponto de entrada leve, e apenas as bibliotecas que a câmara genuinamente não consegue arrancar sem. Tudo o resto vai para a ROMFS, onde iterar significa guardar um novo .img do IDE e regravar – sem necessidade de recompilar o firmware, sem precisar de ter uma toolchain disponível.
O padrão que emerge é um main.py que não faz nada mais do que delegar para a aplicação residente em ROMFS:
# main.py (frozen)
import app
app.run()
# /rom/app/__init__.py (in ROMFS)
def run():
...
Uma alteração ao app é uma edição à ROMFS e uma regravação. A compilação do firmware mantém-se para o tempo de vida do produto a menos que algo no lado congelado realmente precise de mudar.