NervesでのEV3ファームウェア開発

Nervesは(RailsやElixir由来の)Web開発体験を組込みLinuxファーム開発に組み入れたという点でユニークです。IoT時代に注目されるべきプラットフォームだと私は確信します。

EV3はLEGOが販売してプログラミングできるLEGOで、ロボットなどが作れるものです。 Wikipedia Lego Mindstorms EV3 日本ではEV3を使ったロボットコンテストが開催されていますし、EV3を授業や研修、研究に使っている事例も目にします。私の知り合いにもEV3をお持ちの方がいるので、私はそういう方々とこのNervesでの開発体験を共有したいなと普段から考えています。

Nervesチームは去年の2018/9月頃までLEGO MINDSTORM EV3をサポートしていましたが、 利用者数があまり多くない割にはメンテナンスコストが高いことを理由にサポートを打ち切りました。 fhunlethさん EV3サポート終了のおしらせ

EV3の発売日は2013年9月でそれ以降のハードウェアの更新はありません。じゃあ何にコストがかかっているのかというとソフトウェアです。ev3devというEV3向けのLinuxがありまして、そのソースをEV3向けNervesへ移植しているようです。fhunleth さんはev3devの更新頻度が高くてNerves側への反映の手間がかかっているというとおっしゃっています。

Nervesは2018/9時点で1.3がリリース済みで、現在リリースされている1.5と使い勝手は大きく変わりないと私は思います。古いソースコードをわざわざ掘り起こして使っていただく意義も十分あります。そこで、まずは現時点での(2019/12/15)開発環境の設定方法をまとめました。

開発環境の準備

EV3用のプロジェクトを作るためには、インストールするバージョンの制約があります。 結構難しかったのでバージョン設定は下の手順を見ながら正確にインストールすることをお勧めします。

インストール手順

erlangとelixirのバージョンは以下の通りにしてください。

$ asdf install erlang 21.3.8.6
$ asdf install elixir 1.7.3
$ asdf global erlang 21.3.8.6
$ asdf global elixir 1.7.3

nerves用のmix taskが入っている nerves_bootstrapをインストールします。 versionを1.3.2を使うよう気をつけてください。 確認は mix archiveでできます。 これをすると nerves_bootstrap のバージョンが上書きされることに注意です。

$ mix archive.install hex nerves_bootstrap 1.3.2
$ mix archive
* hex-0.20.1
* nerves_bootstrap-1.3.2
Archives installed at: /Users/yoshinori/.asdf/installs/elixir/1.9.1-otp-21/.mix/archives

nerves_bootstrapを最新に戻したい場合はもう一度インストールしましょう。

$ mix archive.install hex nerves_bootstrap

プロジェクトの雛形作成

nerves_ev3_exampleプロジェクトを新規作成します。 依存ライブラリはこの時点でインストールしないでください。 この後インストールする nerves のバージョンを固定する必要があるからです。

$ mix nerves.new nerves_ev3_example --init-gadget
Fetch and install dependencies? [Yn] n

フォルダへ移動し、MIX_TARGETを設定します。

$ cd nerves_ev3_example
$ export MIX_TARGET=ev3

nerves のバージョンが1.4.0がインストールされるようにします。 1.3.2の方が相応しい気もするのですが、ビルドエラーを解決できませんでした。 1.4.0をインストールください。

mix.exs

  # Run "mix help deps" to learn about dependencies.
  defp deps do
    [
-      {:nerves, "~> 1.3", runtime: false},
+      {:nerves, "~> 1.4.0", runtime: false},
      {:shoehorn, "~> 0.4"},
      {:ring_logger, "~> 0.4"}
    ] ++ deps(@target)
  end

依存ライブラリをインストールします。

$ mix deps.get

リリースフォルダにリソースファイルを設置します。

$ mix nerves.release.init 

ファームウェアをビルドします。

$ mix firmware

_build/ev3/dev/nerves/images/nerves_ev3_sample3.fwファームウェアができているはずです。

ファームアップ用のスクリプトを生成しておきます。

$ mix firmware.gen.script

下のコマンドでファームアップできるので便利です。 ssh越しにファームアップするので、パスワードを要求されたら入力してください。

$ ./upload.sh

開発

EV3のmini USBポートと開発PCをつないでください。 sshでEV3にログインして作業してみます。 この後パスワード等を入力を要求されたら入力してください。 以下のように iex が始まります。

$ ssh nerves.local
Enter passphrase for key 'XXXX': 
Interactive Elixir (1.7.3) - press Ctrl+C to exit (type h() ENTER for help)
The Nerves.Runtime.Helpers have been removed. Use https://hex.pm/packages/toolshed instead.
RingLogger is collecting log messages from Elixir and Linux. To see the
messages, either attach the current IEx session to the logger:

  RingLogger.attach

or tail the log:

  RingLogger.tail

iex(1)> 

EV3に繋がるデバイスとはdevfsで通信できます。 lsコマンドで通信IF(ファイル形式)を調べてみてください。 サーボモーターを装着した場合、以下のパスにモーターのIFが生えています。

ls "/sys/class/tacho-motor/motor0/

あとはFile.readやFile.writeを駆使してモータを制御してみてください。 Elixir File

残念ですが時間切れなので、記事はここまでです。

参考情報

Nervesの歴史をさかのぼっていつのNervesが使えそうかを調査しました。githubnerves/nerves_bootstrapリポジトリのログを見ると、Remove ev3 target and bump bbb to 2.0を見つけました。 nerves_bootstrapはこのコミット以前のv1.3.2 が最後だとわかります。

nerves_bootstrap はNervesの開発を支援してくれるツール群です。mix nerves.newで新規プロジェクトを作るときに使います。mix nerves.newのソースを見ると必要なライブラリのバージョンがわかります。

nerves_bootstrap

  @nerves_vsn "1.3"
  @shoehorn_vsn "0.4"
  @bootstrap_vsn "1.0"
  @runtime_vsn "0.6"
  @ring_logger_vsn "0.4"
  @init_gadget_vsn "0.4"
  
  ...
  
  defp nerves_dep("deps/nerves"), do: ~s[{:nerves, "~> #{@nerves_vsn}", runtime: false}]

ここから{:nerves "~> 1.3"}はNerves 1.3系がヒントになりそうです。

elixir 1.9.1 と erlangは 22.0.1 を使っているとmix firmwareでエラーが出ます。

** (Mix) Major version mismatch between host and target Erlang/OTP versions
  Host version: 22
  Target version: 21

This will likely cause Erlang code compiled for the target to fail in
unexpected ways. Install an Erlang OTP release that matches the target
version before continuing.

なので erlangは21を使うことにします。

elixir のバージョンですが、1.9.1 を使うと以下のwarningが発生するので、 1.7.3を使います。 これは 2018/9月頃にリリースされたバージョンです。

$ mix firmware
==> nerves
warning: the dependency :nerves requires Elixir "~> 1.6.0 or ~> 1.7.3" but you are running on v1.9.1