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 "\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にチェックを入れています。