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.
| Kern | NPU | Simulator |
|---|---|---|---|
| Cortex-M7 | Keine | QEMU |
| 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-armmacOS – 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 |
|---|---|
| Das |
| Das schreibgeschützte ROM-Dateisystem des Boards, aus |
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.