Linux でお手ごろ価格な USB 接続の温湿度計を使う

USBRH

実験ノートを取るときに温度や湿度を書きましょうという建前があっても、結構サボっている人は多いのではないでしょうか。実験している場所のすぐ横に温湿度計のない場合が多いから。しかし温度によってエレキの応答が変わったりする場合には、ちゃんと室温を記録しておきたいですよね。

実験を一昼夜連続して行う場合には、人間が目で温湿度を読み取るなんてことは出来ません。定期的に PC に測定してもらいたいですが、温湿度計ごときに何万円も払いたくないし、あまり筐体のでかいのが来ても取り回しに苦労します。そこで見つけたのが、Strawberry Linux の USBRH という温湿度計。ハンダ付けを自分でやるキットが 3,980 円、ハンダ付け済みのものが 4,980 円、ハンダ付け済みで専用の筐体に入っているものが 6,240 円と、自分の科研費で気軽に買える値段。今回、筐体に入っているものを買いました。


▲ 大きさはリンゴより少し大きいくらい。基盤中央の PIC で、基盤先端に取り付けてある Sensirion の SHT11 という温湿度計チップを制御しています。

乗っかっている SHT11 は非常に取扱いが簡単で、ちょっと PIC をかじったことのある人であれば、このキットを買わないでも同等品を作れると思います。

Linux で使う

販売元では Windows 用の driver しか公開していないため、Linux で USBRH を使うには有志の方が作成されたソフトを使う必要があります。以下、作業記録。

1. 環境
2. Kernel Module を使う

kimata さんが作成された USBRH driver for Linux を使うことで、

$ cat /proc/usbrh/0/status
t:21.30 h:70.92

なんてやるだけで、簡単に温湿度を読み出すことができます。

2.1 Kernel Module の Build
$ wget http://green-rabbit.sakura.ne.jp/usbrh/dist/usbrh-0.0.8.tgz
$ tar zxvf usbrh-0.0.8.tgz
$ cd usbrh-0.0.8
$ make
$ sudo make install

この作業で、以下の 2 つの file が install されるはずです。

/etc/udev/rules.d/10-usbrh.rules
/lib/modules/2.6.18-194.17.1.el5/extra/usbrh.ko
$ sudo /sbin/modprobe /lib/modules/2.6.18-194.17.1.el5/extra/usbrh.ko

とした後、/sys/bus/usb/drivers/usbrh が作成されることを確認します*1

2.2 /etc/udev/rules.d/ の設定

Gentoo Linux では、2.1 の設定だけで使えるようになるそうですが、Red Hat clone である Scientific LinuxCentOS ではすぐに使用できません。先ほど install した usbrh ではなく、usbhid が先に USBRH を掴んでしまうからです。そこらへんの議論と解決方法は id:dayflower さんが詳しく解説されています

/etc/udev/rules.d/10-usbrh.rules の中身を次のように書き換えます。

# USBRH by Strawberry Linux
ACTION=="add", BUS=="usb", SYSFS{idVendor}=="1774", SYSFS{idProduct}=="1001", PROGRAM="usbrh.sh '%b:1.0'"

id:dayflower さんの環境では PROGRAM の代わりに RUN となっていたのですが、自分のとこでは動かなかったので、PROGRAM に書き換えて解決しました。man udev しても、いまいち RUN と PROGRAM の差が分かりませんでした。

また、ここで呼び出している usbrh.sh を、次の中身で /lib/udev/usbrh.sh として保存しておきます。当然、実行権限は付けておいて下さい。

#!/bin/sh

DRIVER_PATH=/sys/bus/usb/drivers

/sbin/modprobe -v -s usbrh

echo -n "$1" > $DRIVER_PATH/hiddev/unbind 2>/dev/null
echo -n "$1" > $DRIVER_PATH/usbhid/unbind 2>/dev/null
echo -n "$1" > $DRIVER_PATH/usbrh/bind    2>/dev/null

exit 0

ここまで、ほとんど id:dayflower のパクリです。

2.3 実際に使う

それでは、USBRH を接続します。自分とこでは VMware 上で使っているので、USB が VMware 上に現れるようにする必要があります。USB を接続した後、dmesg で次のように出ていれば OK のはず。

usb 2-1: new full speed USB device using uhci_hcd and address 35
usb 2-1: configuration #1 chosen from 1 choice
hiddev96: USB HID v1.00 Device [Strawberry Linux Co.,Ltd. Hygrometer/Thermometer] on usb-0000:02:00.0-1
/home/oxon/sw/usbrh-0.0.8/src/usbrh.c: USBRH device now attached to /dev/usbrh0

後は、次のようにして温湿度を読み出せれば完了です。root 権限は必要ありません。

$ cat /proc/usbrh/0/status
2.4 Error への対処

ここまで、本当はうまく行くはずだったのですが、手元の環境では

$ cat /proc/usbrh/0/status
Failed to get temperature/humierature

という error が頻繁に出ました。どうやら USB の通信に時間がかかりすぎ、timeout する場合があるようです。そこで、作者の kimata さんにお伺いしたところ、src/usbrh.c の 152 行目で 1000 msec の wait を 5000 msec に長くするという方法で解決しました。2000 msec では失敗するときがあり、また 5000 msec でも稀に失敗するときがあるのですが、この遅延の原因はよく分かりません。

失敗する場合は、src/usbrh.c を書き換えて、再度 usbrh を読み込ませます。

$ sudo /sbin/rmmod usbrh
$ make
$ sudo cp src/usbrh.ko /lib/modules/2.6.18-194.17.1.el5/extra/usbrh.ko
$ sudo /sbin/modprobe usbrh
3. 単独の Command を使う

id:Briareos さんが作成された command で、こちらも簡単に

$ sudo ./usbrh      
21.53 56.09

とすれば、温湿度を読み取れます。

3.1 Command の Build

まずは、普通に tar.gz を展開します。

$ wget http://www.dd.iij4u.or.jp/~briareos/soft/usbrh-0.05.tar.gz
$ tar zxvf usbrh-0.05.tar.gz
$ cd usbrh-0.05

作者さんの blog のコメントによると、一部環境で error が出るようなので、
usbrh_main.c の 232 から 236 行目を次のように書き換えます。

    if((rc = usb_set_configuration(dh, dev->config->bConfigurationValue))<0){
      if( rc = usb_detach_kernel_driver_np(dh, dev->config->interface->altsetting->bInterfaceNumber)<0 ){
        puts("usb_set_configuration error");
        usb_close(dh);
        exit(3);
      }
    }

で、make して実行すれば動作します。

$ make
$ sudo ./usbrh
24.01 33.55
3.2 Error

ただし、自分の環境では 2 回に 1 回、必ず読み取り値が不正でした。

$ sudo ./usbrh -v -d
usb_set_debug: Setting debugging level to 5 (on)
USBRH is found
USB error: could not set config 1: Device or resource busy
usb_control_msg OK:send bytes:[7]
00 00 00 00 00 00 00 
usb_bulk_read error
convert to integer(temperature):[00 00] -> [0000]
convert to integer(humidity):[00 00] -> [0000]
Temperature: -40.00 C
Humidity: -4.25 %

usbrh_main.c の中で 5000 msec の timeout を設定してあるのですが、これを 20000 msec などに変更しても timeout してしまい、配列 buff の値が初期値のままになるからです。これは原因が不明です。

4. 試しに測定してみる

TestEquity 1000 Series の恒温槽を使って、較正してみました。と言っても、恒温槽側の温度計の精度は不明です。

15.0 ℃、17.5 ℃、20.0 ℃、22.5 ℃、25.0 ℃に恒温槽を設定したときの、USBRH で測定した温度の変化のグラフです。測定値自体は安定しているので、offset を考慮すれば、問題なく使えます。また、±5 ℃であれば、実用上は十分に線形です。

*1:usbrh.ko を絶対 path でしないと、初回は modprobe が usbrh.ko を見つけてくれませんでした。再起動後は、modprobe usbrh とするだけで動作しました。再起動せずに検索させる方法は知りません。