この記事は「Elixir or Phoenix Advent Calendar 2017」の22日目です.
昨日は@zacky1972さんの「ZEAM開発ログv0.1.3 AI/MLを爆速にしたい! Flow のコードを OpenCL で書いてみる〜GPU編」でした.

:black_square_button::black_large_square::black_square_button: お知らせ :black_square_button::black_large_square::black_square_button:
「fukuoka.ex#11:DB/データサイエンスにコネクトするElixir」を6/22(金) 19時に開催します
私も『ElixirでIoTやってみた』ネタで発表します!是非ともご参加下さい!!

https://fukuokaex.connpass.com/event/87241/

はじめに

こんにちは.
組込み界隈の"Hello, World!"はLチカ(LEDの点滅制御)と謂われています.
えぇーっ!?たった4日間で組込みビギナーを卒業できる開発合宿があるんだって!??

https://swest.toppers.jp/LED-Camp/

さてステマはさておき,先日の勉強会「fukuoka.ex#8(福岡Elixir会):2018年 春のElixir入学式」にて発表した内容を加筆編集しながら,ElixirをIoTボードで動かしたらどうなんの?という異色ネタをお届けしています.

これまでの連載記事では,IoTボード上でElixirが実行できる環境を構築し,それぞれの性能をベンチマークアプリで評価してきました.

Elixir or Phoenix Advent Calendar 2017
 |> ElixirでIoT#0:IoTボードへのLinux環境の準備
 |> ElixirでIoT#1:IoTボードへのElixir環境の構築とEEloTツールキットの紹介
 |> ElixirでIoT#2:いろいろ分かるベンチマークを整備してみる
 |> ElixirでIoT#3:IoTボードで動いた!Phoenixが立った!性能評価と考察

残念ながらボード/アーキテクチャの性能評価までに留まり,IoT屋さんには物足りないところかもしれません.
今回はIoTの醍醐味?であるLチカをしてみましょう!!
ElixirでIoTボードのデバイスプログラミング可能な環境を提供しているNervesというのを調査してみました.

Nervesって何者?

うーんHPのロゴがcool!!

Nerves Projects

HPのTopでは,
「Craft and deploy bulletproof embedded software in Elixir」
と謳われています.bulletproofをどう解釈するか悩ましいところですが,
堅牢な組込みソフトウェアをElixirでお手軽に開発!
を目指しているようです.

  • Platform: たったの12MBでLinuxブートローダとErlang VM/Elixir実行環境を実現!
  • Framework: ネットワーク,I/Oなどのデバドラ機能を提供!
  • Tooling: mix new対応ですぐにプロジェクト開発を開始!

要するにNervesとは,IoTボード上で動作する最小構成のLinuxブートローダ+Elixir実行環境+各種デバドラのパッケージセットと理解してよいかと思います.

このプロジェクト,v1.0.0の正式リリースが2018年5月3日と新しめでありつつ,initial commitは2013年10月と,長期的かつ活発に活動されているようです.素晴らしい!!

現状の対応ボードは,歴代のラズパイに加えて,BeagleBone BlackやLEGO Mindstorms EV3も使えるようです.Linuxブート可能なものなら他のIoTボードへの移植もできるのかも.
この辺りもそのうちいろいろ試してみたいところです.

環境設定

それではNervesを試してみるにあたって,まずはInstallationのページを参考にしてホスト側の開発環境を整えてみたいと思います.
Elixirアプリ/mixプロジェクトの開発はクロス開発1を前提にしています.このため本記事で解説する操作はホストPC上で行います.私はMacとUbuntuの両方で動くことを確認しています.

なお,Erlang/OTPとElixirはインストール済みを前提とします.

$ elixir --version 
Erlang/OTP 20 [erts-9.3] [source] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]

パッケージの導入

Nervesのツール内ではfwupsquashfsssh-askpass辺りのパッケージを使っています.それぞれインストールしていきましょう.

  • Macの場合
$ brew install fwup squashfs coreutils 
  • Ubuntuの場合
$ sudo apt install build-essential automake autoconf git squashfs-tools ssh-askpass
$ wget https://github.com/fhunleth/fwup/releases/download/v1.1.0/fwup_1.1.0_amd64.deb
$ sudo dpkg -i fwup_1.1.0_amd64.deb

以降の操作はMac/Ubuntuで同じになります.

ライブラリアップデート

hexrebarは最新版にアップデートしといてほしいそうです.

$ mix local.hex
$ mix local.rebar

環境のインストール

nerves_bootstrapという名前でHexパッケージとして公開されています.
もちろんコマンドラインから環境をインストールすることができます.

$ mix archive.install hex nerves_bootstrap

これでNervesアプリの開発環境が整いました!

使い方

次は,Nervesの使い方を説明していきます.

プロジェクトの作成

mixで作成できます.途中のFetch and install dependencies? [Yn]では気にせずYを打ち込んで良いです.
以下はhello_nervesという名前のプロジェクトの作成例です.出力も掲載します.

$ mix nerves.new hello_nerves
* creating hello_nerves/config/config.exs
* creating hello_nerves/lib/hello_nerves.ex
* creating hello_nerves/lib/hello_nerves/application.ex
* creating hello_nerves/test/test_helper.exs
* creating hello_nerves/test/hello_nerves_test.exs
* creating hello_nerves/rel/vm.args
* creating hello_nerves/rootfs_overlay/etc/iex.exs
* creating hello_nerves/.gitignore
* creating hello_nerves/.formatter.exs
* creating hello_nerves/mix.exs
* creating hello_nerves/README.md

Fetch and install dependencies? [Yn] Y
* running mix deps.get
* running mix nerves.release.init
Your Nerves project was created successfully.

You should now pick a target. See https://hexdocs.pm/nerves/targets.html#content
for supported targets. If your target is on the list, set `MIX_TARGET`
to its tag name:

For example, for the Raspberry Pi 3 you can either
  $ export MIX_TARGET=rpi3
Or prefix `mix` commands like the following:
  $ MIX_TARGET=rpi3 mix firmware

If you will be using a custom system, update the `mix.exs`
dependencies to point to desired system's package.

Now download the dependencies and build a firmware archive:
  $ cd hello_nerves
  $ mix deps.get
  $ mix firmware

If your target boots up using an SDCard (like the Raspberry Pi 3),
then insert an SDCard into a reader on your computer and run:
  $ mix firmware.burn

Plug the SDCard into the target and power it up. See target documentation
above for more information and other targets.

もうみなまで説明が書かれていて親切ですね.

テンプレートとして出力されるElixirコードを見てみましょう.

lib/hello_nerves.ex
defmodule HelloNerves do
  @moduledoc """
  Documentation for HelloNerves.
  """

  @doc """
  Hello world.

  ## Examples

      iex> HelloNerves.hello
      :world

  """
  def hello do
    :world
  end
end

これをベースとして色々なIoTアプリを開発できそうです.

プロジェクトのビルド

まずは,ターゲットのボードを環境変数の設定によって指定します.
選択肢はTargetsのページにある表のTAG列になります.今回はRaspberry Pi 3 Model Bのrpi3を使っています.

$ export MIX_TARGET=rpi3

あとはいつも通りのmixプロジェクトのビルドと同じですね.
イメージファイル生成のためのmixタスクfirmwareが用意されています.

$ cd hello_nerves
$ mix deps.get
$ mix firmware

これで,ラズパイ3B上で動作するアプリが含まれたイメージファイル(最小構成のLinuxブートローダ+Elixir実行環境+各種デバドラ)が生成されました.

なお初回のmix deps.get時には,おそらくブートローダとErlang VMをビルドするためのクロスコンパイラ環境が~/.nerves/artifacts/にインストールされます.

何が生成されたの?

ちなみに生成されるイメージファイルの実態は_build/rpi3/dev/nerves/images/hello_nerves.fwです.

$ ls -l _build/rpi3/dev/nerves/images/hello_nerves.fw
-rw-r--r--  1 takase  staff    24M  5 13 18:01 _build/rpi3/dev/nerves/images/hello_nerves.fw

確かに24MBと驚くべき小ささです!!

$ file _build/rpi3/dev/nerves/images/hello_nerves.fw 
_build/rpi3/dev/nerves/images/hello_nerves.fw: Zip archive data, at least v2.0 to extract

ということは,,,??

$ unzip _build/rpi3/dev/nerves/images/hello_nerves.fw 

$ ls meta.conf data/
meta.conf

data/:
bcm2710-rpi-3-b.dtb config.txt      start.elf
bcm2710-rpi-cm3.dtb fixup.dat       w1-gpio-pullup.dtbo
bootcode.bin        pi3-miniuart-bt.dtbo    zImage
cmdline.txt     rootfs.img

なるほどなるほど,確かにいろいろ入っていますね:laughing:

TIPS: SSH公開鍵の作成

$ mix deps.get 
** (Mix.Config.LoadError) could not load config config/config.exs
    ** (File.Error) could not read file "/Users/takase/.ssh/id_rsa.pub": no such file or directory

と言われる場合は,SSH公開鍵を以下のように作ってあげてください.

$ ssh-keygen -t rsa -f ~/.ssh/id_rsa 

microSDへの書き込み

これも簡単です.microSDカードをホストPCに繋いで$ mix firmware.burnを実行します.
microSDの接続先は自動認識されますので,接続先が正しければYを打ち込みます.なお,イメージ書き込み時には管理者パスワードを求められます.

$ mix firmware.burn 

Nerves environment
  MIX_TARGET:   rpi3
  MIX_ENV:      dev

Use 59.8 GiB memory card found at /dev/rdisk2? [Yn] Y
|====================================| 100% (27.50 / 27.50) MB
Success!
Elapsed time: 4.330 s

ラズパイでの実行

イメージファイルを焼いたmicroSDカードをラズパイ3Bに差し込み,HDMIディスプレイとUSBキーボードを接続して電源を投下しました.

そして数秒経つと,,,おーiexが立ち上がってきています!
普通のインタラクティブなコードはもちろんのこと,テンプレートのコードhello_nerves.exに入っていたHelloNerves.helloだってもちろん動きます!!

iex.jpg

ちなみにCtrl+C x2をしてもiexが落ちることはありません^^;

さあLチカしてみよう!

Nerves Projectが幾つかのサンプルを提供しています.
その中のBlinkyを使ってみました.

$ git clone https://github.com/nerves-project/nerves_examples.git
$ cd nerves_examples/blinky
$ export MIX_TARGET=rpi3
$ mix deps.get
$ mix firmware
$ mix firmware.burn

おーなんとなんと!お分かりになりますでしょうか??
ボード左下にある緑色のLEDが見事にチカチカしています!!!

ledtikatika2.gif

hello_gpiohello_phoenixなどなど,GPIOやPhoenixフレームワークを使ったサンプルも提供されています.また,各種センサ/アクチュエータをお手軽に繋げるGroveモジュールのライブラリもあるようです.
この辺りを使えばIoTアプリの構築もお手のもの!?これからぜひ触ってみたいと思います.

使ってみた感想

Elixir環境でここまでお手軽にさくっとIoTデバイスのアプリ開発を始められるとは,非常に驚きでした.IoTワールドでElixirの生産性の良さや並列性能を活かすことができますので,新たなアプリ創出の機運が高まってきていますね.

ただ,クロス開発なのはちょっと面倒だと感じました.
いちいちmicroSDに焼くのも面倒ですし,いちいち電源を投下して数秒経たないと結果が分からないのはストレスに感じます.複数ボードへの本番環境へのデプロイならお手軽になる状況とも考えられます.調査が及んでいないので提供されているかもですが,ホスト開発2の方法やリモートデバッグの方法が無いとツラいところです.
イメージファイルのサイズの小ささは魅力ではあります.しかしながら,ラズパイのようなLinuxがきびきび動くIoTボードは,そもそもメモリ量が潤沢ですので,メモリサイズはそこまで重視する要素にはなりません.それであれば,Linuxを載せちゃって生のelixir/iex環境でホスト開発したほうが手っ取り早いよなぁと感じました.(なお,Linuxが動かせないクラスのボードを目指すなら,12MBでも全然大きかったりします)

ホスト開発だと「elixir_ale - Elixir Actor Library for Embedded」というのが使えるらしいという情報もあります.王道としてはNIF/BIFに飛び込むのもアリでしょう.
IoTアプリのためのElixir実行環境/開発環境,うーん研究材料としてとっても面白そうだ!!

まとめ

  • ElixirでIoT開発ができます!!
  • Nervesを使ってお手軽に組込みソフトウェアを開発!
    • IoTボード上で動作する最小構成のLinuxブートローダ+Elixir実行環境+各種デバドラのパッケージセット
    • ホストPC上のmixシステムでクロス開発を実現
    • テンプレートのアプリ込みでもイメージファイルはたったの24MB!

皆さんもElixirを片手にIoTワールドへ飛び込んでみませんか!??

次回の発表駆動開発の機会である「fukuoka.ex#11:DB/データサイエンスにコネクトするElixir」までに,さらなる調査や開発を進めたいと思います!私の発表もお楽しみに!!

明日のAdvent Calendarは@piacereさんによる
ExcelでElixirマスター5回目:Webにグラフ表示
です.


  1. クロス開発とは,実際の実行環境とは異なるシステム(ホストPC)で開発を行うことを指します.ホストのPCで実装とビルドを行い,バイナリ等をターゲットのIoTボードなどに転送して実行・デバッグを行います.例えばArduino IDEだと,MacやWindows上でコーディングして,そのバイナリをArduinoボードに転送して実行していますよね. 

  2. 逆にホスト開発とは,実行環境と同じシステム上で開発を行うことを指します.例えばRaspberry PiにSSH接続でログインして,その上のエディタでPythonやElixirのスクリプトをコーディングして実行することを想像してください. 

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.