Raspberry Pi あらゆるデバイスをSimulinkに接続

## この記事について
SimulinkでRaspberry Piの開発をする場合、ハードウエアデバイスとの接続はサポートパッケージを利用して、ブロックを配置するだけで実現できます。
![Block_Hardware.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/4dbcedea-9dfe-b9d3-2400-deb4f4259e2f.png)
ブロックの基本的な使い方は詳細は下記リンクを参照ください。

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

マイクやカメラ等、ほとんどのニーズをカバーするブロックが用意されていますが、もっとマニアックな？ デバイスを接続したいときはどうしたらよいでしょう？

![Devices.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/1ffcec97-01d5-c3d3-bfc0-f4c1024196fa.png)

ROSやMQTT、WebSocketのようなミドルウエアを利用して簡単に済ませる手がありますが、デバイス側がノード化できる必要があります。
Raspberry Piにつながるデバイス自体は多く(=Linuxで管理できるデバイス)、参考記事などもたくさんある中で、こういったデバイスをSimulinkに接続できたら...
本記事は、プロセス間通信を用いて、Linuxで管理できるデバイスは全てSimulinkにつないでしまおう！という内容です。

## 無線？有線？　物理的接続方法はあまり関係ない
実はSimulinkのマイクやスピーカーのブロックも、Raspbian OSの音声関連ライブラリALSA経由でデータを受け取っています。なので例えばRaspberry Pi+Simulinkで、BLE(Bluetooth Low Energy)経由でマイクを繋ぐときは、この面倒は全てALSAが見るため、物理的な接続がBLEでもUSBでも、Simulinkからすれば関係ありません。SimulinkブロックでBluetoothによって無線のマイクが接続できます(本記事の内容も無用です)。
![ALSA_Block_system.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/c418e563-6252-5444-6764-78dbd3ebc678.png)

このように、Raspbian OSおよびそのドライバ(音声ならALSA)が管理しているデバイス接続の土管に相当するようなプロトコルはOSとドライバが面倒を見るので、有線か無線かといったような物理的な接続方法は問題ではなく、問題になるのは接続するデバイスについて、ドライバ等が存在してそれ経由でコントロールできるか？ということになります。

## ドライバとOSに任せる
上記の音声関連のALSAの他に、Webカメラブロック(仮想ビデオドライバV4I2)、CAN (CAN-Utils)などは、Raspbian OSの基本的なドライバを使用していて、ブロック内でドライバもコントロールできます。
一方、ブロックが用意されていないデバイスでも、ドライバ経由で所望のセンサ測定値などにアクセスできるなら、Simulinkとプロセス間通信でデータをやり取りする手があります。上記のようなブロック一つで済むデバイスに比べひと手間増えますが、汎用的に対応できるので重宝します。

![Driver_SimulinkBlock.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/382bfa4e-c957-f44c-548a-889037d5c70c.png)
![Clibraly_system.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/daa5dd88-b71c-6d88-ded7-a52dcf2597e3.png)

## C? Python? CLI? (Simulinkの外で)
色々なデバイスがありますが、ドライバの配布形式はほぼ、下の3つのいずれかでしょう。
1. C/C++　　　Cライブラリをダウンロード、サンプルコードなどをビルドして使用
2. Python　　　Pythonライブラリをpip install。Pyhtonコードを起動して使用
3. CLIコマンド　apt installでインストールして、シェルスクリプトで使用

これらのライブラリを使用して必要なデータを取得し、プロセス間通信でSimulinkに転送しようというわけです。

## プロセス間通信
SimulinkのRaspberry Pi向けサポートパッケージには"NNG"というブロックがあります。NNGはNanomessage Next Gen の略で、従来共有メモリやFIFOを用いるしかなく、やや敷居の高かったプロセス間通信を、メッセージとしてやり取りする技術です。

https://github.com/nanomsg/nng

SimulinkのNNGブロックではNNGメッセージとして他のプロセスとデータを授受できます。
つまり！Linux(Raspbian OS)上でライブラリを通じてデータにアクセスできるデバイスはSimulinkに接続できる！！ということです。
あとはデバイスをRaspberry Pi上で動作させるCやPythonのコード、あるいはCLIコマンドのシェルスクリプトの中に、NNGでデータを送受信するコードを追加すればよいだけです。

## NNG デバイス側(C or Python or CLI)
NNGにはCやPython、CLIに対応したアクセス手段があります。
1. Cライブラリ　　　”nng.c”　高速、機能豊富だがコンパイルする必要
2. Pythonライブラリ”pynng”　 機能豊富、コンパイル不要
3. CLIコマンド　　　”nngcat”　最も簡単だが機能は制限

最も簡単なのはCLIコマンドです。nng-utilsをインストールするとnngcatというCLIコマンドが使用できます。

https://nng.nanomsg.org/man/tip/nngcat.1.html

NNGは色々な通信形態に対応していますが、Simulinkとのやりとりにはpub/subを使用します。CLIなのでRaspberry Piのコンソールに入力すれば簡単に試すことができます。以下のコマンドでプロセス(=ipc:///tmp/pubsub.ipc)を作成し、${msg}をdataとして、delay=1秒で送信を始めます。
``` nngcat
$ nngcat --pub --listen=“ipc:///tmp/pubsub.ipc” –data　“${msg}” –delay 1
```
上記の${msg}には、例えばUSB経由で得たデータを代入することもできますし(下図、および後段の接続例1)、あるいはBLE関連のCLIコマンドで値を代入すればBluetoothで接続したデバイスのデータを代入することもできます(後段の接続例2)。

![Datafloｗ_CLI.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/49045687-2f17-08ef-e49a-0c5c3dd77399.png)

上記はCLIの例でしたが、接続のためのサンプルコードがCで書かれている場合は、サンプルコードにnng.hをインクルードしてNNG publishのコードを挿入することになります(後段の接続例3)。同様にサンプルコードがPythonの場合はpynngをインポートしてNNG publishのコードを挿入します(後段の接続例4)。

## NNG Simulink側
NNGのデータを受け取るSimulink側ではNNG Receiveブロック(subscribe)を配置して、
![NNG_Simulink.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/6af12497-3eb1-84fa-e565-42734d422503.png)
ブロックのパラメータとしてNNGのプロセス名(ipcアドレス)とデータ型/サイズを入力するだけです。
![NNG_Block_parameter.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/bfa1f7f1-a430-2b01-46d4-02f7415ff4bc.png)

以上、説明が長くなりましたが、詳細な諸設定に関しては、以下のような実際の例を参照ください。

## 接続例1. 別のArduino基板をUSBで(CLI経由)
リアルタイムに定サンプルレートでデータを取得したい場合は、OSが稼働するRaspberry Piより、ArduinoなどのOSのないデバイスの方が向いています。Arduino側で定レートでデータを採取してUSBでRaspberry Piに送信するような使い方も可能です。Arduino側のコードでデータを扱いやすいフォーマットにして(LF区切りや10個ごとにLFなど)。

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

## 接続例2. 温湿度計をBlueToothで(CLI)
BLE(Bluetooth Low Energy)のCLIコマンドであるbluetoothctlを利用して、シェルスクリプトからNNGを起動してデータをSimulinkに送っています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/41f12102-3e41-e96a-7b69-4a0f2871d9fa.png" width="200")>

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

## 接続例3. サーモカメラをI2Cで(Cライブラリ経由)
MLX90640は32x24の画素を持つサーモカメラですが、温度画像を取得するCのサンプルプログラムがあったので、、そこにNNGでデータ送信するCコードを追加して、Simulinkで受けています。Simulink側では画像を処理して高温な箇所の中心座標を求め、サーボモーターを駆動して追尾するようなこともできます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/68ce881e-4884-a892-08fe-1d1764d519ff.png" width="200")>

![MLX90640.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/b65c3832-100c-dbe3-2776-7609069d2aa1.png)

<記事作成中>

## 接続例4.Sense HAT (Pythonライブラリ経由)
Sense HATを駆動するPythonライブラリもあるようなので、これにpynngのコードを加えてSimulinkで処理をすることもできます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3583335/ece45353-622b-b541-ac1d-e8cc620c5705.png" width="200")>


以下に接続例があります。

https://jp.mathworks.com/help/supportpkg/raspberrypi/ref/communicate-data-between-raspberry-pi-and-sense-hat-using-nng-blocks.html