13
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

#NervesJPAdvent Calendar 2019

Day 8

作って学ぶNerves、BBBでCO2計測

Last updated at Posted at 2019-12-07

この記事は、「#NervesJP Advent Calendar 2019」の8日目です。

昨日はtorifukukaiouさんの「Nervesでtarget(Raspberry Pi等)で動かすときはこっち、host(macOS等)で動かすときはそっち」でした。

今回はElixirを使って組み込みシステムを作ることができるNervesを使い、
CO2計測ができたのでそれを紹介します。

Nerves」とその「インストール」については、ドキュメントが豊富なのでここでは扱いません。

アウトライン

以下の順に紹介していきます。

  • Nervesプロジェクトの作成からBBBでの起動
  • targetをhostから更新する
  • CO2の計測をする
  • 自動起動するようにする

プロジェクトの作成からBBBでの起動

プロジェクトの作成

$ mix nerves.new [project name] # 以下 プロジェクト名はhello_nervesとします
* creating hello_nerves/config/config.exs
* creating hello_nerves/config/target.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.eex
* 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] # Enter
* running mix deps.get
Your Nerves project was created successfully.
# 以下略
$ cd hello_nerves

mix newと 変わらないですね。

BBBに必要なライブラリの取得

$ export MIX_TARGET=bbb # 環境変数MIX_TARGETにbbbを設定し
$ mix deps.get
** (Mix) No SSH public keys found in ~/.ssh. An ssh authorized key is needed to
log into the Nerves device and update firmware on it using ssh.
See your project's config.exs for this error message.

Nervesが動作する端末にはSSH接続ができます。
その際に使用するSSHの鍵の設定がこの時点で必要なようです。

SSHの鍵を設定

上記ではconfig.exsと書かれていますが、config.exsでimportしているtarget.exsに設定があるので書き換えます。

$ vim config/target.exs
# 略
# 公開鍵の設置ディレクトリと名前を作成した鍵に合わせて設定します。
keys =
  [
    Path.join([System.user_home!(), ".ssh", "id_rsa.pub"]),
    Path.join([System.user_home!(), ".ssh", "id_ecdsa.pub"]),
    Path.join([System.user_home!(), ".ssh", "id_ed25519.pub"])
  ]
  |> Enum.filter(&File.exists?/1)
# 略

設定できたらもう一度

$ mix deps.get

firm作成とSDカードへの書き込み

※書き込み先を間違えるとOS逝っちゃうので気をつけて!!

$ mix firmware # 作成
$ mix firmware.burn --device /dev/sdd # 書込、デバイス名は自分の環境に合わせて慎重に選択!!

BBBでの起動

SDをBBBに挿し、SDカードから起動するためにS2ボタンを押しながらUSBケーブルを投入します。
右上のLEDが光りだしたら、S2ボタンから手を離して大丈夫です。

このときの接続構成は以下です。

|bbb(target)|<--USBケーブル-->|PC(host)| 
IMG_2203.JPG

正常に起動できるとpingに応答を返すので、打って待機します。

$ ping nerves.local # デフォルト設定でmDNSが動作しているので、左記で応答を返します。

応答が返ってきたら、SSH接続してみます。

$ ssh nerves.local
Interactive Elixir (1.9.1) - press Ctrl+C to exit (type h() ENTER for help)
Toolshed imported. Run h(Toolshed) for more info
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 print the next messages in the log:

  RingLogger.next

iex(hello_nerves@nerves.local)1> 

ばっちりです。

Toolshedについて

Toolshed imported. Run h(Toolshed) for more info

SSH接続した際に、上の一行が表示されていました。
このToolshedを紹介します。

iex(hello_nerves@nerves.local)1> h Toolshed

                                    Toolshed                                    

Making the IEx console friendlier one command at a time

To use the helpers, run:

    iex> use Toolshed

Add this to your .iex.exs to load automatically.

The following is a list of helpers:

   cat/1          - print out a file
   cmd/1          - run a system command and print the output
   date/0         - print out the current date and time
   dmesg/0        - print kernel messages (Nerves-only)
   exit/0         - exit out of an IEx session
   fw_validate/0  - marks the current image as valid (check Nerves system
    if supported)
   grep/2         - print out lines that match a regular expression
   hex/1          - print a number as hex
   hostname/0     - print our hostname
   ifconfig/0     - print info on network interfaces
   load_term!/2   - load a term that was saved by save_term/2
   lsof/0         - print out open file handles by OS process
   lsmod/0        - print out what kernel modules have been loaded
    (Nerves-only)
   lsusb/0        - print info on USB devices
   nslookup/1     - query DNS to find an IP address
   pastebin/1     - post text to a pastebin server (requires networking)
   ping/2         - ping a remote host (but use TCP instead of ICMP)
   qr_encode/1    - create a QR code (requires networking)
   reboot/0       - reboots gracefully (Nerves-only)
   reboot!/0      - reboots immediately  (Nerves-only)
   save_value/2   - save a value to a file as Elixir terms (uses inspect)
   save_term!/2   - save a term as a binary
   top/2          - list out the top processes
   tping/2        - check if a host can be reached (like ping, but uses
    TCP)
   tree/1         - pretty print a directory tree
   uptime/0       - print out the current Erlang VM uptime
   uname/0        - print information about the running system
    (Nerves-only)
   weather/0      - get the local weather (requires networking)

linuxで見覚えのあるコマンドが並んでいます。
Toolshedはちょっとした便利コマンドの集まりのようです。
通信の確認をしたり、targetの構成を調べたりできそうです。

targetをhostから更新する

|bbb(target)|<--USBケーブル-->|PC(host)| 

mix firmware.burnで毎回SDに書き込みを行うのは手間なので、
Nervesにはtargetをhostから更新する手段が提供されています。

$ mix firmware.gen.script # 実行によりupload.shが作成されます
$ ./upload.sh nerves.local # upload
$ mix firmware && ./upload.sh nerves.local # firmwareの作成とuploadを一度にする

これにより、PCでmix firmware.burnをする必要がなくなり、
BBBにSDを挿したままfirmwareを更新できるようになります。

参考

CO2の計測

firmwareの更新が楽になったので、開発が進められます。
今回使用したCO2センサはS-300L-3V CO₂センサモジュールです。

出力のI/Fはアナログ、PWM、TTL-UART、I2Cがありますが、I2Cで計測します。

センサーのI/F仕様書はスイッチサイエンスの同じページにあります。
ELT社 | Programming Guide I2C Bus

開発は以下の順で進めました。

  1. I2C通信ライブラリの調査
  2. 手動計測
  3. 自動計測開始

I2C通信ライブラリ

Elixir Circuits」というライブラリ群があります。
この中に「circuits_i2c」があります。これを使います。

以下を追加します。

mix.exs
  defp deps do
    [
  ...
      # I2C
      {:circuits_i2c, "~> 0.1"}
  ...
    ]
  end

以下を忘れずに実行。

$ mix deps.get
$ mix firmware && ./upload.sh nerves.local

手動計測

ブレッドボードを使い回路を組みます。
バスはI2C-2を使います。
※BBBのピン配はこちら
※SCL, SDAは内蔵プルアップが機能しているようでした。

IMG_2204.JPG

I/F仕様書をみつつ、やってみると何か値が取れました。

iex(hello_nerves@nerves.local)1> {:ok, ref} = Circuits.I2C.open("i2c-2")
{:ok, #Reference<0.1331158910.268828677.48092>}
iex(hello_nerves@nerves.local)2> Circuits.I2C.write(ref, 0x31, <<0x52>>)
:ok
iex(hello_nerves@nerves.local)3> Circuits.I2C.read(ref, 0x31, 7)
{:ok, <<8, 3, 51, 0, 3, 0, 1>>}

3*256+51=819[ppm]です。大気がおよそ400ppmなので活動分増えてるのかな。
手動計測ができたので、上記を関数化してエラーの取り回しをしてやればよさそうです。

自動計測開始

ここは説明するには長くなってしまうので割愛します。
Application、Supervisor、GenServerの連携のしくみを理解する必要がありました。:wink:
※ほぼこの理解をするために時間を使ったと言っても過言でないです:sweat_smile:

Screenshot from 2019-11-26 14-21-24.png

最終成果物は https://github.com/pojiro/co2_measurement_by_nerves

まとめ

開発環境構築の説明がメインになってしまいましたが、
Nervesを使いBBBでI2C通信によりCO2計測ができました。

もっと真面目にやろうとすると、以下などを詰めていく必要があると思います。

  • 複数のI2Cセンサを使う場合はI2Cバスの排他
  • 計測失敗からの復帰
    • 落ちればSupervisorに起動し直してもらえますが、落ちずにハングする場合があるのでそれへの対応

取得した値をPhoenixへPOSTしWEBブラウザで見られるようにできたら、
WEBからIoT端末までElixirで統一できてかっちょいいですね。
お正月の休みにElixirで環境センサつくってみるのはどうでしょうか?

明日、9日はnishiuchikazumaさんの「ElixirでラズパイのLEDをチカ〜RaspbianOSインストールから〜」です。

それではまた!

「いいね」よろしくお願いします。 :wink:

おまけ

シリアル接続について

仮想シリアル

BBBはUSBの仮想シリアルがあるので、
screenコマンドやtera termでシリアル接続ができます。

$ screen /dev/ttyACM0 115200 # デバイス名は自分の環境に合わせて読み替えて
# エンターを押下して以下が出ればOK
iex(hello_nerves@nerves.local)3>

シリアル

FTDIのUSBシリアルケーブルを使って接続することも可能です。
firmwareの転送ごとにscreenをつなぎ直す必要がないのでこれを使うと便利です。
Kernelの起動ログもみれます。

  1. Download the default erlinit.config file from the system repository for your target.
  2. Place it in your project folder under rootfs_overlay/etc/erlinit.config.
  3. Modify the -c console setting to match the value shown in the UART row of the hardware description table (rpi3 example shown):
rootfs_overlay/etc/erlinit.config
# Specify where erlinit should send the IEx prompt. Only one may be enabled at
# a time.
#-c ttyGS0      # Virtual serial port over the USB interface
-c ttyS0   # Debug UART connector
#-c tty1      # HDMI output

参考

eth0の使用について

以下のように修正することでeth0経由で通信可能になります。
※usb経由での通信はできなくなります
※起動してからIP取得に多少時間がかかるようです

config/target.exs
config :nerves_init_gadget,
  ifname: "eth0",
  address_method: :dhcp, # :dhcpdでなくて:dhcp!
  mdns_domain: "nerves.local",
  node_name: node_name,
  node_host: :mdns_domain

参考

13
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?