14.1.1.3. Simulatoare#

Două valori TARGET construiesc firmware-ul pentru a rula într-un simulator pe gazda voastră, fără hardware atașat. Există pentru ca firmware-ul să poată fi rulat și testat oriunde.

TARGET

Nucleu

NPU

Simulator

MPS2_AN500

Cortex-M7

None

QEMU

MPS3_AN547

Cortex-M55

Ethos-U55 (256 MACs)

Arm FVP – Corstone SSE-300

MPS2_AN500 este ținta de bază Cortex-M7 fără NPU. Rulează sub QEMU, care pornește rapid și este modalitatea ușoară de a exersa codul independent de platformă și suita de teste.

MPS3_AN547 este un Cortex-M55 cu NPU-ul Ethos-U55, rulat pe Fast Models de la Arm – FVP, care modelează subsistemul de referință Corstone SSE-300. Aceasta este ținta pentru exersarea NPU-ului și a căii modelului ML în simulare.

Ambele oferă sistemul de fișiere ROM și multă RAM (și NPU-ul pe M55), astfel încât scripturile de viziune și ML rulează nemodificate.

Nu există un senzor real, dar modulul csi funcționează totuși cu unul virtual – csi.CSI.snapshot() returnează un model de test sintetic, animat (o tablă de șah derulantă în tonuri de gri, un gradient în RGB565), nu o scenă live. Pentru a procesa conținut de imagine real, încărcați-l dintr-un fișier în schimb: un image.Image dintr-un fixture din sistemul de fișiere ROM, sau un flux image.ImageIO pentru cadre înregistrate.

14.1.1.3.1. Construire și rulare#

Fiecare simulator este o unealtă gazdă pe care o instalați voi înșivă. Construiți o țintă ca oricare alta (vezi Construirea firmware-ului), apoi o run sub simulatorul corespunzător – run construiește imaginea ROMFS, pornește firmware-ul și îl lasă rulând cu o conexiune serială la care vă puteți atașa.

14.1.1.3.1.1. MPS2_AN500 (QEMU)#

QEMU este livrat în majoritatea managerilor de pachete ca emulatorul de sistem Arm:

  • Linux (Debian / Ubuntu) – instalați-l cu apt

    sudo apt install qemu-system-arm
    
  • macOS – instalați-l cu Homebrew:

    brew install qemu
    

Apoi construiți și rulați ținta:

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

14.1.1.3.1.2. MPS3_AN547 (Arm FVP)#

FVP este Fixed Virtual Platform de la Arm pentru Corstone SSE-300, livrat ca parte din Arm Virtual Hardware. Este disponibil doar pentru Linux – pe un Mac, folosiți în schimb ținta QEMU de mai sus.

Descărcați pachetul, extrageți-l și puneți directorul său bin/ în 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"

FVP are de asemenea nevoie de bibliotecile Python ale SDK-ului în LD_LIBRARY_PATH când rulează. Exportați-l o dată per shell din rădăcina depozitului – citirea SDK_VERSION îl menține corect pe măsură ce depozitul actualizează SDK-ul fixat:

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

Apoi construiți și rulați ținta:

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

14.1.1.3.2. Rularea suitei de teste#

Testele unitare se află în scripts/unittest/tests/, cu imaginile lor fixture și datele în scripts/unittest/data/. Sunt rulate cu mpremote, care montează scripts/unittest/ pe simulatorul care rulează și execută run.py al acestuia.

Legătura cu simulatorul este lentă cu mpremote standard, așa că folosiți copia inclusă în depozit cu patch-ul serial aplicat (aplicați-l o dată):

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

Pentru MPS2_AN500 sub QEMU, porniți ținta – aceasta afișează pseudo-terminalul pe care se află portul său serial (de exemplu /dev/pts/5):

make TARGET=MPS2_AN500 run

Apoi, dintr-un alt shell, îndreptați mpremote cu patch aplicat către acel dispozitiv:

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

Pentru MPS3_AN547 sub FVP, portul serial este în schimb un socket telnet pe portul 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 descoperă și execută fiecare test, afișând o linie PASSED / FAILED per test cu cronometrare și un rezumat la final.

14.1.1.3.3. Adăugarea unui test#

Testele sunt descoperite automat. Pentru a adăuga unul, plasați un fișier în scripts/unittest/tests/ care definește o funcție unittest(data_path, temp_path) ce returnează True când testul trece și False când eșuează:

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

Argumentele data_path și temp_path indică spre cele două sisteme de fișiere pe care le vede simulatorul în timp ce suita rulează:

Cale

Susținut de

/remote

Directorul scripts/unittest/ al gazdei, montat live peste conexiunea mpremote. run.py și tests/ pe care le descoperă se află aici, așa că adăugarea sau editarea unui test are efect la următoarea rulare fără reconstruire. temp_path este /remote/temp pe dispozitiv, care este scripts/unittest/temp/ al gazdei voastre – un director temporar de lucru pentru testele care creează fișiere.

/rom

Sistemul de fișiere ROM doar-citire al plăcii, integrat în imaginea de firmware din romfs_config.json: fixture-urile de test (din scripts/unittest/data/) și modelele ML incluse. data_path este /rom – ajungeți la un fixture ca data_path + "/<file>".

Așadar un test nou nu necesită reconstruire, dar un fixture nou da: imaginea ROM este cheia după romfs_config.json mai degrabă decât după fișierele de date individuale, așa că forțați reconstruirea atingând romfs_config.json al plăcii (sau make TARGET=<TARGET> clean) și rulând din nou.

Valorile așteptate sunt verificate prin aserțiuni inline în test, așa că nu există un fișier separat de ieșire-așteptată de întreținut. Pentru a sări peste un test la rulare – de exemplu când are nevoie de hardware pe care simulatorul nu îl modelează – ridicați o excepție al cărei mesaj conține "SKIPPED".