14.2.2.2. Ein ROMFS-Image erstellen¶
Ein ROMFS-Image ist ein im Flash residentes, schreibgeschütztes Dateisystem, das die Laufzeitumgebung automatisch unter /rom einhängt. Es löst das Asset-Problem, mit dem die vorherige Seite endete: Modelldateien für maschinelles Lernen, Label-Tabellen, JSON-Konfiguration, Bildvorlagen – alles, was die Anwendung öffnet und liest, aber nie schreibt – gelangt in den Build, ohne den Preis dafür zu zahlen, als Python-Literale eingebettet zu werden.
Drei Dinge machen ROMFS zum richtigen Werkzeug für ausgelieferte Assets:
Das Dateisystem ist Teil des Firmware-Images. Endnutzer können keine Datei aus
/romlöschen, eine bearbeiten oder durch eine eigene ersetzen.Dateien in
/romsind an Ort und Stelle zugänglich. Konsumenten wie dasml-Modul, das eine Modelldatei lädt, erhalten eine direkte Sicht in den Flash ohne RAM-Kopie – ein mehrere Megabyte großes Modell auf/rom„lädt“ im Grunde kostenlos, wo dieselbe Datei auf/sdcardbeim Laden in den RAM eingelesen wird und dort für die Lebensdauer der Referenz verbleibt. Gewöhnlichesopen()+readkopiert bei Bedarf: Jederread(n)-Aufruf kopiertnBytes vom Flash in den RAM im Moment des Aufrufs, wobei ein nacktesread()die gesamte Datei anfordert./romund/rom/libwerden beim Booten zusys.pathhinzugefügt. In das Image gelegte Python-Pakete sind über ihren Namen importierbar; an der Aufrufstelle ist nichts Besonderes nötig.
14.2.2.2.1. Ein Image erstellen¶
ROMFS-Images werden über die IDE erstellt, bearbeitet und geflasht. Verwenden Sie sie als Single Source of Truth für den Inhalt jeder ausgelieferten ROMFS-Partition.
Der Grund, warum das wichtig ist: Modelldateien kommen mit Ausrichtungsanforderungen, die der Loader zur Laufzeit durchsetzt. .tflite-Dateien müssen auf 16-Byte-Grenzen aufgefüllt werden, und die NPU des N6 erfordert eine 32-Byte-Ausrichtung für kompilierte Modelle. Die IDE wendet diese Auffüllung automatisch an, wenn sie das Image schreibt. Werkzeuge, die den Quellbaum durchlaufen, ohne die Auffüllung anzuwenden – insbesondere mpremote romfs – erzeugen ein Image, das sauber einhängt, dessen Modelle aber beim ersten Inferenzaufruf fehlschlagen.
Der ROMFS-Editor der IDE ist eine interaktive Ansicht des Image-Inhalts. Dateien und Ordner können im Speicher hinzugefügt, umbenannt und gelöscht werden; das Speichern schreibt das Ergebnis als zum Flashen bereite .img-Datei aus. Eine typische Struktur für eine Anwendung, die ein Modell zusammen mit einigen Assets und einem Python-Paket ausliefert, sieht so aus:
model.tflite
labels.txt
config.json
templates/
calibration.jpg
lib/
mylib/
__init__.py
helpers.py
Tipp
Sowohl die IDE als auch mpremote cross-kompilieren .py-Dateien auf dem Weg in ein ROMFS-Image zu .mpy-Bytecode, sodass die Kamera sie importiert, ohne beim Laden die Parse-Kosten zu zahlen. Quelldateien im Editor bleiben .py; das Image enthält .mpy.
Sobald das Image geflasht ist, ist der Baum von MicroPython aus unter /rom/ sichtbar:
>>> 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. Der Großteil der Anwendung liegt in ROMFS¶
ROMFS ist das richtige Zuhause für fast alles, was eine Anwendung ausliefert: die Bibliotheken, die sie importiert, die Modelldateien, die sie lädt, die Konfiguration, die sie liest, jedes Asset, dessen Ausgabe von einem Build-Werkzeug stammt, das einen Dateibaum ausgibt (Modellkonverter, Bild-Pipelines, Asset-Packer), und – ganz wichtig – den Anwendungscode selbst.
Die Seite der eingefrorenen Module sollte klein bleiben: boot.py für die Einrichtung vor der REPL, main.py als schlanker Einstiegspunkt und nur die Bibliotheken, ohne die die Kamera wirklich nicht booten kann. Alles andere kommt in ROMFS, wo das Iterieren darüber ein frisches, aus der IDE gespeichertes und neu geflashtes .img bedeutet – kein Firmware-Neubau erforderlich, keine Toolchain zur Hand nötig.
Das Muster, das sich daraus ergibt, ist eine main.py, die nichts tut, außer in die in ROMFS residente Anwendung zu delegieren:
# main.py (frozen)
import app
app.run()
# /rom/app/__init__.py (in ROMFS)
def run():
...
Eine Änderung an app ist eine ROMFS-Bearbeitung und ein Neu-Flashen. Der Firmware-Build bleibt für die Lebensdauer des Produkts unverändert, es sei denn, auf der eingefrorenen Seite muss sich tatsächlich etwas ändern.