ししかわです。
社員研修の一環で二足歩行ロボットを作って、競技会「Humanoid Autonomous Challenge(HAC)」に参加します。
前回からM5Stackの画像認識モジュール「M5Stack UnitV2」をM5Stackのユニットとしてではなく単独で使い、ロボットを制御できるようにしよう!というマニアックな計画を進めています。
UnitV2で好きなプログラムを動かすための下準備として、まずUnitV2の仕組みを調べてみます。今回のゴールとして、電源投入時に自動で起動する「画像認識サーバ」を止めてみましょう。この作業を通じてUnitV2のLinuxの基本的な構造や、プログラム自動起動の仕組みも理解できます。
なお、UnitV2のビルトイン機能の紹介や使い方の説明は、既に他のブログ記事が複数出ているため本連載では割愛します。トラブルシュートも含め公式ドキュメントが詳しいです。
組込みLinuxボードとしての「M5Stack UnitV2」
前回説明したとおり「M5Stack UnitV2」は画像認識機能のベースとしてLinuxがインストールされているのでした。
組込みLinuxの知識がないと「この小さいボードでLinuxが動いてるってどういうこと?」「LinuxってUbuntuとかRaspbian(現RaspberryPi OS)のこと?」など、疑問に思うことでしょう。
そこで、次の疑問点について説明します。
- そもそもLinux/組込みLinuxとは何か
- UnitV2で動いているLinuxの種類は何か
- 画像認識機能が自動で立ち上がるのは、どんな仕組みによるものか
そもそもLinux/組込みLinuxとは何か
Linuxに馴染みの無い方もいるかと思いますので簡単におさらいします。
OSとしてのLinuxは、プロセス管理やメモリ管理、ハードウェアとの通信などOSとしてのコア機能を司る「Linuxカーネル」と、カーネルを用いたライブラリやアプリケーションからなる「ユーザランド」からなります。ユーザランドのアプリケーションはLinuxカーネルとシステムコールを介してやりとりします。Linuxカーネルに含まれる各ハードウェア用のドライバはカメラやネットワークインタフェースカード(NIC)を制御します。
Linuxカーネルがハードウェア毎の違いを吸収して共通のAPIを用意しているため、ユーザランドのアプリケーションは(たいていの場合)ハードウェアの差異を気にせずに済みます。例えば皆さんのPCでUSBカメラを違うものに差し替えても同じようにZoomが使えているのはLinuxカーネルのドライバのおかげです。また、多くのドライバはカーネルモジュールとして提供されています。必要なモジュールのみ実行時に動的に読み込む作りにすることでカーネル本体のサイズは小さく保てます。
UbuntuなどのディストリビューションはLinuxカーネルに加えて様々なユーザランドのプログラム群で構成されます(図中の点線枠)。
ユーザの用途に応じて様々なディストリビューションがあります。例えばUbuntu DesktopはデスクトップPCとしての用途を想定しているため、アプリケーションマネージャやGUI、開発用のライブラリが初めから入っていてすぐに使い始められます。
一方、組込み機器でLinuxを使う場合、はじめから用途が特定のタスクに限定できるので、Linuxカーネルの他には必要最小限のアプリケーションだけインストールしてあれば十分です。既存のディストリビューションを使わずとも、カーネルやユーザランドのプログラムを自分で選択してコンパイルすればよいのです。
UnitV2で動いているLinuxの種類は何か
ここからは実際にUnitV2を操作しながら進めてみます。手元にUnitV2を持っている方はぜひコマンドを自分で打ちながら試してみてください!
M5Stack UnitV2はPCとUSBケーブルで接続するだけでネットワークが有効になります。
手始めにSSH接続してみましょう。UnitV2にはunitv2.localという名前でアクセスできます。またm5stackという名前の初期ユーザが登録されています。
host-pc% ssh m5stack@unitv2.local m5stack@unitv2.local's password: (初期パスワードは12345678) unitv2%
(こんなに小さいカメラにSSH接続できてしまうのは不思議な感じですね!)
さて、UnitV2ではどんなディストリビューションが使われているでしょうか?OSの種類に関する情報はたいてい/etc/
ディレクトリ配下にありますので見てみましょう。
unitv2% ls /etc/ ... os-release ... unitv2% cat /etc/os-release NAME=Buildroot VERSION=2020.02.8 ID=buildroot VERSION_ID=2020.02.8 PRETTY_NAME="Buildroot 2020.02.8"
なるほど、OSはBuildrootというもののようです。あまり聞き慣れないですね。
公式サイトには次のような説明があります。
Buildroot is a simple, efficient and easy-to-use tool to generate embedded Linux systems through cross-compilation.
Buildrootは冒頭で説明したような組込み機器のためのLinuxシステムを生成するツールです。GUIなどで必要なパッケージを定義すると、それら一式を備えたミニマルなLinuxシステムが作れます。
Buildrootは「クロスコンパイル」に対応しています。クロスコンパイルとは、開発用の環境と異なる環境で動くプログラムをコンパイルすることです。たとえばx86_64アーキテクチャの開発用PCでシステム一式をビルドして、armv7アーキテクチャのUnitV2に書き込み、動かすことができます。
ということでUnitV2は特定のディストリビューションではなく、UnitV2向けに専用にビルドされた組込みLinuxであることが確認できました。
他にも幾つかの設定を確認してみましょう。
ロードされているカーネルモジュールは次のとおりです。8188fu(Wi-Fiアダプタのドライバ)、nls_utf8(多言語サポート)、ehci_hcd(USBドライバ)などがロードされています。
unitv2% lsmod Module Size Used by Tainted: G vfat 6820 1 ntfs 73756 0 nls_utf8 1457 0 msdos 5668 0 grace 5158 1 fat 42384 2 vfat,msdos ehci_hcd 33777 0 cifs 169945 0 8188fu 836118 0
さきほどSSHでunitv2
というホスト名でアクセスできました。これは/etc/hosts
で定義されています。
unitv2% cat /etc/hosts 127.0.0.1 localhost 127.0.1.1 unitv2
(今は使っていませんが)UnitV2はWi-Fiアクセスポイントにもなります。これは/etc/wpa_supplicant.conf
で定義されています。
unitv2% cat /etc/wpa_supplicant.conf ctrl_interface=/var/run/wpa_supplicant eapol_version=1 ap_scan=1 fast_reauth=1 network={ ssid="M5-2.4G" psk=(Wi-Fiアクセスポイントのパスフレーズ) }%
プログラム自動起動の仕組み
UnitV2はUSBケーブルを挿すと電源が自動でONになります。起動すると、
- SSHサーバ
- Wi-Fiアクセスポイント
- 画像認識機能のテスト用Webサーバ(ブラウザからアクセスできる)
などが自動起動します。これらがどこで起動されるか確認していきます。
まず「画像認識機能のテスト用Webサーバ」の本体ですが、m5stackユーザのホームディレクトリ配下にありました。
unitv2% ls -l /home/m5stack total 0 drwxrwxr-x 10 m5stack avahi 1768 Jan 1 00:03 payload unitv2% ls -l /home/m5stack/payload total 48 drwxr-xr-x 2 m5stack staff 2400 Apr 28 2021 bin drwxr-xr-x 2 m5stack staff 160 Apr 28 2021 data drwxr-xr-x 2 m5stack staff 3032 Apr 28 2021 models -rwxr-xr-x 1 m5stack staff 382 Apr 21 2021 run_notebook.py -rwxr-xr-x 1 m5stack staff 1575 Apr 21 2021 server.py -rwxr-xr-x 1 m5stack staff 30619 Apr 28 2021 server_core.py -rwxr-xr-x 1 m5stack root 1292 Jan 1 00:18 server_log.txt -rwxr-xr-x 1 m5stack root 87 Jan 1 00:06 server_system_config.json drwxr-xr-x 6 m5stack staff 832 Apr 28 2021 static drwxr-xr-x 2 m5stack staff 304 Apr 28 2021 templates drwxr-xr-x 2 m5stack staff 328 Apr 28 2021 tools drwxr-xr-x 6 m5stack staff 696 Apr 28 2021 uploads
/home/m5stack/payload/server.py
がサーバを起動するPython製スクリプトでした。もちろんここに置いたスクリプトがひとりでに起動するわけではなく、どこかでこのスクリプトを実行する仕組みがあるはずです。探してみましょう。
前述のとおり、UnitV2のLinuxシステムはBuildrootで作られています。まずはBuildrootのマニュアルから、システムの初期化に関する記述を探します。
The BusyBox
init
program will read the/etc/inittab
file at boot to know what to do.
説明がありました。Linuxが起動して最初に実行されるのはinit
というプログラムで、/etc/inittab
に定義された処理を行います。
etc/inittab
を確認します。
unitv2% cat /etc/inittab (略) # now run any rc scripts ::sysinit:/etc/init.d/rcS (略)
inittabの細かな記法の説明は省略します(inittabのファイルにコメントで書かれています)。/etc/init.d/
配下にあるrcS
というスクリプトを実行しているようです。この中身を確認してみます。
unitv2% cat /etc/init.d/rcS #!/bin/sh # Start all init scripts in /etc/init.d # executing them in numerical order. # for i in /etc/init.d/S??* ;do (中略、スクリプトを順番に実行している) done
コメントの説明にある通り、/etc/init.d/
配下のSから始まる名前のスクリプトを順番に実行しています。だんだん欲しい情報に近づいてきましたね。init.dの中には何が入っているでしょうか。
unitv2% ls -l /etc/init.d total 128 -rwxr-xr-x 1 avahi avahi 1012 Jan 18 2021 S01syslogd -rwxr-xr-x 1 avahi avahi 1004 Jan 18 2021 S02klogd -rwxr-xr-x 1 avahi avahi 1876 Jan 18 2021 S02sysctl -rwxr-xr-x 1 avahi avahi 274 Jan 18 2021 S05avahi-setup.sh -rwxrwxr-x 1 avahi avahi 1167 Apr 6 2021 S05initled -rwxrwxr-x 1 avahi avahi 667 Apr 6 2021 S06wifipwr -rwxrwxr-x 1 avahi avahi 673 Jan 1 00:00 S100setup-priv -rwxrwxr-x 1 avahi avahi 501 Apr 6 2021 S10loadfsko -rwxrwxrwx 1 root root 600 Jan 1 00:00 S110thermal -rwxr-xr-x 1 avahi avahi 1684 Jan 18 2021 S20urandom -rwxr-xr-x 1 avahi avahi 404 Jan 18 2021 S21haveged -rwxr-xr-x 1 avahi avahi 459 Jan 18 2021 S30cgroupfs -rwxr-xr-x 1 avahi avahi 1635 Jan 18 2021 S30dbus -rwxr-xr-x 1 avahi avahi 438 Jan 18 2021 S40network -rwxr-xr-x 1 avahi avahi 617 Jan 18 2021 S41dhcpcd -rwxr-xr-x 1 avahi avahi 581 Jan 18 2021 S49ntp -rwxr-xr-x 1 avahi avahi 285 Jan 18 2021 S50avahi-daemon -rwxr-xr-x 1 avahi avahi 210 Apr 6 2021 S50mosquitto -rwxr-xr-x 1 avahi avahi 445 Apr 6 2021 S50nginx -rwxr-xr-x 1 avahi avahi 531 Apr 6 2021 S50sshd -rwxr-xr-x 1 avahi avahi 916 Apr 6 2021 S80dhcp-relay -rwxr-xr-x 1 avahi avahi 779 Apr 6 2021 S80dhcp-server -rwxr-xr-x 1 avahi avahi 427 Jan 18 2021 S80dnsmasq -rwxrwxr-x 1 avahi avahi 630 Apr 6 2021 S81mdev -rwxrwxr-x 1 avahi avahi 638 Jan 1 00:00 S85runpayload -rwxrwxr-x 1 avahi avahi 741 Jan 1 00:00 S90wifi-conf -rwxrwxr-x 1 avahi avahi 1428 Jan 1 00:00 S95ip-conf -rwxrwxrwx 1 root root 596 Jan 1 00:00 S96ntpdate -rwxrwxr-x 1 avahi avahi 5492 Jan 1 00:00 automount.sh -rwxr-xr-x 1 avahi avahi 423 Jan 18 2021 rcK -rwxr-xr-x 1 avahi avahi 408 Jan 18 2021 rcS
初期化のためのスクリプトが色々置かれていました。ファイル名を見るとSSHの起動(S50sshd
)、Wi-Fiの設定(S90wifi-conf
)はここで処理されることが分かります。
そしてS85runpayload
という、それっぽい名前のファイルもありますね(先のpythonスクリプトは/home/m5stack/payload
にあるのでした)。
unitv2% cat /etc/init.d/S85runpayload #!/bin/sh case "$1" in start) printf "Starting payload: " cd /home/m5stack/payload python3 /home/m5stack/payload/server.py &> /tmp/payload.info & [ $? = 0 ] && echo "OK" || echo "FAIL" ;; stop) printf "Stoping payload: " killall -9 python3 [ $? = 0 ] && echo "OK" || echo "FAIL" ;; restart|reload) $0 stop $0 start ;; *) echo "Usage: $0 {start|stop|restart}" exit 1 esac exit 0
中身を見てみると…ビンゴ!これはserver.py
を起動しています。ついでにサーバのエラーログはtmp/payload.info
に出力されることもわかりました。
以上の検証から、今回のゴールである「画像認識サーバ」が自動で立ち上がるのを止めるには、S85runpayload
を他の場所に移してしまえばよさそうです。
ここで1点補足。このスクリプトの移動にはルート権限が必要ですが、デフォルトではユーザm5stackはsudoを使えません。次の記事に紹介されている手順でsudoが使えるようになります。
unitv2% sudo mv /etc/init.d/S85runpayload /home/m5stack/ unitv2% sudo reboot
再起動してブラウザからunitv2.local
にアクセスしてもサーバが起動していません。変更が反映されていますね!
以上、UnitV2の中身を確認してきました。想像していたよりも普通にLinuxだということが実感してもらえたのではないでしょうか。cd、ls、catなどのコマンドは当たり前に使えますし、「UnitV2だけの特別なコード」みたいなものもありません。ロボットの画像処理のために「Raspberry Piよりも小さくてLinuxが使える開発ボード」を探している方には、きっと有力な選択肢となるでしょう。
次回はクロスコンパイル環境を整えて、UnitV2でHello Worldを動かしてみます。
→次の記事