14.1.1.3. 模拟器#

有两个 TARGET 取值会将固件构建为在你主机上的 模拟器 中运行,无需连接任何硬件。它们的存在使得固件可以在任何地方运行和测试。

TARGET

内核

NPU

模拟器

MPS2_AN500

Cortex-M7

QEMU

MPS3_AN547

Cortex-M55

Ethos-U55 (256 MACs)

Arm FVP -- Corstone SSE-300

MPS2_AN500 是不带 NPU 的基础 Cortex-M7 目标。它在 QEMU 下运行,启动很快,是练习与平台无关的代码和测试套件的轻量方式。

MPS3_AN547 是带 Ethos-U55 NPU 的 Cortex-M55,运行在 Arm 的 Fast Models 上——即 FVP,它对 Corstone SSE-300 参考子系统进行建模。这是在模拟中练习 NPU 和 ML 模型路径的目标。

两者都提供 ROM 文件系统和充裕的 RAM(M55 上还有 NPU),因此视觉和 ML 脚本无需修改即可运行。

没有真实的传感器,但 csi 模块仍可针对一个虚拟传感器工作——csi.CSI.snapshot() 返回一个合成的、带动画的测试图案(灰度下是滚动的棋盘格,RGB565 下是渐变),而不是实时场景。要处理真实的图像内容,请改为从文件加载:从 ROM 文件系统中的固定文件加载一个 image.Image,或为录制的帧加载一个 image.ImageIO 流。

14.1.1.3.1. 构建与运行#

每个模拟器都是一个由你自行安装的主机工具。你像构建任何其他目标一样构建一个目标(参见 构建固件),然后在对应的模拟器下 run 它——run 会构建 ROMFS 镜像、引导固件,并让它保持运行,同时提供一个你可以连接的串口连接。

14.1.1.3.1.1. MPS2_AN500 (QEMU)#

QEMU 在大多数包管理器中作为 Arm 系统模拟器提供:

  • Linux(Debian / Ubuntu)——用 apt 安装它:

    sudo apt install qemu-system-arm
    
  • macOS——用 Homebrew 安装它:

    brew install qemu
    

然后构建并运行目标:

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

14.1.1.3.1.2. MPS3_AN547 (Arm FVP)#

FVP 是 Arm 面向 Corstone SSE-300 的固定虚拟平台(Fixed Virtual Platform),作为 Arm Virtual Hardware 的一部分提供。它仅适用于 Linux——在 Mac 上,请改用上面的 QEMU 目标。

下载该捆绑包,解压它,并将其 bin/ 目录加入你的 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 在运行时还需要 SDK 的 Python 库位于 LD_LIBRARY_PATH 上。请在仓库根目录下每个 shell 导出一次——读取 SDK_VERSION 可在仓库更新固定的 SDK 时保持其正确:

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

然后构建并运行目标:

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

14.1.1.3.2. 运行测试套件#

单元测试位于 scripts/unittest/tests/ 中,其固定图像和数据位于 scripts/unittest/data/ 中。它们使用 mpremote 运行,后者会将 scripts/unittest/ 挂载到正在运行的模拟器上并执行其 run.py

模拟器链接在原版 mpremote 下很慢,因此请使用仓库中捆绑的、已应用串口补丁的副本(应用一次即可):

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

对于 QEMU 下的 MPS2_AN500,启动该目标——它会打印其串口所在的伪终端(例如 /dev/pts/5):

make TARGET=MPS2_AN500 run

然后,从另一个 shell,将打过补丁的 mpremote 指向该设备:

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

对于 FVP 下的 MPS3_AN547,串口改为端口 5555 上的一个 telnet 套接字:

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 会发现并执行每一个测试,为每个测试打印一行带计时的 PASSED / FAILED,并在末尾给出汇总。

14.1.1.3.3. 添加测试#

测试会被自动发现。要添加一个,请在 scripts/unittest/tests/ 中放入一个文件,其中定义一个 unittest(data_path, temp_path) 函数,测试通过时返回 True,失败时返回 False:

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

data_pathtemp_path 参数指向套件运行时模拟器所看到的两个文件系统:

路径

由……支持

/remote

主机的 scripts/unittest/ 目录,通过 mpremote 连接实时挂载。run.py 及它所发现的 tests/ 都位于此处,因此添加或编辑测试会在下次运行时生效,无需重新构建。temp_path 在设备上是 /remote/temp,也就是你主机的 scripts/unittest/temp/——一个供创建文件的测试使用的可写暂存目录。

/rom

开发板的只读 ROM 文件系统,从 romfs_config.json 构建进固件镜像:测试固定文件(来自 scripts/unittest/data/)和捆绑的 ML 模型。data_path/rom——可通过 data_path + "/<file>" 访问某个固定文件。

因此一个新的 测试 无需重新构建,但一个新的 固定文件 则需要:ROM 镜像以 romfs_config.json 而非各个数据文件为依据,所以请通过 touch 开发板的 romfs_config.json(或 make TARGET=<TARGET> clean)强制重新构建并再次运行。

预期值在测试中以内联方式断言,因此没有单独的预期输出文件需要维护。要在运行时跳过某个测试——例如当它需要模拟器未建模的硬件时——请抛出一个消息中包含 "SKIPPED" 的异常。