産業用オレオレ Nerves マシン ExiBee の作り方（コンセプト編）

これは [#NervesJP Advent Calendar 2021](https://qiita.com/advent-calendar/2021/nervesjp)の15日目です。昨日は @mnishiguchi さんの [ElixirでPNGを画像をRGBA形式の行列に変換したい](https://qiita.com/mnishiguchi/items/7be5b170a1a148b22039)でした。

# はじめに
以前より工場のいわゆる FA (Factory Automation) の現場に Nerves/Elixir を使えないかと画策してます。どうしてそういう気になったかは [Elixir を使うようになった経緯 〜電力システム制御の現場から〜](https://qiita.com/kikuyuta/items/96c3f91a850e9274b0e9) にも書いているので御覧ください。

FAに Nerves を持ち込むにはいくつもの課題があります。その一つに動く堅牢なハードウェアが必要であるという課題があります。この点は Nerves に限らず Linux やらの GPOS (General Purpose Operating System) で動くマシン全般がそうです。工場で使うためには過酷な動作環境に耐える必要があり、Raspberry Pi や BeagleBone といった SBC (Single Board Computer) をそのまま使える場合は限定されます。

**ならば自分で作ってしまえば良いのではないか**

このように考えてこれまでいくつものマシンを作ってきました。今年開発したバージョンで、おおよそ安定した感じがするのでここに御披露する次第です。全国のオレオレハードウェア開発民に届くと幸いです。

![IMG_1779.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260320/8de2116f-6b22-f4cd-220b-2cb930cc1adf.jpeg)


## 歴史
今回のハードウェアはコンセプトづくりから一発で出来たものではありません。紆余曲折の挙げ句に今があります。今回の記事は、以下の第3版の内容です。

- 第0版：ラズパイ2Bそのままで Python/Linux マシン
  - 高温多湿の環境で、かつSDカードへの書込みに対する配慮無しで稀に壊れる
- 第1版：Armadillo で Python/Linux マシン
  - ハードウェアとしてはまずまずだった
  - Python が並行プログラミングに対応してないのでうまく行かない
  - A/D 変換が緩慢で必要な処理が間に合わない
  - コードネーム *BunkaPLC* （ぶんか ぴーえるしー）
    - ハードウェアの微調整でバージョンが 1.0, 1.1, 1.5 とある
- 第2版：Armadillo で Elixir/Linux マシン
  - 第1版同様でより産業用に使いやすくしてみた
  - 現場で使う出番がなかった
  - コードネーム BunkaPLC 2.0、後に *ExiArmadillo* （いち あるまじろ）と改名
- 第3版：BeagleBone ベースで Nerves/Elixir/Linux マシン
  - コードネーム *ExiBee* （いち びー）


## 記事の構成
話全体が長いのでいくつかの記事に分割します。

- 概要とコンセプト（この記事）
- 設計・製作
- ファームウェアのポーティング
- 環境試験

なお、このマシンで実際のソフトウェア・システムを組んだ話は [@32hero](https://qiita.com/32hero) さんが [オレオレハード＋Nervesの設計モデルを考えて実装したよ！](https://qiita.com/32hero/items/58c9d7d37786cb1fcd43) として [#NervesJP アドベントカレンダー](https://qiita.com/advent-calendar/2021/nervesjp) の23日目の記事にしてます。

## 他のアプローチ
FA に Nerves を導入するには、堅牢なハードウェアを用意するだけでは不十分です。システムをネットワーク全体で組上げる場合の効率性・可用性・保守性等を、Nerves が持つもともとの性質に加えてより優れたプラットフォームを用意していく必要があります。

そのような一つの方向性として「1デバイス・1ユニークID・標準API」の構想を進めています。それが実現する未来を想像するために [すまあとリレー を Nerves で作ってみた](https://qiita.com/kikuyuta/items/233fdfab050be2879cc9) のでこちらも御覧ください。

# コンセプト
基本的な考え方はざっくり以下のようなものです。

- Nerves が楽にいごく
  - スクラッチからすべて設計すると Nerves のポーティングが大変になりすぎる
- 商用のPLCを置き換えられる I/O の自由度の高さ
  - I/O 点数、ADC の変換速度、絶縁、端子
  - ネットワーク利用前提
- 気の効いた電源周り
- やる気の出る外観
- できるだけオープンソースとして公開

以下ではもう少し詳しく掘り下げます。

## Nerves が楽にいごく
Nerves は組込み用 Linux を構成する Buildroot で作られています。独自のハードウェアで Nerves がいごくということは **そのハードウェアで Buildroot による組込み Linux を構成できる** こととほぼ同義です。Linux はハードウェアの I/O の差異を Device Tree の概念で吸収します。このため独自のハードウェアを作る場合、Device Tree をちゃんと作ることが必要です。

さて我々の目的はオレオレハードウェアを作ること自体ではなく、Nerves が動く堅牢なハードウェアを作ることです。このため buildroot にかかる時間、すなわち Device Tree をハックする時間はできるだけ短くしたいところです。このため Nerves が動く既存の SBC をベースにすることにします。

[Nerves のサポートする公式のターゲットデバイス](https://hexdocs.pm/nerves/targets.html#supported-targets-and-systems) を見ると（汎用の X86_64 を除いて）SBC向けは大きく以下の3つに分類されます。

- Raspberry Pi
  - ハードウェアの設計自体が公開されていない[^Raspberry-Pi]
  - SoM (System on Module) としてコンピュートボードを使う手はある
    - ラズパイにロックインしてしまう可能性
- BeagleBone
  - ハードウェアの設計が公開されている
    - 元祖 BeagleBoneBlack はもちろん
	- Seeed 製の BeagleBoneGreen やそれの Wireless 版も公開されてる
- OSD32MP1
  - ハードウェアの設計が公開されている
    - Nerves プロジェクトでターゲットにしている Octavo Systems 製開発ボード
	- Seeed 製の STM32MP1 ベースの SBC
  - Nerves のポーティングがなされて日が浅い
    - 公式ターゲットのボードのネットワークI/Fがしょぼい

特定の組織にロックインしないためにはボードのハードウェアが公開されいる必要があり、なおかつ長期に渡って安定して Nerves がいごいているという実績の元に、BeagleBone のハードウェアをベースにして開発することにしました。特に `MIX_TARGET=bbb` でカーネルを作ることができれば上々です。

[^Raspberry-Pi]: ラズパイのハードウェアの一部は公式ページの [Raspberry Pi Documentation](https://www.raspberrypi.com/documentation/computers/raspberry-pi.html)にありますが、回路図は完全ではなさそうです。

## I/O の自由度の高さ
産業用途に使う場合には多彩な入出力に対応する必要があります。

頻繁に産業用で使用されるコンピュータに PLC (Programmable Logic Controller) があります。これらはいくつものモジュールで全体のハードウェアを構成するようになってます。モジュールを装着するレールにバス配線がなされており、一つのCPUモジュールと必要なI/Oのモジュールをレール上に組上げることで、任意のI/Oの組合せを得ることが出来ます。ただし、I/Oモジュール単体では動かすことができません。また、一つのCPUと一つのBUSに全部のI/Oがぶら下がるという欠点もあります。
![plc-bus.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260320/12dce783-7bbe-887f-5473-4a8572ec94fd.jpeg)
Nerves で考えるなら、このようなPLCに見られる構成をとらなくても良くなります。無理やり全部のI/Oを持つ1台のコンピュータにしなくても、すべてのI/OモジュールにCPUを乗せてやって、それらをIP通信させてやることが可能です。
![exibee-bus.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260320/efa8448e-f832-d689-ff00-96b05e4cc78c.jpeg)
今回は、各モジュールをすべて独立のNervesマシンとして、単体でも動作するようにしました。I/O点数が少ないなどで複数のモジュールを使う必要がある場合は、スイッチングHUB等でIP的に接続して全体を構成するように考えてあります。

## 気の効いた電源周り
地味に面倒なのが電源です。ざっと以下の課題があります。

- 電源の接続方法
- 停電発生時のOSへの対応
- 長期無給電の場合のRTCへの対応

### 電源の接続方法
市販の SBC ではACアダプタでDC5Vを供給することがほとんどです。しかしこれは産業用には望ましくありません。一つはACアダプタの信頼性で、もうひとつは5Vを接続するUSBコネクタの信頼性です。民生用のACアダプタは壊れやすいので産業用のを使う必要があります。もっと深刻なのはコネクタで、基本「引っ張ったら外れる可能性がある」ような接続方法は産業用には使うことが出来ません。

FA用のPLCでは電源がDC24Vの場合が多く、それを供給するためにそれなりに信頼性の高い電源モジュールを用意します。接続は、レールに装着する場合にはバスに直結、そうでない場合はO端子Y端子のネジ止めかスプリング端子などの他の端子同様の固定方法を用います。

我々の場合は複数モジュールをEthernet接続する構成をとるので、そもそもネットワークの配線があります。これにさらに電源配線を別途用意すると配線が煩雑になるキライがあります。そこで監視カメラやビルのWiFi-APに用いられるような PoE (Power on Ethernet) を採用することにしました。

ネットワーク用にスイッチングハブを用意する場合に PoE 対応のものを使うことで、ネットワークと電源と両方に同時に対応できます。PoE 付きのスイッチングハブには産業用の高信頼性の製品もありますので、工場等ではそれを選択することになります。

### 停電発生時のOSへの対応
ラズパイも BeagleBone も、割とみなさん IoT で利用する場合には電プチすることが多いかと思います。私もよくやってしまいます。Linux 等の GPOS が動いているマシンでは、これはあまり良いマナーではありません。

さて、では電源が喪失した際に正しくOSをシャットダウンさせようとすると、これはこれで大変です。大元の電源が喪失しても、数十秒程度の時間はボードに電源を供給する必要があります。あと、シャットダウンを開始するために電源断を検出する必要もあります。

今回は、キャパシタを用意して電源喪失時にシャットダウンする時間は電源を供給し続けられるようにしました。ただしキャパシタの容量に制約があるので、電源供給はOSのシャットダウンのみに使うものとして、I/O 全部が動作し続けることは要求しません。

さらに電源断を検出するのに、電源電圧を計測しつづけ、一定以下になったときにCPUに割り込みを発生させる機能を用意しました。これをトリガにしてシャットダウンも出来ますし、さらに機能停止に入ることを SNMP (Simple Network Management Protocol) 等で他のモジュールに対して通知することが可能になります。

### 長期無給電の場合のRTCへの対応
これは絶対時刻を持っている RTC (Real Time Clock) チップに対する電源をどうするか問題です。たいていの RTC を持つ SBC やドータボード（HatやCapeと呼ばれる、SBCに後付するボード）は酸化銀ボタン電池などのバックアップを持っています。これがやっかいなのは5年程度で電池が放電仕切ってしまって交換する必要があることです。

今回のボードはボタン電池による RTC チップのバックアップにしました。ただし、キャパシタにして「無電源で時計が保持できるのは一月ぐらいだけど後から交換の必要がない」という考え方でも良かったかなと思ってます。

## やる気の出る外観
外観も重要です。機能だけ詰め込んでも、見た目がショボいとガッカリです。

今回の前のバージョンを作るときに知人に教えてもらったフェニックス・コンタクト製の ME-PLC タイプのケースがかっこよかったので、それを今回も使うことにしました。以下の写真はフェニックス・コンタクトのホームページから持ってきてます。
![me-plc.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260320/00095d79-ed3a-8413-1d64-22e974cfe75f.jpeg)


## できるだけオープンソースとして公開
これを作るに当たっては Nerves プロジェクトに加えて BeagleBone や Seeed の公開情報を用いています。我々の活動も公開することでできるだけ広く世界に貢献したいと考えています。ですので、ライセンスの制約が発生しない限り全部公開していくという方針にしました。

# まとめ
産業用途に Nerves を導入するために独自のハードウェアを構成することにしました。ここではプロジェクト当初を振り返ってそのコンセプトを書き起こしました。

現在、このマシンを産業の現場で使うプロジェクトが進んでいます。また、この経験を元に Version 4 を構築する計画も進んでいます。また別の機会にご紹介しようと思います。

さて、アドベントカレンダー [#NervesJP Advent Calendar 2021](https://qiita.com/advent-calendar/2021/nervesjp) の方の明日の記事はというと、こちらも @mnishiguchi さんで [NervesのIExをカスタマイズしたい](https://qiita.com/mnishiguchi/items/9e259b8836054bb5cb34) です。お楽しみに！

# 参考文献
- [BeagleBone 関係はこちらから](https://beagleboard.org)
- [Seeed 製 BeagleBone Green](https://beagleboard.org/green)
- [Seeed 製 BeagleBone Green Wireless](https://beagleboard.org/green-wireless)
- [ExiBee 仕様](https://github.com/kikuyuta/exibee/blob/master/concept-jp.md)
- [オレオレハード＋Nervesの設計モデルを考えて実装したよ！](https://qiita.com/32hero/items/58c9d7d37786cb1fcd43)
- [すまあとリレー を Nerves で作ってみた](https://qiita.com/kikuyuta/items/233fdfab050be2879cc9)
- [Nerves プロジェクトがサポートする公式のターゲットデバイス](https://hexdocs.pm/nerves/targets.html#supported-targets-and-systems)
- [Phoenix Contact 製 多機能ケース ME-PLC](https://www.phoenixcontact.com/online/portal/jp?1dmy&urile=wcm%3apath%3a/jpja/web/main/products/subcategory_pages/Multifunctional_housings_ME-PLC_P-01-12-08/8706a764-5158-4867-9fa1-f11065f1af6e)