Open22

m5stack UnitV2用のOpenCVプログラムをRustでクロスコンパイルする方法

exyriasexyrias

作りたいもの

  • m5stack UnitV2で動くプログラム
  • OpenCVを使ってカメラ画像取得(できればストリーミング)

開発環境

  • 言語:Rust
  • 開発するPC:Ubuntu

この記事

開発に必要なもののメモからサンプルプログラムを動かすところまでを記事として残す
Rustの開発環境は構築済みとする

exyriasexyrias

m5stack UnitV2

Linuxが動いていて、マイクやカメラを搭載してる小型マイコンだと思えば良さそう。

チュートリアル から

  • Built-in recognition function use tutorial
  • Jupyter Notebook Development Tutorial/Example
  • SSH connection & WIFI configuration

あたりを試しておく

チュートリアルのBuit-inプログラムについて

UnitV2は起動時にホームディレクトリにあるWebアプリのサーバプログラムを自動で実行するようになっている。
Ethernet over USBによりUSBケーブル越しにIP通信ができるので、PCからブラウザでWebアプリを起動したり、Jupyterが使えるようになっている。
Webアプリではあらかじめ保存されているBuiltinプログラムを試せる

Builtinプログラムのコードはここ https://github.com/m5stack/UnitV2Framework

m5stack特有のライブラリなどがあるわけではなく、ただ単にOpenCVをC++で使ったり、arecordでロク0音したりしているので、プログラム自体は普通のLinuxとして書けば良さそう。

exyriasexyrias

ファイルとしては

ホームディレクトリの/home/m5stack以下にpayloadというディレクトリがあり、その下にWebアプリ用のファイルやプログラムがまとめられている

server.pyが起動プログラム、binにBuilt-inプログラムがまとめられている

server.py自体は/etc/init.d/S85runpayloadで起動している

exyriasexyrias

あまり詳しい説明はないが、組み込み用のため、ランレベルで切り替えたり、サービスのon/off切り替えのような機能(それを実現するためのスクリプト)など使わないっぽい。
単純に/etc/init.d以下にある、スクリプトファイルを順に実行するだけなので、S85runpayloadのファイル名を変える(S以外の文字で始める)か、削除してしまうかがよさげ

exyriasexyrias

OpenCV

UnitV2にはOpenCVのライブラリが入っているので、今回はOpenCV自体のクロスコンパイルは不要か?

まずは、UnitV2にインストール済みのOpenCVを使うプログラムをクロスコンパイルしてみる

exyriasexyrias

Rustのクロスコンパイル環境

ここを参考に構築してみる

rustup target list

でクロスコンパイルのターゲット一覧を確認

armv7関連は下記のものがある。

armv7-linux-androideabi
armv7-unknown-linux-gnueabi
armv7-unknown-linux-gnueabihf
armv7-unknown-linux-musleabi
armv7-unknown-linux-musleabihf
armv7a-none-eabi
armv7r-none-eabi
armv7r-none-eabihf

Builtinプログラムのコンパイル方法とかから類推でarmv7-unknown-linux-gnueabihfをインストール

rustup target add armv7-unknown-linux-gnueabihf
sudo apt install g++-arm-linux-gnueabihf # リンカのインストール
exyriasexyrias

このあと、リンカの設定がいる

${HOME}/.cargo/configというファイルを作り、下記内容を書いておく

[target.armv7-unknown-linux-gnueabihf]
linker = "arm-linux-gnueabihf-gcc"
exyriasexyrias

まずはOpenCVを使わないhelloworldをクロスコンパイルしてみる

下記コマンドでビルド

cargo build --target=armv7-unknown-linux-gnueabihf

target/armv7-unknown-linux-gnueabihf/debug/m5unitv2_cv_cameraという実行バイナリができる

exyriasexyrias

プログラムのコピー

UnitV2ではsshができるように設定されているが、scpは難あり。
/dev/nullのパーミッションエラーでscpができない。/dev/nullのパーミッションを変えている記事もあったが、ここではrootでscpすることにした。
scp後、所有者変更と実行権限付与

chown  m5stack:10 m5unitv2_cv_camera
chmod 755 m5unitv2_cv_camera
exyriasexyrias

m5stackではなぜか660になっているが、/dev/nullは通常の権限は666になっているらしいので、/dev/nullの権限を変えるのが正しい直し方かもしれない。
rootでsshして権限を変更しておく

chmod 666 /dev/null
exyriasexyrias

ホームディレクトリの所有者もavahiになっており、m5stackユーザで書き込めないので、所有者を変更しておく

 chown m5stack:m5stack /home/m5stack
exyriasexyrias

再起動すると /dev/null の権限が660に戻っている。組み込みLinuxはこれが正しい挙動なのか?

exyriasexyrias

GLIBCエラー

実行したところGLIBCがないというエラーが出た

unitv2% ./m5unitv2_cv_camera
./m5unitv2_cv_camera: /lib/libc.so.6: version `GLIBC_2.33' not found (required by ./m5unitv2_cv_camera)
./m5unitv2_cv_camera: /lib/libc.so.6: version `GLIBC_2.32' not found (required by ./m5unitv2_cv_camera)
./m5unitv2_cv_camera: /lib/libc.so.6: version `GLIBC_2.34' not found (required by ./m5unitv2_cv_camera)
exyriasexyrias

開発PCのglibcのバージョンがターゲットのバージョンより新しいと、このエラーが出るらしい

ターゲットをgnuではなく、muslにするとライブラリ非依存のバイナリを作れるらしいので、試してみる。
muslは対応するg++のリンカはなく、rust-lldを使う

rustup target add armv7-unknown-linux-musleabihf

.cargo/configに以下を追記

[target.armv7-unknown-linux-musleabihf]
linker = "rust-lld"
exyriasexyrias

ターゲットを変えてビルド

cargo build --target=armv7-unknown-linux-musleabihf

ビルドしたら、再度rootのscpでUnitV2にコピー。この時、ファイルを上書きしたのに、なぜか所有者や権限はそのままだった。。。

exyriasexyrias

無事helloworldがUnitV2で起動できた。

ファイルサイズは4.6M。glibc使う方は3.9Mなので、多少大きくなっているが許容範囲。

exyriasexyrias

本題と関係ないがUnitV2はWiFi APにできるのだが、初期状態ではうまくいかない。ほかの記事でも設定できず断念している記事があったが、下記の方法でAP化に成功したので、メモしておく

WiFiのAPとしての設定ファイルが/etc/hostapd.confにある。このファイルを編集することで設定を変更できるのだが、ここにssidの指定がない。

ssid=M5UV2_XXX

と、ssidを追記すると、PCなどからSSIDが見えるようになり、ログインできる。
パスワードはUnitV2のドキュメントに書いてあるが、このファイルを編集して変えることもできると思う。

exyriasexyrias

OpenCVのクレートは https://github.com/twistedfall/opencv-rust を使う

cargo add opencv

でCargo.tomlにクレートを追記できる

公式のReadmeに従って、必要なパッケージをインストール。(Ubuntu用コマンド)

apt install libopencv-dev clang libclang-dev
exyriasexyrias

このままだとclangがうまく設定?できておらず、ビルドに失敗する。

コンパイルの途中で、clangがヘッダファイルに対して not found というエラーを出す。
調べたところ、clang++の設定がうまくいっていないらしい。clang++単体で試してもコンパイルに失敗した。

exyriasexyrias

ライブラリ周りの設定ができていないようだが、開発環境の設定を頑張ってもクロスコンパイルでは意味がないので、クロスコンパイルを試してみる。

clang++ --target=arm-linux-gnueabihf a.cpp

でテスト用のhelloworldはコンパイルできたが、UnitV2に持っていくとrustのときと同様glibcのバージョンエラーが出た。
clangはmuslに対応しておらず、musl用のコンパイルは大変そう。結局glibcのバージョン問題を解決する必要がある。

exyriasexyrias

m5stack unitv2の公式Built-inのgithubにgnu toolchainの情報があるので、ダウンロードページから直接ダウンロードしてみる
執筆時点のバージョン情報は
gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf.tar.xz