Zephyr RTOS & Pico 2W & SPIカメラで動画ストリーミング!

本サイトはアフィリエイト広告を利用しています。
Zephyr

SRAMが1MBに満たない省電力マイコンで、カメラから動画をリアルタイムにストリーミング配信してみました。

対象ボードは、Raspberry Pi Pico 2W、Nordic nRF54L15-DK、そしてArduino® UNO Qです。

今回は、Zephyr RTOSとArducam Mega 3MPを組み合わせ、20〜30 FPSという驚異的なフレームレートでPCへ動画を連続ストリーミングするリファレンス実装を紹介します。

カメラ内蔵ハードウェアJPEGエンコーダの活用法や、32KB×2面のPing-Pongダブルバッファリング、OSのバッファ詰まりを防ぐPython側の非同期受信アーキテクチャなど、実践的なノウハウを詳しく解説します。

 

スポンサーリンク

Zephyr RTOS & SPIカメラで20〜30FPS動画ストリーミング!【Pico 2W / nRF54L15 / UNO Q 共通MJPEG編】

SRAMが1MBに満たない省電力マイコンで、カメラから動画をリアルタイムにストリーミング配信してみました。

対象ボードは、Raspberry Pi Pico 2W、Nordic nRF54L15-DK、そしてArduino® UNO Qです。

Pico2Wをメインに紹介します。

 

今回は、Zephyr RTOSとArducam Mega 3MPを組み合わせ、20〜30 FPSという驚異的なフレームレートでPCへ動画を連続ストリーミングするリファレンス実装を紹介します。

カメラ内蔵ハードウェアJPEGエンコーダの活用法や、32KB×2面のPing-Pongダブルバッファリング、OSのバッファ詰まりを防ぐPython側の非同期受信アーキテクチャなど、実践的なノウハウを詳しく解説します。

 

プロジェクト・GitHubのリンク先

GitHubのリンク先は下記です

GitHub - iotengineer22/zephyr-spicam
Contribute to iotengineer22/zephyr-spicam development by creating an account on GitHub.

 

実際のデモ動画は下記です

Raspberry Pi Pico 2W(USB経由のリアルタイム動画ストリーミング実演)

 

マルチボード構成とピンアサイン

本プロジェクトでは、Cortex-M33コアを搭載した3種類の最新マイコンボードを使用しています。

Arducam Mega 3MP(SPI接続カメラ)を各ボードへ以下のピン配置で接続しました。

 

ハードウェア接続一覧表

信号名 カメラピン Raspberry Pi Pico 2W Nordic nRF54L15-DK (P1) Arduino® UNO Q
電源 (VCC) Pin 1 (VCC) 3V3 (Pin 36) Pin 1 (VDDIO / 3.3V) 3.3V / 5V
グランド (GND) Pin 2 (GND) GND (Pin 23) Pin 2 (GND) GND
SPI MOSI Pin 3 (MOSI) GP19 (Pin 25) Pin 6 (P1.06 / SPI22) D11 (PB15 / SPI2)
SPI MISO Pin 4 (MISO) GP16 (Pin 21) Pin 7 (P1.07 / SPI22) D12 (PB14 / SPI2)
チップセレクト (CS) Pin 6 (CS) GP17 (Pin 22) Pin 10 (P1.10 / GPIO) D10 (PB9 / GPIO)
SPI クロック (SCK) Pin 5 (SCK) GP18 (Pin 24) Pin 11 (P1.11 / SPI22) D13 (PB13 / SPI2)
PC通信路 - 内蔵USB CDC ACM オンボード J-Link VCOM1 USART1シリアル (D0/D1)

 

リアルタイム動画を実現する4つの技術的工夫

SRAMが数百KBしかないマイコンで高フレームレートな動画配信を行うため、4つの工夫を凝らしました。

 

ハードウェアJPEG圧縮の徹底活用

非圧縮のRAW画像(例えばVGA 640x480 RGB565)は1フレームあたり約614KBあり、マイコンのSRAM容量もUSB転送帯域も一瞬で破綻します。

そこで、Arducam Megaの内蔵ハードウェアJPEGエンコーダを活用しました。

画像データを撮影の瞬間に約1/25〜1/40に圧縮し、フレームサイズを3〜8KB程度に抑え込んでいます。

 

動的な解像度最適化(QVGAとQQVGA)

用途に応じて最適な画質と速度を選べるよう、2種類の解像度を用意しました。

 

* QVGA (320x240): フレームサイズ 4〜7 KB(約15〜25 FPS)
人物の表情や文字がくっきりと認識でき、滑らかな映像が得られます。

* QQVGA (160x120): フレームサイズ 1.5〜3 KB(約20〜30 FPS)
スポーツや高速移動体の監視にも追従できる、超高フレームレート表示が可能です。

 

静的ダブルバッファリング(Ping-Pong Buffer)

Zephyrの video_import_buffer() を利用し、.bss 領域に32KB × 2面(計64KB)の静的バッファを確保しました。

バッファAをPCへUSB送信している裏で、カメラ側がSPI経由でバッファBへ次フレームを並行キャプチャします。

パイプラインの待ち時間をゼロにすることで、フレーム落ちのないスムーズな動画伝送を実現しました。

 

ストリーミング専用軽量パケット(*VID)

静止画のキャプチャでは確実性を重視して4KBごとのACKハンドシェイクを用いましたが、動画配信では速度を優先し、連続ストリーミング対応のパケットプロトコルを新規設計しました。

24バイトの自己同期ヘッダー(マジックコード *VID、解像度、フレーム番号、タイムスタンプ)に続けてJPEGデータを流し込み、4バイトのフッター(VID*)で終了します。

パケットロスが発生した場合でも、次のヘッダーで即座に自動復帰できます。

 

各ボードのスペック比較とリソース消費

各マイコンボードにおける動画配信時の性能測定結果です。

項目 Raspberry Pi Pico 2W Nordic nRF54L15-DK Arduino® UNO Q
SoC / コア RP2350 (Dual M33 @ 150 MHz) nRF54L15 (M33 @ 128 MHz) STM32U585 (M33 @ 160 MHz)
内蔵SRAM 520 KB 256 KB (最小環境) 786 KB
標準解像度 320 x 240 QVGA 320 x 240 QVGA 320 x 240 QVGA
達成フレームレート 20 〜 30 FPS 15 〜 25 FPS 20 〜 30 FPS
平均フレームサイズ 4.5 〜 7.0 KB 4.5 〜 7.0 KB 4.5 〜 7.0 KB
バッファ構成 32 KB x 2面 (計 64 KB) 32 KB x 2面 (計 64 KB) 32 KB x 2面 (計 64 KB)
SRAM使用量 約 18.5% (空き 420 KB) 約 43.8% (空き 144 KB) 約 10.4% (空き 686 KB)
Flash使用量 約 74 KB / 4 MB (1.8%) 約 53 KB / 1.5 MB (3.5%) 約 48 KB / 2 MB (2.3%)

最もSRAMが小さいnRF54L15-DK(256KB)でも、SRAM使用率はわずか43.8%であり、余裕を持って動作しています。

 

ビルドと書き込み手順(West)

各ボード向けのファームウェアは、プロジェクト内のバッチファイル(build.bat)で簡単にビルドできます。

ソースコードはGitHubで公開しています。

 

Raspberry Pi Pico 2W のビルド手順

PowerShellで仮想環境を起動し、ビルドを実行します。

 

生成された build\pico\zephyr\zephyr.uf2 を、BOOTSELモードで接続したPico 2Wのドライブへドラッグ&ドロップして書き込みます。

 

Nordic nRF54L15-DK のビルドと書き込み手順

nRF54L15-DKは、コマンドラインから直接書き込み可能です。

 

 

Arduino® UNO Q のビルド手順

Arduino® UNO QのSTM32マイコン向けファームウェアをビルドします。

 

 

Python低遅延ストリーミングビューワー

PC側で動画を表示するため、Python(PySerial + OpenCV)による高機能ビューワー(video_stream.py)を作成しました。

 

OSバッファの背圧を解消する非同期受信

通常のシリアル読み込みループでは、PC側の描画処理に引きずられて受信バッファが溜まり、数秒の表示遅延(ラグ)が発生しがちです。

本ビューワーでは、バックグラウンドスレッドが32KBのリングバッファを介してシリアルデータを常時一括読み込み(Bulk Read)します。

メインスレッドは常に「最新の完全なフレーム」だけをデコードして描画するため、遅延(レイテンシ)ほぼゼロのリアルタイム表示を実現しています。

 

ストリーミングの実行方法

付属のバッチファイルでワンクリック起動できます。

 

またはPythonから直接実行します。

 

画面上にはリアルタイムFPS、解像度、フレームサイズがHUD表示されます。

キーボード操作で一時停止(スペースキー)、解像度切替(数字の1キーでQVGA、2キーでQQVGA)、JPEG写真の保存(Cキー)が手軽に行えます。

 

まとめ

1MB未満のSRAMしか持たない省電力マイコン(Pico 2W / nRF54L15 / UNO Q)で、Zephyr RTOSとArducam Megaを活用した20〜30 FPSのリアルタイム動画ストリーミングを実現しました。

 

* ハードウェア圧縮: 内蔵JPEGエンコーダにより、フレームサイズを3〜7KBに圧縮。

* Ping-Pongダブルバッファ: 64KBの静的バッファでキャプチャと送信を完全並行化。

* ストリーミングプロトコル: 軽量パケット設計で高スループットと即時同期を両立。

* 超低遅延ビューワー: Python非同期受信により、PC側での描画遅延をゼロ化。

 

マイコンによる見守りカメラやロボットの視覚センサ、遠隔モニタリングなど、多彩なIoT応用に活用できる実用的なリファレンスです。

ソースコードはGitHubで公開していますので、ぜひ滑らかな動画ストリーミングを体験してみてください!

コメント