RaspberryPi+Arduino、オムロンPLC、Intel Galileo でMQTTしてみた話

2014/3/21 オムロンPLC, Intel Galileoを追加した図を追加。

やりたかったこと

  1. クラウド(IaaS)上のサーバー(MQTTブローカー)ごしにセンサーの値を送受信して遠隔地の機器を制御した場合にどの程度リニアに制御できるか知りたかった。
  2. 同じくクラウド(IaaS)上のサーバー(MQTTブローカー)ごしにセンサーの値を送受信してブラウザ上でグラフ描画した場合にどの程度リニアにセンサーの値がグラフに反映されるか知りたかった。
  3. Erlang/OTPで組込み側のソフトウエアを組んだ場合の感触を知りたかった。

特に、ある端末のセンサー値をMQTTプロトコルを介して別の端末に配信した場合の機器制御がどの程度のリニアさなのか、がもっとも知りたかった事です。
この後にある動画で、僕が手で回してるダイヤルと、それによって回転するサーボは間隔が15cmほどですが、実はこれらは電気的には繋がっておらず、はるか10,800km彼方のニューヨークのサーバーを通して繋がっています。そのような構成で、インターネットを通じて離れた場所にある機器を制御した場合にどの程度のリニアさが得られるのかを今回試してみました。

MQTTプロトコルについて

MQTTプロトコルについては、下記サイトを参照させて頂きました。

「MQ Telemetry Transport (MQTT) V3.1 プロトコル仕様」
https://www.ibm.com/developerworks/jp/websphere/library/wmq/mqtt31_spec/

「MQTT コトハジメ
https://gist.github.com/voluntas/8238751

「MQTTについてのまとめ」そこはかとなく書くよん。
http://tdoc.info/blog/2014/01/27/mqtt.html

「HTTPからMQTTへ - IBMが提唱するモノとモノがつながる時代に最適化したプロトコル&アプライアンス
http://it.impressbm.co.jp/special/2013/12/09/5313

用意するもの

  • RaspberryPi(2個)
  • Arduino uno(2個)
  • 可変抵抗(1個)
  • サーボ(1個)
  • それらを繋ぐジャンパワイヤー

です。RaspberryPiを無線LANでネットワークに接続する場合は無線LAN子機も必要です。
今回、Arduinoは単にアナログ、デジタルデータの入出力のために使用します。Arduino内で制御プログラムは組まず、arduino IDEに入っている「Standard Firmata」というスケッチを入れただけのものです。

あ、それともちろんMQTTブローカー(サーバー)が必要です。今回は@voluntasさん実装の時雨堂MQTTブローカーを使わせて頂きました。ありがとうございます。
それと、このページを読んでいる人は大概知っておられると思いますがRaspberryPiとArduinoについては以下の通りです。

RaspberryPi
RaspberryPiは手のひらサイズの安価なコンピュータ基板です。CPUは700MHz、メモリは512MBと十年前のノートパソコンと同等近い性能を持ちLinuxが稼働可能(raspbianというDebian GNU/Linuxを元にした専用ディストリビューションあり)、ボード単体では4,000円程度で購入する事ができます。

Wikipedia:RaspberryPi

Arduino uno
Arduino unoはアナログ入力6点、デジタル入出力14点を備えた基板。単体で使用するだけでなく、Firmata(ファルマータ)プロトコルを通じてPCなどから制御することでもできる。ボード単体では3,000円以下で購入可能。

Wikipedia:Arduino


構成

構成は上図のとおりになります。
基本的にpi-001がアナログ、デジタルデータをブローカー(サーバー)に送信、pi-002はそのデータを受け取って自身に繋がった機器を制御します。

なお、TCP/IPセッションは常に端末側からサーバーに対してオープンし且つそのセッションを維持する為、端末側に固定IPアドレスは不要ですし、会社や家庭のLAN内にあっても特に問題はありません。このあたりは地味ではありますがMQTT良いなと思いました。

  1. 各RaspberryPiとarduinoはUSBケーブルを通じてアナログ・デジタルデータを送受信します。
  2. Arduinoからデータを受け取ったRaspberryPi(pi-001)はそれをインターネットを通じてサーバー(MQTTブローカー)へ送信(publish)します。
  3. データを受け取ったサーバー(MQTTブローカー)はトピックの内容を見て、そのトピックを受信待機(subscribe)しているRaspberryPi(pi-002)へ、インターネットを通じてデータを送信します。
  4. データを受け取ったRaspberryPi(pi-002)は受け取った値(0〜1024)を角度の0〜180度に変換し、USBケーブルを通じてArduinoにサーボ制御要求を出し、サーボが回転します。
  5. 同様のデータをWebSocketを通じて受け取ったブラウザでは、最新のデータでグラフを更新します。

なお、ブラウザでのグラフ描画にはフリーのグラフ描画ライブラリ、ccchartを使わせて頂きました。WebSocketをサポートしている上に見た目も綺麗で見やすいので気に入っています。

デモ動画
で、実際に動かしてみた様子はこんな感じです。

サーバーはニューヨークにあるとの事ですが、太平洋を渡って一往復してるにしては結構いい反応速度です。
これ以外にpi-001に繋がったタクトスイッチをON、OFFしてpi-002のLEDを光らせてみましたが、遅延はどんなに長くても1秒以内、だいたい平均して0.5秒くらいでした。

感想
MQTTの興味深いところは、従来のセンサーデータ収集ネットワークと異り、最初から機器間の相互制御を念頭に置いた設計になっているところだと思います。
そのため、TCP/IPセッションは常にオープンしっぱなしであり、従ってソケットオープンの為の時間が0となるため、かなりリニアにデータの送受信ができます。実際今回の実験を見ても、サーバーは10,800km彼方のニューヨークにあるわけですが、電気信号と同等とはいかないまでも待ち時間は長く見積もっても1秒以内でした。サーバーが国内に有れば反応速度は更に早くなる事が予想できます。

課題としては、MQTTの特徴でもあるTCP/IPセッション張りっぱなしの部分で、サーバー側で多数のクライアントの通信をどう捌くか、という所かと思います。さらにそれをインフラとして運用する場合、サーバーがダウンすると端末制御が止まるだけでなく、サーバー復活時には一気に端末からの再接続が始まる訳で、クラスタを組むなどして(クラスタ単体でのダウンはあるとしても)絶対にシステム全体がダウンしない運用を念頭においてシステム構成しないといけないなーと思います(とはいえ絶対は無いので、その場合にどうするか、も考慮が必要と思います)。

なお、動画の時点では0.3秒おきにアナログデータをpublishしてますが、それだと変化が無い場合には頻繁すぎるかなーと思いましたので、現在は通常時は3秒おきにしておき、ダイヤルが操作されるなどして一定以上の変化が有ると、その間は0.3秒間隔で送るように変えました。TCP/IPの再送なども考慮すると常時1秒以下の間隔で送るのはちょっと辛いかなと思ってそうしたのですが、どれくらいの間隔で送るのがいいのか、はケースバイケースで考慮が必要と思います。


追記: 2013年3月21日

追記1:オムロンPLC, Intel Galileoボードに対応
上記に続き、オムロンPLCのFinsプロトコルに対応しました。またGalileo上でもほぼそのまま動作しましたので追加。
ただしGalileoのGPIO特有の部分は現在実装してるところです。GalileoをサポートしたいのはGalileoはこれ一枚でアナログもデジタルも取れるからです。

なお、開発中の端末側アプリのレポジトリはこちらです(サーバーサイドは前述の通り時雨堂のvoluntasさん実装のブローカーとの通信となります)。
https://github.com/hiroeorz/marionet-device

Erlang/OTPで組んでいます。速度やメモリ使用量ではCに比べて不利ですが、M2Mアプリで必須となる並列処理やプロセス停止時の自動再起動などで楽ができると思ったので。
それと端末側でセンサーなど各種機器とやりとりする際のプロトコルはバイナリフォーマットが多いので、型やサイズを指定してのバイナリ生成や、バイナリパターンマッチを持っているErlang/OTPは、その変でもらくちんです。
あ、それと僕のアプリではあんまり関係ありませんが、Erlang/OTPのGCはプロセス毎に張り付いているのでGCの為に全体が停止する事が無いってエロい偉い人がいってました!

あと、オムロンのPLCと通信できるようになりました。まあ1年くらい前に興味本位でfinsプロトコルを喋るErlangアプリ書いてみたので折角なので使ってみたくらいの事ですが。オムロンのPLC(プログラマブル コントローラ)はUDPのfinsプロトコルを介してDMエリアにアクセスできます。

* FinsプロトコルオムロンPLCがシリアルまたはネットワークを介して通信するための公開プロトコルです。

制御プログラムはこのDMエリアに値を書き込んだり読み込んだりできるので、例えばある場所にある端末でセンサーの値がDMエリアに常に書き込まれてるとして、そこから数kmあるいは地球の反対側にある端末に繋がったPLCのDMエリアにほぼリアルタイムに同期する事が可能です。地球の反対側のDMエリアと同期して何に使うのかはわかりませんが同じ国内程度なら色々用途が有りそうです。


追記2:設定用のWebインターフェイスを追加
今までボードにSSHでログインしてErlang形式の設定ファイルをvimなどで編集する必要が有りましたが、簡単なWebインターフェイスを追加しました。
こちらはcowboyでWebサーバーをアプリに組込み、クライアントインターフェイスAngularJS、あとデザインで楽する為にTwitter Bootstrapを使っています。

MQTTの通信設定

MQTTのSubscribe設定

GPIOの設定

シリアル接続したArduinoの設定

オムロンPLCの通信設定

オムロンPLCの監視対象DM(データメモリ)の設定