14.1.1.3. Simulatori#

Due valori di TARGET compilano il firmware per essere eseguito all’interno di un simulatore sul tuo host, senza hardware collegato. Esistono affinché il firmware possa essere eseguito e testato ovunque.

TARGET

Core

NPU

Simulatore

MPS2_AN500

Cortex-M7

None

QEMU

MPS3_AN547

Cortex-M55

Ethos-U55 (256 MACs)

Arm FVP – Corstone SSE-300

MPS2_AN500 è il target Cortex-M7 di base senza NPU. Viene eseguito sotto QEMU, che è veloce da avviare ed è il modo leggero per esercitare il codice indipendente dalla piattaforma e la suite di test.

MPS3_AN547 è un Cortex-M55 con la NPU Ethos-U55, eseguito sui Fast Models di Arm – l’FVP, che modella il sottosistema di riferimento Corstone SSE-300. Questo è il target per esercitare la NPU e il percorso del modello ML in simulazione.

Entrambi forniscono il filesystem ROM e abbondante RAM (e la NPU sull’M55), così gli script di visione e ML vengono eseguiti senza modifiche.

Non c’è un sensore reale, ma il modulo csi funziona comunque con uno virtuale – csi.CSI.snapshot() restituisce un pattern di test sintetico e animato (una scacchiera scorrevole in scala di grigi, un gradiente in RGB565), non una scena dal vivo. Per elaborare contenuti di immagini reali, caricali invece da un file: un image.Image da una fixture nel filesystem ROM, oppure uno stream image.ImageIO per fotogrammi registrati.

14.1.1.3.1. Compilazione ed esecuzione#

Ogni simulatore è uno strumento host che installi tu stesso. Compili un target come qualsiasi altro (vedi Compilazione del firmware), poi lo esegui con run sotto il simulatore corrispondente – run compila l’immagine ROMFS, avvia il firmware e lo lascia in esecuzione con una connessione seriale a cui puoi collegarti.

14.1.1.3.1.1. MPS2_AN500 (QEMU)#

QEMU è disponibile nella maggior parte dei gestori di pacchetti come emulatore di sistema Arm:

  • Linux (Debian / Ubuntu) – installalo con apt:

    sudo apt install qemu-system-arm
    
  • macOS – installalo con Homebrew:

    brew install qemu
    

Poi compila ed esegui il target:

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

14.1.1.3.1.2. MPS3_AN547 (Arm FVP)#

L’FVP è la Fixed Virtual Platform di Arm per il Corstone SSE-300, distribuita come parte di Arm Virtual Hardware. È disponibile solo per Linux – su un Mac, usa invece il target QEMU sopra.

Scarica il bundle, estrailo e metti la sua directory bin/ nel tuo PATH:

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"

L’FVP necessita anche delle librerie Python dell’SDK su LD_LIBRARY_PATH quando viene eseguito. Esportalo una volta per shell dalla radice del repo – leggere SDK_VERSION lo mantiene corretto man mano che il repo aggiorna l’SDK fissato:

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

Poi compila ed esegui il target:

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

14.1.1.3.2. Esecuzione della suite di test#

I test unitari risiedono in scripts/unittest/tests/, con le loro immagini di fixture e i dati in scripts/unittest/data/. Vengono eseguiti con mpremote, che monta scripts/unittest/ sul simulatore in esecuzione ed esegue il suo run.py.

Il collegamento al simulatore è lento con mpremote standard, quindi usa la copia inclusa nel repo con la patch seriale applicata (applicala una volta):

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

Per MPS2_AN500 sotto QEMU, avvia il target – stampa lo pseudo-terminale su cui si trova la sua porta seriale (ad esempio /dev/pts/5):

make TARGET=MPS2_AN500 run

Poi, da un’altra shell, punta il mpremote con la patch a quel dispositivo:

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

Per MPS3_AN547 sotto l’FVP, la porta seriale è invece un socket telnet sulla porta 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 individua ed esegue ogni test, stampando una riga PASSED / FAILED per ciascun test con i tempi e un riepilogo alla fine.

14.1.1.3.3. Aggiungere un test#

I test vengono individuati automaticamente. Per aggiungerne uno, inserisci un file in scripts/unittest/tests/ che definisca una funzione unittest(data_path, temp_path) che restituisce True quando il test passa e False quando fallisce:

# 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)

Gli argomenti data_path e temp_path puntano nei due filesystem che il simulatore vede mentre la suite è in esecuzione:

Path

Backed by

/remote

La directory scripts/unittest/ dell’host, montata in tempo reale sulla connessione mpremote. run.py e i tests/ che individua risiedono qui, quindi aggiungere o modificare un test ha effetto alla prossima esecuzione senza ricompilazione. temp_path è /remote/temp sul dispositivo, che è la scripts/unittest/temp/ del tuo host – una directory scratch scrivibile per i test che creano file.

/rom

Il filesystem ROM di sola lettura della scheda, integrato nell’immagine del firmware da romfs_config.json: le fixture di test (da scripts/unittest/data/) e i modelli ML inclusi. data_path è /rom – raggiungi una fixture come data_path + "/<file>".

Quindi un nuovo test non necessita di ricompilazione, ma una nuova fixture sì: l’immagine ROM è basata su romfs_config.json anziché sui singoli file di dati, quindi forza la ricompilazione facendo touch del romfs_config.json della scheda (oppure make TARGET=<TARGET> clean) ed eseguendo di nuovo.

I valori attesi sono asseriti inline nel test, quindi non c’è un file di output atteso separato da mantenere. Per saltare un test a runtime – ad esempio quando necessita di hardware che il simulatore non modella – solleva un’eccezione il cui messaggio contiene "SKIPPED".