14.1.1.3. Simulatoren#

Zwei TARGET-Werte bauen die Firmware so, dass sie innerhalb eines Simulators auf deinem Host läuft, ohne angeschlossene Hardware. Sie existieren, damit die Firmware überall ausgeführt und getestet werden kann.

TARGET

Kern

NPU

Simulator

MPS2_AN500

Cortex-M7

Keine

QEMU

MPS3_AN547

Cortex-M55

Ethos-U55 (256 MACs)

Arm FVP – Corstone SSE-300

MPS2_AN500 ist das Basis-Cortex-M7-Target ohne NPU. Es läuft unter QEMU, das schnell startet und der leichtgewichtige Weg ist, um den plattformunabhängigen Code und die Test-Suite zu durchlaufen.

MPS3_AN547 ist ein Cortex-M55 mit der Ethos-U55-NPU, ausgeführt auf Arms Fast Models – dem FVP, der das Corstone-SSE-300-Referenzsubsystem modelliert. Dies ist das Target, um die NPU und den ML-Modellpfad in der Simulation zu durchlaufen.

Beide stellen das ROM-Dateisystem und reichlich RAM bereit (und die NPU auf dem M55), sodass Vision- und ML-Skripte unverändert laufen.

Es gibt keinen echten Sensor, aber das csi-Modul funktioniert trotzdem gegen einen virtuellen – csi.CSI.snapshot() liefert ein synthetisches, animiertes Testmuster (ein scrollendes Schachbrett in Graustufen, ein Verlauf in RGB565), keine Live-Szene. Um echte Bildinhalte zu verarbeiten, lade sie stattdessen aus einer Datei: ein image.Image aus einer Fixture im ROM-Dateisystem oder einen image.ImageIO-Stream für aufgezeichnete Frames.

14.1.1.3.1. Bauen und ausführen#

Jeder Simulator ist ein Host-Werkzeug, das du selbst installierst. Du baust ein Target wie jedes andere (siehe Die Firmware bauen) und führst es dann mit run unter dem passenden Simulator aus – run baut das ROMFS-Image, bootet die Firmware und lässt sie mit einer seriellen Verbindung laufen, an die du dich anhängen kannst.

14.1.1.3.1.1. MPS2_AN500 (QEMU)#

QEMU wird in den meisten Paketmanagern als Arm-System-Emulator ausgeliefert:

  • Linux (Debian / Ubuntu) – installiere es mit apt:

    sudo apt install qemu-system-arm
    
  • macOS – installiere es mit Homebrew:

    brew install qemu
    

Baue und führe dann das Target aus:

make -j$(nproc) TARGET=MPS2_AN500
make TARGET=MPS2_AN500 run

14.1.1.3.1.2. MPS3_AN547 (Arm FVP)#

Das FVP ist Arms Fixed Virtual Platform für das Corstone SSE-300, ausgeliefert als Teil von Arm Virtual Hardware. Es ist nur für Linux verfügbar – verwende auf einem Mac stattdessen das obige QEMU-Target.

Lade das Bundle herunter, entpacke es und füge sein bin/-Verzeichnis zu deinem PATH hinzu:

wget https://artifacts.tools.arm.com/avh/11.31.28/avh-linux-x86_11.31_28_Linux64.tar.gz
mkdir -p ~/fvp
tar --strip-components=1 -xzf avh-linux-x86_11.31_28_Linux64.tar.gz -C ~/fvp
export PATH="$HOME/fvp/bin:$PATH"

Das FVP benötigt außerdem die Python-Bibliotheken des SDK im LD_LIBRARY_PATH, wenn es läuft. Exportiere ihn einmal pro Shell vom Repo-Stammverzeichnis aus – das Lesen von SDK_VERSION hält ihn korrekt, während das Repo das fest verankerte SDK aktualisiert:

export LD_LIBRARY_PATH="$HOME/openmv-sdk-$(cat SDK_VERSION)/python/lib:$LD_LIBRARY_PATH"

Baue und führe dann das Target aus:

make -j$(nproc) TARGET=MPS3_AN547
make TARGET=MPS3_AN547 run

14.1.1.3.2. Die Test-Suite ausführen#

Die Unit-Tests befinden sich in scripts/unittest/tests/, mit ihren Fixture-Bildern und -Daten in scripts/unittest/data/. Sie werden mit mpremote ausgeführt, das scripts/unittest/ in den laufenden Simulator einhängt und dessen run.py ausführt.

Die Simulator-Verbindung ist mit dem Standard-mpremote langsam, verwende daher die im Repo mitgelieferte Kopie mit angewendetem Serial-Patch (wende ihn einmal an):

patch -N -p1 -d lib/micropython < tools/mpremote-qemu-serial.patch

Für MPS2_AN500 unter QEMU starte das Target – es gibt das Pseudo-Terminal aus, an dem sich sein serieller Port befindet (zum Beispiel /dev/pts/5):

make TARGET=MPS2_AN500 run

Richte dann aus einer anderen Shell das gepatchte mpremote auf dieses Gerät:

python3 lib/micropython/tools/mpremote/mpremote.py connect /dev/pts/5 \
    mount scripts/unittest/ run scripts/unittest/run.py

Für MPS3_AN547 unter dem FVP ist der serielle Port stattdessen ein Telnet-Socket auf Port 5555:

make TARGET=MPS3_AN547 run
python3 lib/micropython/tools/mpremote/mpremote.py connect socket://localhost:5555 \
    mount scripts/unittest/ run scripts/unittest/run.py

run.py findet und führt jeden Test aus und gibt pro Test eine PASSED / FAILED-Zeile mit Zeitangabe sowie am Ende eine Zusammenfassung aus.

14.1.1.3.3. Einen Test hinzufügen#

Tests werden automatisch gefunden. Um einen hinzuzufügen, lege eine Datei in scripts/unittest/tests/ ab, die eine Funktion unittest(data_path, temp_path) definiert, die True zurückgibt, wenn der Test besteht, und False, wenn er fehlschlägt:

# scripts/unittest/tests/circles.py
def unittest(data_path, temp_path):
    import image

    img = image.Image(data_path + "/shapes.ppm", copy_to_fb=True)
    circles = img.find_circles(threshold=5000, x_margin=30, y_margin=30, r_margin=30)
    return len(circles) == 1 and circles[0][0:] == (118, 56, 22, 5856)

Die Argumente data_path und temp_path verweisen in die zwei Dateisysteme, die der Simulator sieht, während die Suite läuft:

Pfad

Gestützt durch

/remote

Das scripts/unittest/-Verzeichnis des Hosts, live über die mpremote-Verbindung eingehängt. run.py und die tests/, die es findet, befinden sich hier, sodass das Hinzufügen oder Bearbeiten eines Tests beim nächsten Lauf ohne Neubau wirksam wird. temp_path ist /remote/temp auf dem Gerät, was dem scripts/unittest/temp/ deines Hosts entspricht – ein beschreibbares Scratch-Verzeichnis für Tests, die Dateien erstellen.

/rom

Das schreibgeschützte ROM-Dateisystem des Boards, aus romfs_config.json in das Firmware-Image eingebaut: die Test-Fixtures (aus scripts/unittest/data/) und die mitgelieferten ML-Modelle. data_path ist /rom – erreiche eine Fixture als data_path + "/<file>".

Ein neuer Test benötigt also keinen Neubau, eine neue Fixture jedoch schon: Das ROM-Image ist an romfs_config.json gebunden statt an die einzelnen Datendateien, also erzwinge den Neubau, indem du die romfs_config.json des Boards berührst (oder make TARGET=<TARGET> clean) und es erneut ausführst.

Erwartete Werte werden inline im Test geprüft, sodass es keine separate Datei mit erwarteter Ausgabe zu pflegen gibt. Um einen Test zur Laufzeit zu überspringen – zum Beispiel, wenn er Hardware benötigt, die der Simulator nicht modelliert – löse eine Exception aus, deren Nachricht "SKIPPED" enthält.