🙆‍♀️

Nerves on Raspberry Pi 4でカメラモジュールを使う

2022/06/14に公開

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)

実際にやってみた様子はこんな感じ。

https://twitter.com/kentaro/status/1534502818681622528

カメラモジュールからフレームを読み込んで表示することができました。

懸念

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