Nerves on Raspberry Pi 4でカメラモジュールを使う
Nervesで遊んでみるのに、Nerves Livebookはとても便利です。しかし、Raspberry Pi 4では、カメラモジュールがそのままでは使えません。
課題
ElixirでRapspberry Piのカメラモジュールを扱うライブラリとしてpicamというものがあります。Nerves Livebookでは、Raspberry Pi 4未満でしか依存に組み込まれません。
# Libraries that use MMAL on the Raspberry Pi won't work with the Raspberry
# Pi 4. The Raspberry Pi 4 uses DRM and libcamera.
@rpi_mmal_targets [:rpi, :rpi0, :rpi2, :rpi3, :rpi3a]
nerves_livebook/mix.exs at main · livebook-dev/nerves_livebook
picamはMMAL(Multi-Media Abstraction Layer)を通じてカメラデバイスにアクセスするのですが、Bullseye camera system - Raspberry Piにある通り、Raspberry Pi OS Bullseyeからはカメラ周りのドライバが変更され、libcameraを使うようになったことが関連するようです。
上記のターゲットに:rpi4
を入れてビルドしてみても、以下の通りmmalに関するヘッダがなくて失敗します。
==> picam
mkdir -p /Users/kentaro/src/github.com/kentaro/nerves_livebook_ml/_build/rpi4_dev/lib/picam/ebin/../obj
mkdir -p /Users/kentaro/src/github.com/kentaro/nerves_livebook_ml/_build/rpi4_dev/lib/picam/ebin/../priv
/Users/kentaro/.nerves/artifacts/nerves_toolchain_aarch64_nerves_linux_gnu-darwin_arm-1.5.0/bin/aarch64-nerves-linux-gnu-gcc -mabi=lp64 -fstack-protector-strong -mcpu=cortex-a72 -fPIE -pie -Wl,-z,now -Wl,-z,relro-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -pipe -O2 -I/Users/kentaro/.nerves/artifacts/nerves_system_rpi4-portable-1.19.0/staging/usr/include -c src/raspijpgs.c -o /Users/kentaro/src/github.com/kentaro/nerves_livebook_ml/_build/rpi4_dev/lib/picam/ebin/../obj/raspijpgs.o
src/raspijpgs.c:39:10: fatal error: interface/mmal/mmal.h: No such file or directory
39 | #include "interface/mmal/mmal.h"
| ^~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
make: *** [/Users/kentaro/src/github.com/kentaro/nerves_livebook_ml/_build/rpi4_dev/lib/picam/ebin/../obj/raspijpgs.o] Error 1
解決
とりあえずの解決策としては、ElixirのOpenCVバインディングであるevisionを使うという方法があります。使い方は簡単で、Nerves Livebookのmix.exs
に以下の通り追加するだけです。
{:evision, "~> 0.1.0-dev", github: "cocoa-xu/evision", branch: "main"},
その上で、ビルドしたファームウェアを焼いたSDカードでRaspberry Pi 4を起動して、Livebookの画面上で以下のようなコードを書けばOKです。
alias Evision, as: OpenCV
{:ok, cap} = OpenCV.VideoCapture.videoCapture(0)
{:ok, mat} = OpenCV.VideoCapture.read(cap)
{:ok, encoded} = OpenCV.imencode(".png", mat)
encoded
|> IO.iodata_to_binary()
|> Kino.Image.new(:png)
実際にやってみた様子はこんな感じ。
カメラモジュールからフレームを読み込んで表示することができました。
懸念
evisionのコンパイル時間がとても長くなるのと、ファームウェアサイズが53MBと大きくなることがデメリットではあるでしょうか。パフォーマンスについても検証する必要があるでしょう。
ls -lah _build/rpi4_dev/nerves/images/nerves_livebook.fw
-rw-r--r-- 1 kentaro staff 53M 6 9 19:15 _build/rpi4_dev/nerves/images/nerves_livebook.fw
Discussion