14.1.1.3. シミュレーター#

2つの TARGET 値は、ハードウェアを接続せずにホスト上のシミュレーター内で動作するファームウェアをビルドします。これらは、ファームウェアをどこでも実行してテストできるようにするために存在します。

TARGET

コア

NPU

シミュレーター

MPS2_AN500

Cortex-M7

None

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 は Corstone SSE-300 向けの Arm の 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 上に必要とします。リポジトリのルートからシェルごとに一度エクスポートします。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

次に、別のシェルから、パッチを適用した 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. テストの追加#

テストは自動的に検出されます。テストを追加するには、テストが成功したときに True を、失敗したときに False を返す unittest(data_path, temp_path) 関数を定義したファイルを scripts/unittest/tests/ に置きます:

# 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_path 引数と temp_path 引数は、スイートの実行中にシミュレーターが見る2つのファイルシステムを指します:

パス

バックエンド

/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 をキーにしているため、ボードの romfs_config.json をタッチして(または make TARGET=<TARGET> clean)再実行することで再ビルドを強制します。

期待値はテスト内でインラインにアサートされるため、維持すべき別個の期待出力ファイルはありません。実行時にテストをスキップするには(例えばシミュレーターがモデル化しないハードウェアを必要とする場合)、メッセージに "SKIPPED" を含む例外を送出します。