IoTで使うPython入門Step3-計測 (6) DMM 2000 ① RS-232C

 Keithleyの2000は 6 1/2桁のDMMです。Keithleyは現在、テクトロニクスと合併しています。ディジタル・マルチ・メータの原器を作ったフルークは、テクトロニクスと同様にダナハーの子会社です。
 Keithley 2000は、RS-232CとGPIBのインターフェースを搭載しています。ここではRS-232Cを利用します。シリアル-USB変換ケーブルは、BuffaloのBSUSRC06を使いました。

 最初は、Windows 10の環境でプログラムを作っています。後半は、ラズパイの環境で実験します。

RS-232Cの機能を有効にする

 Keithley 2000のパネルの操作で、工場出荷時OFFになっているRS-232CをONにします。
 Shiftキーを押し、次にRS232を押すと、画面にRS 232 OFF が表示されます。RS 232がブリンクしているので、右矢印キーを押すとOFFがブリンクします。上もしくは下矢印キーでONとOFFがトグルに切り替わります。ONの表示が出ている状態で、Enterキーを押します。
 BAUD 9600の表示になるので、Exitキーを押すと設定画面を抜けます。次に電源を入れても、この設定は維持されています。

 リモート通信中は、Keithley 2000のパネル左肩にREMの表示が出ます。エラーなどが出て元に戻したいときは、Powerキーの上にあるLocalキーで、リモート状態を解除できます。リモート通信でデータのやり取りが行われると、電圧などの表示の数字が全部「-」に切り替わり、通信が終わると元の数字表示に戻ります。

TeraTermで接続を確認

 変換ケーブルをつなぎ、デバイスマネージャでCOM7につながっていることを確認し、通信ソフトの定番TeraTermを立ち上げ、シリアルでCOM7を選んで通信を始めます。通信速度は9600bpsです。
 エコーは返ってきませんが、次のコマンドを入力するとレスポンスがありました。シリアルでもSCPIコマンドをサポートしています(ユーザーズ・マニュアル2000-900_J-Aug2010_User.pdf)。

READ? +2.49220280E+00
*IDN? KEITHLEY INSTRUMENTS INC.,MODEL 2000,0801917,A13 /A02

シリアル通信

 タスクバーの「ここに入力して検索」欄にCMDと入れ、コマンド・プロンプトを立ち上げ、シリアル通信のライブラリを用意します。

pip install pyserial

 プログラムの中で、読み取りコマンドread?を使うとinitに失敗するというエラー・コードをパネルに表示しますが、データを読んできます。measを使うとエラーなく読みます。Keithley 2000は、電源ON時、直流測定モード、オート・レンジです。
 メッセージが長くなると、SCPIコマンド列の並びは正しくてもエラーが出て実行されません。コンパクトな記述を心がけます。(※)2018/11/21 長さの問題ではないことがわかりました。詳細はGPIB編を参照ください。

import serial
from time import sleep

ser = serial.Serial('COM7', 9600, timeout=0.5)

ser.write(b"volt:dc:rang 100\n")
ser.write(b"meas?\n") # read? is init error
sleep(0.1)
data = ser.read(64)
print(float(data))

ser.close()

 pipは、Pythonのインストール時に入るライブラリ管理ソフトです。Python2だけをインストールしてあればよいのですが、Python3もインストールしていると、pipはどちらのライブラリをインストールしているか不明なことがあります。
 筆者の環境は、最初Python2を入れました。次にPython3をインストールしました。コマンド・プロンプトでは、「python」はバージョン2が、「py」はバージョン3が動きます。「pip」はバージョン3にライブラリをインストールします。したがって、PC環境ではPython3で動いています。

MQTTに対応

import paho.mqtt.publish as publish
import serial
from time import sleep

ser = serial.Serial('COM7', 9600, timeout=0.5)
topic = "k2000/DC/volt"
host = 'raspberrypi.local'
ser.write(b"volt:dc:rang 10\n")

while 1:
ser.write(b"meas?\n")
readDcVoltage = ser.read(64)
print ("DC :", float(readDcVoltage), "V")
publish.single(topic, readDcVoltage, hostname=host)
sleep(1)
ser.close()

 実行中です。

 Node-REDでも正しく購読できています。

ラズパイ

 シリアル-USB変換ケーブルをKeithley2000とラズパイとをつないで、ターミナルで、

ls /dev

で表示されるのがttyUSB0です。ケーブルを抜くと、このデバイスは見えなくなります。
 シリアル通信のライブラリを入れます。ラズパイのターミナルでPythonを動かすと、Python2が動きます。pipもバージョン2に対応します。

pip install pyserial

 ポートの設定のところでは、timeout=0.1を入れないと、正しく値を取得できません。また、交流と直流のモードを切り替えたときにも読み出せるまで時間がかかります。sleep()を入れて対応します。
 AC、DCモードの設定はconfから書き始めないと変更されませんでした。PCの例のようにレンジ切り替えは、confから書き始めるとエラーが出ました。

import serial
from time import sleep

ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=0.1)
print(ser.write(b"*IDN?\n"))
print(ser.readline())

ser.write(b"CONF:VOLT:AC\n")
ser.write(b"meas?\n")
sleep(5)
data1 = ser.readline()
print data1

ser.write(b"conf:volt:dc\n")
ser.write(b"meas?\n")
sleep(1)
data2 = ser.readline()
print data2

ser.close()

 実行した時の表示です。

(※)Keithley 2000はSCPIのコマンドの解釈ができないときに、エラー番号をディスプレイに表示します。マニュアルに英語の解説があります。説明はとても簡潔なので、意味が理解しにくいです。日本語で読めて参考になるエラー・メッセージの解説例があります。http://ena.support.keysight.com/e5071c/manuals/webhelp/jpn/product_information/error_messages/error_messages.htm

(※)このページで、Python2とPython3の表記上の違いは、printのところだけです。
 write()の送り出す文字コードはASCIIコードです。強制的に b"...."とバイト型に指定していますが、Python2とPython3では文字がデフォルトがバイトかユニコードかと異なります。SCPIはASCIIコードなので、バイトでコマンドの文字列を届けないといけません。また、ページの初めにエンコードを指定していないときと# coding: utf-8を書いているときとそうでないときで、デフォルトの解釈が異なります。
 送った文字列が正しいのにエラーになるときは、エンコードが間違っている可能性があります。ターミナルは勝手にエンコードが実行されているのに、通信先にはそうでないことがあります。
 「型」、「エンコード」などが整理できていません。どこかで整理したいと思います。
 ASCIIコードではなくバイナリ・コードを送りたいときは、bytes, bytearrayを使います。次回のおんどとりのときに利用します。