14.1.1.3. Simuladores#
Dois valores de TARGET compilam o firmware para rodar dentro de um simulador no seu host, sem hardware conectado. Eles existem para que o firmware possa ser executado e testado em qualquer lugar.
| Core | NPU | Simulador |
|---|---|---|---|
| Cortex-M7 | None | QEMU |
| Cortex-M55 | Ethos-U55 (256 MACs) | Arm FVP – Corstone SSE-300 |
MPS2_AN500 é o alvo Cortex-M7 de base, sem NPU. Ele roda sob o QEMU, que é rápido de iniciar e é a forma leve de exercitar o código independente de plataforma e a suíte de testes.
MPS3_AN547 é um Cortex-M55 com a NPU Ethos-U55, executado nos Fast Models da Arm – o FVP, que modela o subsistema de referência Corstone SSE-300. Este é o alvo para exercitar a NPU e o caminho de modelos de ML em simulação.
Ambos fornecem o sistema de arquivos ROM e bastante RAM (e a NPU no M55), de modo que scripts de visão e de ML rodam sem modificação.
Não há sensor real, mas o módulo csi ainda funciona contra um virtual – csi.CSI.snapshot() retorna um padrão de teste sintético e animado (um tabuleiro de xadrez rolante em escala de cinza, um gradiente em RGB565), não uma cena ao vivo. Para processar conteúdo de imagem real, carregue-o de um arquivo: uma image.Image a partir de um fixture no sistema de arquivos ROM, ou um stream image.ImageIO para quadros gravados.
14.1.1.3.1. Compilando e executando#
Cada simulador é uma ferramenta de host que você mesmo instala. Você compila um alvo como qualquer outro (veja Compilando o firmware), depois o executa com run sob o simulador correspondente – o run compila a imagem ROMFS, inicia o firmware e o deixa rodando com uma conexão serial à qual você pode se conectar.
14.1.1.3.1.1. MPS2_AN500 (QEMU)#
O QEMU vem na maioria dos gerenciadores de pacotes como o emulador de sistema Arm:
Linux (Debian / Ubuntu) – instale-o com
apt:sudo apt install qemu-system-armmacOS – instale-o com o Homebrew:
brew install qemu
Depois compile e execute o alvo:
make -j$(nproc) TARGET=MPS2_AN500
make TARGET=MPS2_AN500 run
14.1.1.3.1.2. MPS3_AN547 (Arm FVP)#
O FVP é a Fixed Virtual Platform da Arm para o Corstone SSE-300, distribuída como parte do Arm Virtual Hardware. Está disponível apenas para Linux – em um Mac, use o alvo QEMU acima.
Baixe o bundle, extraia-o e coloque o diretório bin/ dele no seu 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"
O FVP também precisa das bibliotecas Python do SDK no LD_LIBRARY_PATH quando ele roda. Exporte-o uma vez por shell a partir da raiz do repositório – ler SDK_VERSION mantém o valor correto à medida que o repositório atualiza o SDK fixado:
export LD_LIBRARY_PATH="$HOME/openmv-sdk-$(cat SDK_VERSION)/python/lib:$LD_LIBRARY_PATH"
Depois compile e execute o alvo:
make -j$(nproc) TARGET=MPS3_AN547
make TARGET=MPS3_AN547 run
14.1.1.3.2. Executando a suíte de testes#
Os testes unitários ficam em scripts/unittest/tests/, com suas imagens de fixture e dados em scripts/unittest/data/. Eles são executados com o mpremote, que monta scripts/unittest/ no simulador em execução e executa o run.py dele.
O link do simulador é lento com o mpremote padrão, então use a cópia incluída no repositório com o patch serial aplicado (aplique-o uma vez):
patch -N -p1 -d lib/micropython < tools/mpremote-qemu-serial.patch
Para MPS2_AN500 sob o QEMU, inicie o alvo – ele imprime o pseudo-terminal em que sua porta serial está (por exemplo /dev/pts/5):
make TARGET=MPS2_AN500 run
Depois, a partir de outro shell, aponte o mpremote corrigido para esse dispositivo:
python3 lib/micropython/tools/mpremote/mpremote.py connect /dev/pts/5 \
mount scripts/unittest/ run scripts/unittest/run.py
Para MPS3_AN547 sob o FVP, a porta serial é um socket telnet na 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
O run.py descobre e executa cada teste, imprimindo uma linha PASSED / FAILED por teste com tempo e um resumo ao final.
14.1.1.3.3. Adicionando um teste#
Os testes são descobertos automaticamente. Para adicionar um, coloque um arquivo em scripts/unittest/tests/ que defina uma função unittest(data_path, temp_path) que retorne True quando o teste passa e False quando ele falha:
# 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)
Os argumentos data_path e temp_path apontam para os dois sistemas de arquivos que o simulador vê enquanto a suíte roda:
Path | Backed by |
|---|---|
| O diretório |
| O sistema de arquivos ROM somente leitura da placa, embutido na imagem do firmware a partir de |
Então um novo teste não precisa de recompilação, mas um novo fixture precisa: a imagem ROM é chaveada a partir de romfs_config.json em vez dos arquivos de dados individuais, então force a recompilação tocando o romfs_config.json da placa (ou make TARGET=<TARGET> clean) e executando novamente.
Os valores esperados são verificados inline no teste, então não há um arquivo de saída esperada separado para manter. Para pular um teste em tempo de execução – por exemplo quando ele precisa de hardware que o simulador não modela – lance uma exceção cuja mensagem contenha "SKIPPED".