Raspberry PiとSimulinkでホームLED

## この記事について
前回の"Raspberry PiとSimulinkでLED調光+色変更"では、3色LEDの光量調整や色の変更までを試していますが、これをMQTT経由で制御することでホームLEDを構成します。本記事ではMQTTの環境セットアップと、SimulinkモデルにMQTT通信を加えるところについて説明しています。

https://qiita.com/kureta90/items/d5fea1f81b79c8f1b2be

## ハードウエア
"Raspberry PiとSimulinkでLチカ！"と全く同じ構成です

https://qiita.com/kureta90/items/5554117f0a94df89480d

今回はMQTTで指令値を渡すので、スイッチはなくてもよいです


## ソフトウエア(MATLAB/Simulink)
・MATLAB/Simulink
・Simulink Support Package for Raspberry Pi Hardware(アドオン)
こちらも"Raspberry PiとSimulinkでLチカ！"のようにアドオンのインストールまで済ませます。

## MQTT(Mosquitto)
MQTTのブローカーはネットワーク上のどこにあってもいいのですが、今回は開発環境であるMATLAB/SimulinkがWindows上で動作するので、このWindows PCに、お手軽にMosquittoをインストールします。既にNode.jsなどでMQTTネットワークを構築している場合はそれでもよいです。
Mosquittoのインストールや通信の設定は、こちらの記事を参考にさせて頂きました。

https://qiita.com/yomori/items/74a9af05a8ccdda12e2f

こちらに沿って、Mosquittoブローカーを起動しておきます。

## MQTT(Node-RED)
Node-Redはオープンソースでビジュアルプログラミングできるフローベースの開発環境で、ブラウザ上のGUIでフロー図を作成することができます。Node-RedはホームLEDのコントローラとして使用します。ブラウザ上のフロー図でMQTTトピックを発生させたり受信したりできます。Simulink開発環境やMosquittoブローカーをインストールしたのと同じWindows PCにセットアップすることとします。セットアップに関しては以下の記事を参考にさせて頂きました。

https://qiita.com/HiguchiTakahiro/items/3c024c79e5f463936ecc

Node-REDを起動してブラウザを開いた後、右端の三本線から、
![nodered1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/11b331af-bceb-faed-ada3-af112febe25a.png)
"読み込み"をクリックして、
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/8eb33530-165a-403a-843f-f80ceb2aee3f.png" width="200">
"読み込むファイルを選択..."から、.json形式のモデルを読み込みます。このとき"新規のタブ"を選んでおくと、
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/5899dd57-4b44-fd9a-f1c1-99d3f742077a.png" width="400">


.json形式のモデルは、以下のテキストをdemo_MQTT.jsonファイルとして保存し、上記ファイル選択から指定してください。
``` demo_MQTT.json
[{"id":"d0d3abb8.8d8498","type":"mqtt out","z":"f43b61f4.2b9f","name":"to_rasp3B_intensity","topic":"home/rasp_3B/val","qos":"0","retain":"false","broker":"49b108fc.5ad008","x":373,"y":380,"wires":[]},{"id":"90d66f68.ec985","type":"inject","z":"f43b61f4.2b9f","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"100","payloadType":"num","x":113,"y":380,"wires":[["d0d3abb8.8d8498"]]},{"id":"b09c0fe1.833a1","type":"mqtt in","z":"f43b61f4.2b9f","name":"from_rasp3B_state","topic":"home/rasp_3B/state","qos":"2","datatype":"auto","broker":"49b108fc.5ad008","x":133,"y":620,"wires":[["f1349853.a88488"]]},{"id":"ad974d1c.0ce3e","type":"mqtt out","z":"f43b61f4.2b9f","name":"to_rasp3B_mode","topic":"home/rasp_3B/mode","qos":"0","retain":"false","broker":"49b108fc.5ad008","x":370,"y":540,"wires":[]},{"id":"29c1266a.6b134a","type":"inject","z":"f43b61f4.2b9f","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"99","payloadType":"num","x":113,"y":540,"wires":[["ad974d1c.0ce3e"]]},{"id":"f1349853.a88488","type":"debug","z":"f43b61f4.2b9f","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":373,"y":620,"wires":[]},{"id":"28735e51.d51e42","type":"inject","z":"f43b61f4.2b9f","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"60","payloadType":"num","x":113,"y":420,"wires":[["d0d3abb8.8d8498"]]},{"id":"1d6a7f89.3e3fc","type":"inject","z":"f43b61f4.2b9f","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"20","payloadType":"num","x":113,"y":460,"wires":[["d0d3abb8.8d8498"]]},{"id":"49b108fc.5ad008","type":"mqtt-broker","z":"","name":"mosquitto","broker":"192.168.1.4","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""}]
``` 

すると、以下のようなフロー図が現れます。左側のボタンを押すと、数値がトピックとして送出されます。線でつながれたピンクのブロックはmqtt_outノードで、クリックすると
![nodered4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/a1632309-357a-18fd-c9a9-da80ad84a64e.png)

トピック名を指定したり、"サーバ"の編集ボタンから
![nodered5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/3213e267-14b5-771a-6e3c-2dc9a92606d6.png)
ブローカーアドレスを設定できます。お手許のMQTT環境に合わせてブローカーアドレスを設定してください。ブローカーアドレスはMosquittoをインストールしたPCのIPアドレスとなります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/fcca12e7-358b-cbe6-671b-5832306a2890.png" width=500>
どれか一つのノードで変更すると、フロー内の他のノードにも変更が反映されます。
"デプロイ"をクリックすると、このフローはブラウザに記憶され、次回起動したときもこのフローが立ち上がります。
![nodered7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/2d9fff9f-2c17-843b-2118-6890a2b126ce.png)


これでMQTT関連の設定は完了です。ホームLEDのコントローラも、なんらか端末があった方がいい、という場合はNode-REDのかわりに別のRaspberry Piや他のMQTT対応機器を使用できますが、トピック送受信をモニタできて判りやすいため、今回はNode-Redを利用します。
Node-Redはイベントドリブンなので非常にわかりやすくフローが書けますが、内部にモードやステートを持つような記述はすこし面倒です。今回は、色モードの保持はSimulink側のStateflowで行い、Node-REDからはモードを変更するトリガを出すようにします。

以下、Simulinkのモデルについて説明します。

## Simulinkモデル
Simulinkモデルは前回記事"Raspberry PiとSimulinkでLED調光+色変更"のモデルをベースに、明るさのシミュレーション入力のノブの代わりに、MQTT入力ブロックを追加しています。
また色モード変更スイッチの代わりに、MQTT入力ブロックを追加しています。
色モードのステートはこのモデル内で管理しているので、現状どのモードにあるかを、コントローラであるNode-REDにMQTTブロックで返しています。
![model_MQTT.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/0567d9e7-c6d8-a2dd-d498-388ffae90b28.png)
MQTTブロックでは購読するトピック名を指定します。トピック名はNode-REDのフローに記載したパブリッシャ/サブスクライバと対応させます。
![topic_lumination.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/65f5d6ea-59e5-829b-7c94-256657425513.png)
明るさ指定トピック    home/rasp_3B/val
色モード変更トピック  home/rasp_3B/mode
色モード報告トピック  home/rasp_3B/val

なお色モード報告トピックは、ステートに変化が起きたときのみ発行するため、Enabled subsystem内に記述しています。
![pub.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/f3f59abc-b799-57a3-ff4d-6f049af2d20d.png)

## MQTTノードとしてのSimulinkモデル
アルゴリズムへの入力のところにサブスクライバーを、出力にはパブリッシャーを配置すると、モデル全体がノードとして動作します。

ターゲットであるRaspberry Piからは、ブローカーのアドレスにアクセスする必要がありますが、以下のように設定します。"ハードウエア"タブの"ハードウエア設定"のボタンから"コンフィギュレーションパラメーター"を開きます。
![button_hardware_settings.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/bd564925-8645-a8cf-11c5-f1f6d31dcacc.png)
"Target hardware resources"の"MQTT"の項目で、Broker Addressのところに、ブローカーアドレスを指定します(MosquittoをインストールしたPCのIPアドレス)
![conf_MQTT_addr.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/c5a90f75-d1a1-e2ec-ec21-c5bd21e372b5.png)

なおRaspberry PiのサポートパッケージではMQTTの他に、ミドルウェアとしてはWebソケットやROSにも対応しているので、同じようにノードを作成してネットワーク上で動作するエッジデバイスを作成できます。

## 動作確認
Node-REDのフローを稼働状態として、一方でSimulink側はエクスターナルモードで動作確認
![ext_mode.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/39cec1de-0373-638a-9aa6-66e3ba82d9fc.png)

Node-Redで明るさや色変更のボタンを押すと、Raspberry PiのLEDが指令のトピック通り動作している様子が判ります。
![Node-RED_LED.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/977b9b3b-0a66-4435-f527-fbd05bc29cdf.gif)

以上で動作確認ができたので、エクスターナルモードではなく(内部変数を参照しない)、最終的なコード生成を行い、Raspberry Piにデプロイします。
![dep_mode.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/2df10952-7d34-d9f4-0cfb-84b436485c8e.png)

なお、生成された実行ファイルを、Raspberry Pi起動時に自動的に実行するには、"コンフィギュレーションパラメーター"で"Run on boot"にチェックを入れます。
![run_on_boot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/ae1bc32a-3a0c-2246-8b96-bd2a2f88da26.png)

デプロイ後は、Simulinkとは関係なく、Raspberry Pi単体でスタンドアローンでIoT機器として動作します。SimulinkのRaspberry Piサポートパッケージでは、GPIOだけでなく様々なデバイスがカバーされているので、例えばマイク入力から設備の予知保全をしたり、画像入力から害獣検出をするなど、夢が広がりますね。予知保全についてはまた別途記事にいたします。