5ドル!ラズパイ・ゼロ(Raspberry pi Zero)でIoT (46) ディジタル温度センサ9 I2C D6T-44L-06

 ■非接触温度センサ

 4×4ポイントのエリアを、非接触で人などの表面温度の測れるセンサです。レンズなどの仕様により何種類かあるのですが、入手しやすいのはD6T-44L-06です。コネクタがハーフ・ピッチなので、圧着は慎重に行います。センサの人を感知できる距離はおおよそ5,6mです。

D6T-44L-06のおもなスペック

  • 電源電圧 4.5~5.5V
  • 測定温度 5~50℃
  • インターフェース I2C(最大100kHz)
  • スレーブ・アドレス 0x0a(7ビット表記)
  • 更新周期 250ms

レジスタ

 読み出しコマンドは0x4cです。
 データ・フォーマットそれぞれ下位、上位の2バイト、CRC8のPECだけは1バイト、PTATはセンサ内部の温度です。読み出すのは合計35バイトです。2バイトのデータは温度を10倍した値です。

PTAT P0 P1 P2 P3 P4 P5 P6 P7 P8 P9 P10 P11 P12 P13 P14 P15 PEC

 データの位置関係です。

P0 P1 P2 P3
P4 P5 P6 P7
P8 P9 P10 P11
P12 P13 P14 P15

接続

 ラズパイとの接続です。センサが5Vで動作するので、レベル変換が必要です。PCA9515ADはI2Cリピータで、レベル変換にも使えます。センサをつないだ5V側は、SDAとSCLに8.2kΩのプルアップを入れました。

ラズパイ PCA9515AD D6T-44L
2番ピン 5V - - Vcc
1番ピン 3.3V 8番   -
6番ピンSCL 4番SCL0 7番SCL1 SCL
3番ピンSDA 3番SDA0 6番SDA1 SDA 
5番ピンGND 2番GND   GND 

 接続が終わったらラズパイの電源を入れます。i2cdetect -y 1を実行して確認します。0x0aにいました。

テスト・スケッチ

 温度を表示するスケッチです。CRCはうまく読み出せないので無視しました。ケーブルの接続などで接触不良があるのか、エラーが多いです。ひとつは通信ができないときに出るIOError、読み出すけどすべてが255になっているのが二つ目です。最初のデータはセンサ自体の温度なので255はあり得ない値です。

 何度かチャレンジしているとわかったことが2点あります。データ転送速度はデフォルトの100kHzにするとほぼ全部IOErrorエラーです。10kHzも同じです。50kHz付近でエラーが少なくなります。通信ができているときにも255データばかりでなく、正常に見えるデータが混じります。手をちかけると正常なデータが増える場合があります。

 try文でIOErrorがおこったらpassで単純にwhileループに戻ります。上位バイトが250以上のようなデータはあり得ないので、読み飛ばします。0.5秒単位でループを回しても、体感的に十分な速度で正しいと思われるデータを表示できるようになりました。このときのデータ転送速度は40kHzです。/boot/config.txtにdtparam=i2c_baudrate=40000と記述します。

 try文でIOErrorをpassすると、プログラムをCTRL-Cで止められなくなります。エラーのなかのKeyboardInterruptはbreakでwhileループを抜けるようにしました。pop(0)は配列の先頭バイトを削除します。

 このセンサはクロックSCLのストレッチを要求する仕様です。ラズパイは多くのスロック・ストレッチのパターンに対応していないので、データ転送速度を落とすことで、かろうじて読み込めたのかもしれません。

#!/usr/bin/env python
import smbus
import time
i2c = smbus.SMBus(1)
addr=0x0a

#main
while 1:
try :
linedata=[]
data = i2c.read_i2c_block_data(addr,0x4c,35)
Atemp=(data[1]*256 +data[0])/10.0
data.pop(0)
data.pop(0)
if data[1] < 250 :
for i in range(4) :
oneline =[]
for j in range(4) :
oneline.append( (int((data[i*2*j+1] ) *256 + data[i*2*j])/10.0 ) )
linedata.append(oneline)
print linedata[0]
print linedata[1]
print linedata[2]
print linedata[3]
print "device Temp ",Atemp
time.sleep(0.5)
except KeyboardInterrupt:
break
except IOError :
pass
finally:
pass

色分けしたスケッチ

 温度範囲で背景色を変えるようにしました。34番目と35番目のデータが正しく読み出せていません。36番目は0なので、読み出し自体は正常だと思います。個体差かもしれません。この画素数だと、ジェスチャとかのモノの移動を判断することはできません。色とカーソルの移動はエスケープ・シーケンスを利用しました。

#!/usr/bin/env python
import smbus
import time
i2c = smbus.SMBus(1)
addr=0x0a

#main
while 1:
try :
linedata=[]
data = i2c.read_i2c_block_data(addr,0x4c,35)
Atemp=(data[1]*256 +data[0])/10.0
data.pop(0)
data.pop(0)
if data[3] < 250 :
for i in range(4) :
oneline =[]
for j in range(4) :
oneline.append( (int((data[i*2*j+1] ) *256 + data[i*2*j])/10.0 ) )
linedata.append(oneline)
for j in range(4):
for i in range(4):
if linedata[j][i] >=30:
print "\x1b[K\x1b[48;5;202m"+str(linedata[j][i])+"\x1b[0m",
elif (linedata[j][i] <30) and (linedata[j][i] >=24):
print "\x1b[K\x1b[48;5;196m"+str(linedata[j][i])+"\x1b[0m",
elif (linedata[j][i] <24) and (linedata[j][i] >=22):
print "\x1b[K\x1b[48;5;160m"+str(linedata[j][i])+"\x1b[0m",
elif (linedata[j][i] <22) and (linedata[j][i] >=19):
print "\x1b[K\x1b[48;5;124m"+str(linedata[j][i])+"\x1b[0m",
elif linedata[j][i] <19:
print "\x1b[K\x1b[48;5;88m"+str(linedata[j][i])+"\x1b[0m",
print
print
print "\x1b[K\x1b[38;5;255m","device Temp ",Atemp,"\x1b[0m"
print "\x1b[7F"
time.sleep(0.1)
except KeyboardInterrupt:
break
except IOError :
pass
finally:
pass

※執筆時点;2017-11-29版をダウンロードし、sudo apt-get update と sudo apt-get upgrade -y および sudo rpi-update で更新し、カーネルはuname -a で確認。4.9.77でした。

※プログラムを仮にd6t.pyという名前で/home/piに保存すると、sudo chmod 755 d6t.py で実行権を付け、ターミナルから、python d6t.pyで実行します。I2CやSPIのグループにpiユーザが属しているので、sudoは不要です。
 プログラム・リストは、表示の関係でTabキーが無視されるので、スペースに代えてあります。また、リスト中を2回クリックすると全選択になるので、CTRL-Cでコピーし、テキスト・エディタにCTRL-Vで貼り付けて利用してください。ラズパイに持っていくと、スペースやリターン・コードなどが化けていることがあるので、一度消して、ラズパイのテキスト・エディタで修正してください。

※I2Cの有効化は、こちらの説明を参照ください。SPIなどにもEnableにチェックを入れています。