2019年7月6日土曜日

USBを使って制御できるリレーモジュールをpythonで動かしてみる

Amazonで検索すると、QuimatリレーモジュールQY15なるものが見つかったので購入してみました。 4個のリレーSRD-05VDC-SL-CをUSBからの出力でON/OFFできるようです。 FT245RLというUSB-パラレル変換のチップが搭載されているようです

カスタマーレビューを見ると、 FTDI社で提供しているライブラリを使い、 BitBangモードにしてバイトデータを書き出せばよいと いうことで、Pythonからも簡単に制御できそうです。

梱包はいたって簡単で、本体とUSBケーブルが1本ついてきました。 それ以外はなにもありません。 USBポートにQY15を接続してみます。 すると、パチッとリレーの動作音がして、LEDが光ります。 デバイスマネージャを見ると、ポートの個所にUSB Serial Portとして認識されていました。

次はソフトウェアです。
Windows10 64bit
Python 2.7 64bit
で試します。

ここ(https://www.ftdichip.com/index.html)のDriversから、 D2XXのドライバーをダウンロードします。 新しいドライバがあるようですが、D2XXは別のページみたいです。 "for D2XX drivers please click here" に従うと、D2XX Driversのダウンロードページに行けます。 試す環境はWindows用64bitなので、それに合わせて64bit版をダウンロードします。 ダウンロードされたCDM v2.12.28 WHQL Certified.zipを展開すると、 中には、ftd2xx.hというヘッダファイル、さらに64bit,32bit版のライブラリが入っていました。 使うのは、64bit環境なのでamd64のフォルダにある、ftd2xx64.dllです。

Pythonは、ctypesモジュールを使ってDLLの関数を呼び出せます。 関数の呼び出し方は、ヘッダファイルftd2xx.hを見ると分かります。 ftd2xx64.dllと同じフォルダーで、Pythonのスクリプトを書いていきます。

まず、ctypesとtimeモジュールをインポートします。 timeモジュールは、動作テストさせるときの待ち時間を作るのに使います。

import ctypes
import time

ctypesモジュールで、DLLファイルをロードします。

dll = ctypes.CDLL('ftd2xx64.dll')

これでDLLを使う準備ができました。

次に、DLLで提供されているFT_Open()関数を使って、制御するためのハンドルを得ます。 ハンドルはポインタですので、ハンドルを格納するポインタ型の領域を確保します。

handle = ctypes.c_void_p()

それでは、FT_Open()関数をコールします。

res=dll.FT_Open(0, ctypes.pointer(handle))

第1引数は、デバイス番号で0を渡します。 第2引数は、結果として得られるハンドルを格納する場所(ポインタを格納する場所へのポインタ)を渡します。 返り値resが0なら、OKです。そうでなければどこか問題があります。

次にボーレート(通信速度)を設定します。

res=dll.FT_SetBaudRate(handle, 921600)

として、921600bpsを設定します。

次に、BitBangモードに設定します。

res=dll.FT_SetBitMode(handle, 0xFF, 1)

第2引数は、バイトデータに含まれる各ビットの入力出力方向を指定するマスクで、すべて出力(1)に設定しています。 第3引数に1を設定することで、BitBangモードを指定します。

あとは、FT_Write()関数でデータを書き出せば、値に応じてリレーがON/OFFするはずです。 各リレーは、1から4ビットに対応していて、各ビットの重みは1、2、4、8になりますので、 3番目のリレーをONにしたければ、4を書き出し、 1番目と3番目のリレーをONにしたければ、1+4=5を書き出せばよいわけです。 そのまえに、FT_Write()関数を使って1バイトデータを書き出す手続きを関数にしておきましょう。

def write_byte(dll, hndl, byte):
    buff = ctypes.c_byte(byte)
    written = ctypes.c_ulong(0)
    return dll.FT_Write(hndl, ctypes.pointer(buff), 1, ctypes.pointer(written))

dll、hndlおよび書き出す1バイトデータを受け取ります。 1バイトデータを格納した、長さ1のバイト型の領域buffを確保します。 書き出されたバイト数を格納するための、領域writtenを確保します。 これら確保した場所へのポインタを、FT_Write()関数に渡して呼び出します。 FT_Write()関数の3番目の引数は、バッファの大きさですので、1を渡します。 この関数を用いて、1番目と3番目のリレーをONにするデータを書き出します。

res = write_byte(dll, handle, 5)

すこし時間を空けて、リレーをOFFにするデータを書き出します。

time.sleep(2)
res = write_byte(dll, handle, 0)

最後に、FT_Close()関数でハンドルを閉じます。

res = dll.FT_Close(handle)

ここまでをまとめて載せます。

import ctypes
import time

def write_byte(dll, hndl, byte):
    data = ctypes.c_byte(byte)
    written = ctypes.c_ulong(0)
    return dll.FT_Write(hndl, 
            ctypes.pointer(data), 1, ctypes.pointer(written)) 

dllfile='ftd2xx64.dll'
dll = ctypes.CDLL(dllfile)
handle = ctypes.c_void_p()
res = dll.FT_Open(0, ctypes.pointer(handle))
res = dll.FT_SetBaudRate(handle, 921600) # 921600 bps 
res = dll.FT_SetBitMode(handle, 0xFF, 1) # All output and bit bang mode 
res = write_byte(dll, handle, 5) 
time.sleep(2)
res = write_byte(dll, handle, 0)
res = dll.FT_Close(handle)         

ftd2xx.dllを扱うPythonのモジュールはあるようですが、 このリレーモジュールを動かす程度なら、自分で書いてしまうほうが楽かもしれません。