CONTEC製「DIO-0808LY-USB」を使ってみる(Linux) from エンジニア・メモ
はじめに
車体の開発にあたり、ウィンカー/スピーカー/リフト等のデジタル機器を操作する仕組みを考える必要があった。この時、車体のハードウェア部品や配線の担当者に「DIO-0808LY-USB」をおすすめされたので、本開発ではこの機器を利用することになった。
本稿では、後学のためにLinuxにおける「DIO-0808LY-USB」の使い方や注意点をまとめる。
開発環境
項目 | |
PC | Jetson Orin Nano |
OS | Jetpack 35.4.1 (Ubuntu20.04) |
ros | ROS 2 foxy Fitzroy |
DIO-0808LY-USBについて
「DIO-0808LY-USB」は株式会社コンテックが販売するUSB機器。
PCと本デバイスをUSB接続(ケーブル付属)、本デバイスとデジタル入出力製品(ボタン,ブザー,LED等)と接続することで、複数のデジタル入出力製品をPCから一括制御できる。 外部機器からの入力信号線を8本、出力信号線を8本分扱うことが出来る。
詳細はcontecのホームページを参照
ドライバの取得
ドライバの圧縮データをダウンロード。 (https://www.contec.com/jp/products-services/daq-control/pc-helper/usb-module/dio-0808ly-usb/price/)
※商品ページから少し下にスクロールした先にある「サポート・ダウンロード」タブをクリックし、一覧の中から「デバイスドライバ(2)」をクリック。 その後、遷移先のページで「Linuxデジタル入出力ドライバAPI-DIO(LNX)開発環境(フルセット)Ver.***」をダウンロードする。 本稿執筆時はVer.8.50で、ファイル名前はcdio_850.tgz。
その後、ダウンロードしたデータ(cdio_***F.tgz)を解凍する。
$ tar -xzvf cdio_***F.tgz
設定ツール
まずは、設定ツールを使って、本デバイスの起動設定などを粉う。 解凍したフォルダ(cdio_***)から、contec/cdioに移動する
$ cd cdio_***/contec/cdio
$ ls
ファイルやフォルダがいくつか並んでいるが、重要なものをピックアップする。
config 設定ツール
samples サンプルソースコードが揃っている。
help cdio/help/jp/cdio.htmが日本語のマニュアルとなっている。
設定ツールはコンソールで起動するアプリであり、以下のコマンドで起動できる。 接続中のデバイスの認識もここで行われるため、本デバイスを接続した状態で起動すること。
$ cd config
$ sudo ./config
設定ツールの使い方はマニュアルに詳しく書かれている。 とりあえず以下を実行すればよい。
DeviceNameを任意の名前に変更。(プログラム上でデバイスを取得する際に使用する)
変更の保存を行う。
変更の保存を行うと、同階層にスクリプトやルールファイルが生成される。 以下のコマンドでスクリプトを実行するとルールファイルが適用される。
$ sudo sh contec_dio_start.sh
使い方(python)
DIO-0808LY-USBは入出力管理とトリガ監視にみ対応している。
本稿では、pythonで入出力管理のプログラムを記述する上で重要な部分について説明する。
必要パッケージのインポート
import cdio
import ctypes # 必須
cdio.pyというファイルがcdio/samples/jp/incに置いてあるので、動かしたいプログラムと同階層以下にコピーしておく。同階層であれば、import cdio、同階層にlibフォルダを作ってその中に置いた時などはfrom lib import cdioのように書けばよい。
cdio.pyはC言語でいうヘッダファイルのようなもので、importしておけばcdio.pyで定義された関数などが使えるようになる。
ctypesはCやC++の関数やデータ型を利用する時に使うpythonの標準ライブラリで、cdioを使う場合は必須なのでimportしておく。
デバイスIDの取得
# 変数
device_name = "DIO001"# DeviceNameで設定した値
dio_id = ctypes.c_short() # デバイスID# デバイスIDの取得
lret = cdio.DioInit(device_name.encode(), ctypes.byref(dio_id))
if lret != cdio.DIO_ERR_SUCCESS:
print("Error: デバイスIDの取得に失敗しました")
設定ツールで設定したDeviceNameでデバイスを認識し、認識したデバイスにアクセスするためのデバイスIDを取得する。lretには、結果が返される。cdio.DIO_ERR_SUCCESSは"ERR"という文字列が含まれてはいるが、正常終了フラグなので注意。
入力信号の取得
port_no = ctypes.c_short(0) # ポート番号# 本デバイスへの入力信号を取得
io_data = ctypes.c_ubyte()
lret = cdio.DioInpByte(dio_id, port_no, ctypes.byref(input_data))
if lret != cdio.DIO_ERR_SUCCESS:
print("Error")
print(f"Input Data: {io_data.value:02b}")
入出力信号を保持する変数はctypes.c_ubyte()で初期化する。 ポート番号に関してだが、1portは8bit(信号線8本)を表しており、今回使用するデバイスは 入力信号/出力信号ともに8bitずつしか用意されていない。 そのため、ポート番号は本プログラムでは簡単化のため、入力出力ともに0固定としている。
入力信号を取得する関数は 1バイト(=8bit=全8本の入力信号線)分を一気に取得する場合はDioInpByte()、 1つだけの信号線の情報を取得する場合はDioInpBitを使う。
データの取得に成功した場合は(変数名).valueでそのデータにアクセスできる。 データ自体は符号なしの数値データではあるが、2進数表記した時の各ビットが結果を表している。 pythonで数値を2進数表記したい時は、f文字列を利用して次のように書くとよい。
print(f"io_data = {io_data.value:08b}")
例として、io_data.value = 13の場合、2進数表記に直すと 00001101となり、以下のように解釈できる。
数値 | 0bit | 1bit | 2bit | 3bit | 4bit | 5bit | 6bit | 7bit |
13 | 1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 |
各bitの数値を取り出す際は、ビット演算子を用いればよい。 例えば 13(=00001101)2bit目の値を取得する場合は、2bit分右ビットシフトして、&演算子で論理積をとる。
# 2bit目の値を取得
io_data_bit2 = io_data.value >> 2 & 0b00000001
出力信号を出力
port_no = ctypes.c_short(0) # ポート番号
io_data = ctypes.c_ubyte(13) # 出力データ(00001101)
lret = cdio.DioInpByte(dio_id, port_no, io_datas) # 出力実行
出力データをctype.c_ubyte(データ)で宣言してDioInpByteで出力する。出力は一瞬ではなくずっと出力され続ける。
出力データ(数値)を計算するサンプルプログラムとして、io_bit配列(int型(0/1)の配列)から 数値を計算する例を示す。
# io_bit配列
io_bit = [1, 1, 0, 1, 0 ,0 ,0 ,0]
# io_data計算
io_data_value = 0for i in range(8):
io_data_value += 1 << i * io_bit[i]
0bit目が1の場合は、数値に1(= 1 << 0)を足す 1bit目が1の場合は、数値に2(= 1 << 1)を足す... というように計算する。
Comments