Modbusを使ってPLC経由でモータを制御する

タグをつけようとしたらModbusもPLCもタグとして利用されていないことに気づきました・・・もしかしてQiita初？


# PLCとは? どんな時に使う？
PLCはProgramable Logic Controllerの略です。
要するに『プログラミング可能なモータドライバ』と捉えれば現状間違いないと思います。
~~ただし、プログラムはCPUではなく、電子回路上で実行されます。~~
どうやら違うらしいです。[Wikipedia](https://ja.wikipedia.org/wiki/プログラマブルロジックコントローラ)・・・。
値段はピンキリですが20,000円以上が相場じゃないでしょうか。
対応しているモータとセットだとかなりの値段になると思います。
100,000円超えも珍しくない。
「たかっ！電子工作で使ってるモータドライバ使って、プログラムならパソコンに書けば良いのでは・・・」と思ったそこのあなた。
正解です。あなたの書いたプログラムで99%の場合(あなたのスキル次第ではそれ以上)はうまく行くでしょう。
ただ、残りの1%が当たってしまった時の処理を書いていますか？
おそらく制御系を書かれたことのある方は分かるでしょう。
「完璧なエラーハンドリングをしたプログラミング」と「完璧なエラーハンドリングをPCでやりきること」の難しさを。
エレベータや大型機械など、ステッピングモータを使った人に危険が及ぶような箇所、精密な動作を要求される箇所のモータ制御にPLCは広く利用されています。
つまり値段は「PC代金」と「モータ代金」と「セーフティな制御プログラム代金」の3つがセットになったもの、と考えれば良いわけです。
そう考えると必ずしも高い、とは言えないのではないでしょうか。
また、最近はインスタレーション系でもちらほら使っているのを見ます。[これ](https://www.youtube.com/watch?v=0rlvePwC-tA)とか[これ](https://www.youtube.com/watch?v=brtqGLQb4fY)とか。

# Modbusとは
PLCのメリットはなんとなくわかったけど、「とはいえtwitter連携とかできないでしょ！？　やっぱPCとかあったほうがよくない？」と思った貴方。
その通りです。
そのため、PLCの中にはPCの連携のためのプロトコル、という規格がいくつか用意されているものがあります。
そのプロトコルの中でもModbusという規格は最もメジャーなものです。
Modbusはシリアル通信ベースのModbus RTU、Modbus Ascii、そしてTCP通信ベースのModus TCPなどさまざまな通信環境でPCと連携可能です。DMXやArtnetに近い感じですね。

# で、使ってみた
今回たまたま機材を触る機会があったので忘備録的に書いておきます。

## 用意するもの
[こちら](https://www.orientalmotor.co.jp/products/detail.action?hinmei=AZD-KD)のP.270をベースに制御システムをPCにした場合の環境を構築します。
![IMG_7459.JPG](https://qiita-image-store.s3.amazonaws.com/0/152718/8847913d-9a09-0b9b-7d42-99e0df3c0210.jpeg)


- [オリエンタルモーター社製AZD-KD](https://www.orientalmotor-shop.jp/shop/product_details_ec/?hinmei=AZD-KD)
- MEXE02用USBケーブル(AZD-KDの付属品)
- [オリエンタルモーター社製モーターAZM24AK-PS7.2](https://www.orientalmotor.co.jp/products/detail.action?hinmei=AZM24AK-PS7.2)
- [オリエンタルモーター社製モータ-PLC間接続ケーブルCC030VZ2F2](https://www.orientalmotor.co.jp/products/detail.action?hinmei=CC030VZ2F2)
- [スイッチング電源DC24V100W](https://www.marutsu.co.jp/pc/i/64248/)
- [RS485のFTDI入りUSBケーブル](http://amzn.asia/e4SAbBY)

## 電子工作
[このキット](https://www.orientalmotor.co.jp/products/detail.action?hinmei=AZM24AK%2BAZD-KX%2BCC030VZ2F2)を買うとオリエンタルモータの部分はとりあえず準備できるかと思います。
あとは電源周りとハーネスの制作に電子工作がちょこっと必要になります。

### 1. RJ45コネクタの取り付け
RS485 USBケーブルの先をRJ45(LANケーブルのアレ)にする必要があります。
線は3本だけ使えばOKで、GND、DATA+、DATA-の3つです。
配線は[『AZシリーズ DC電源入力 ドライバ編』](https://www.orientalmotor.co.jp/products/detail.action?hinmei=AZD-KD#option01)のP.21あたりをみて確認してください。
『RS485ってなんじゃ！？』と思った貴方、僕もよくわかりません。が、シリアル通信の規格の一種です。
が、機材が違うだけでソフトウェア的には(少なくとも今回は)通常のシリアル通信と同じように扱えるので気にしないでください。
気になる方は[このあたり](https://www.fujiele.co.jp/semiconductor/step/engineering/20171219-1/)を読むと良いのではないでしょうか。

### 2. スイッチング電源周りのハーネス制作
今回購入した電源は本当に電源のみだったので、マルツでコンセントケーブルを買ってきてY端子をつけてスイッチング電源への電気ケーブルとしました。
またスイッチング電源 →　PLCへのケーブルも必要だったので適当な赤黒の2線のケーブルを買ってきてこれまたY端子を取り付けました。
PLC側は裸の配線をPLCに小さなマイナスドライバがあれば接続できるコネクタがあるので、特別な機材は必要ありません。

今回はテストなのでPC→RS485入りUSBケーブル→PLCで終わりですが、RJ45の刺し口が2つあることから分かる通り、デイジーチェーンで複数台のPLCを1つのPCから命令して制御することが可能です。
これは通常のLANケーブルでチェーン可能です、非常に便利ですね。
Modubs RTU(というかRS485？)の場合は32台のデイジーチェーンが可能だそうです。

## ソフトを使って設定
オリエンタルモーターは[MEXE02](https://www.orientalmotor.co.jp/download/software/mexe02/)というアプリを公開しており、
それを利用するとPLCに直接USBを指すことでPLCの設定を確認/編集することができます(要会員登録)。
あ、Windows版のみなのでご注意ください。
これを使ってModub RTUの設定を確認しましょう。
スイッチング電源をコンセントに挿して、PLCのランプが点灯している状態で調整用のUSBケーブル(RJ45をつけてない、普通のUSBケーブル)でPCとPLCをつなぎます。
しばらくすると仮想COMポートとしてPLCを認識するはず。
その状態でMEXE02を立ち上げます。
MEXE02でPLCとの接続ボタンを押すとPLCから情報が読み込まれます。
非常にたくさん項目があるのですが、「通信・I/F機能」のところにModbus周りは集約されています。
これもドキュメントのP.270を参考に確認します。
主なチェックポイントはこのあたりでしょうか。

- Modbus RTUを使うかどうか：ハードウェア設定に任す
- Modbus RTUを利用する時のRS485のbaudrate：ハードウェア設定に任す
- parity check：偶数
- stop bit：1bit

デフォルトではこの設定になっているはずですが、違っているとドツボにハマるので念のため確認しましょう。

## ハードを使って設定
[こちらの「AZシリーズ 機能編」のP.267の設定](https://www.orientalmotor.co.jp/products/detail.action?hinmei=AZD-KD)に従ってModbus RTUの設定をハードウェアで行いましょう。

- Modbus RTUを利用(ちっちゃなスイッチの下から2番目を倒します)
- baudrate 115200(可変抵抗を4番にします)
- PLCのアドレスを1に (可変抵抗を1番にします)

これで準備完了です。

## プログラムを書いてみる
AZD-KDはシリアル通信ベースのModbus RTUをサポートしているため、シリアル通信ベースで通信します。
なんとなく最近Pythonが気分なのでPythonで書いていきます。
Pythonでシリアル通信をするにはpyserialが便利です。

```
pip install pyserial
```

でpyserialをインストールします。
「AZシリーズ 機能編」P.266に書かれているテストコードをそのまま実行するプログラムを作ります。

```python:ModbusTest.py
client = serial.Serial("COM6", 115200, timeout=0.01, parity=serial.PARITY_EVEN,stopbits=serial.STOPBITS_ONE) # COMポートは自分の奴を入れる
size = 16 # 適当にサイズを区切る
print(client.name)
commando = b"\x01\x10\x18\x00\x00\x02\x04\x00\x00\x00\x02\xd8\x6e"
client.write(commando)
result = client.read(size) # 短いインターバルの連続コマンド送信はNGなのでちゃんとPLCがコマンドの結果を返すのを待つ
print(result)
commando = b"\x01\x10\x18\x02\x00\x02\x04\x00\x00\x21\x34\xc1\xf1"
client.write(commando)
result = client.read(size)
print(result)
commando = b"\x01\x10\x18\x04\x00\x02\x04\x00\x00\x07\xd0\x5b\xf0"
client.write(commando)
result = client.read(size)
print(result)
commando = b"\x01\x10\x18\x06\x00\x02\x04\x00\x00\x05\xdc\xdb\x4c"
client.write(commando)
result = client.read(size)
print(result)
commando = b"\x01\x10\x18\x08\x00\x02\x04\x00\x00\x05\xdc\x5a\xc0"
client.write(commando)
result = client.read(size)
print(result)
commando = b"\x01\x10\x00\x7c\x00\x02\x04\x00\x00\x00\x08\xf5\x18"
client.write(commando)
result = client.read(size)
print('result')
commando = b"\x01\x10\x00\x7c\x00\x02\x04\x00\x00\x00\x00\xf4\xde"
client.write(commando)
result = client.read(size)
print(result)
client.close()

```

酷い糞コードですがまぁ動けば良し。実行してみましょう。

```
python ModbusTest.py
```

うまく行けばステッピングモータがゆっくりと回転して止まるはずです。
ちょっと面倒くさいのがPLCがModubs RTUの通信に関して厳格なところ。
正規の通信でないとエラーを吐いて止まってしまいます。
うまくいかなかったときはPLC上部のランプが赤く点滅していないか確認しましょう。
赤く点滅しているときはMEXE02を使ってエラーをリセットしてから設定を見直し、再度テストすることになります。
アラームのチェック/停止はMEXE02のアラームモニタの項目から確認できます。
デバッグのときは面倒ですが、イレギュラーな挙動をしたときにちゃんとエラーを吐いて止まり、リセットかけるまで動かない、というのは本番になったときには安心に代わるのではないでしょうか。
まだAZD-KDのコマンド仕様が良く分かってないですが、「一連の動きの設定をレジスタに書き込む」という手順が上記の最初5つのコマンド、後半の2つが「書き込んだ動きをレジスタから読み込んで実行する」のようです。

## 最後に
Modbusでモータ制御がとりあえず動いた！って感じのサンプルや手順がなかなか見つからずに苦労しましたが、このQiitaを見て、初めてPLC触るひとにちょっとした安心感を与えられれば幸いです。
が、昨日Modbus触ったばかりなので色々分かっておらず（特にクェリやレスポンス周り）、もうちょっと把握したら続きを公開しようと思います。
pymodbusのどこらへんが便利なのかとかも良く分かってない・・・。