5ドル!ラズパイ・ゼロ(Raspberry pi Zero)でIoT (38) ディジタル光センサ3 I2C AMG8833
■離れたところから8×8ポイントの温度が測れる
AMG8833は非接触温度計の一つで、特定のエリアの温度を測定できるセンサです。人を検知する目的で作られたようで、温度は0~80℃と限定された範囲のサーモグラフィです。センサ単体では約3千円と低価格です。
●AMG8833の主なスペック
- 動作電圧;3.3Vもしくは5V
- 測定温度範囲;0~80℃、解像度0.25℃、確度±2.5℃
- インターフェース;I2C(最大400kHz)
- SDA端子の出力電流;±10mA
- 測定可能距離;5m
- スレーブ・アドレス;AD-SelectをGNDへつなぐと0x68、Vddへつなぐと0x69
●接続
Digi-keyで購入したAMG8833を、秋月電子通商の変換ボードにはんだ付けしました。信号ピンは0.127mmピッチで並んでいます。四方にある接点はNCなので、はんだ付けしていません。
変換ボードに搭載された製品もあります。Conta サーモグラフィー AMG8833搭載 FeatherWing - AMG8833搭載 赤外線サーマルカメラ
●レジスタ
すべてのレジスタの内容は、パワーオン・リセットで0x00です。各種設定項目は機能がレジスタごとに用意されているので、わかりやすいです。
◆設定関係
パワー・コントロール・レジスタ(0x00)
状態は、ノーマル、スタンバイ(2種類)、スリープの四つあり、パワー・リセット直後はノーマル・モードなので、データの読み出しができます。
リセット・レジスタ(0x01)
フレーム・レート・レジスタ(0x02)
1フレーム/秒と10フレーム/秒が選べ、デフォルトは10フレーム/秒です。
割り込み・レジスタ(0x03)
ステータス・レジスタ(0x04)
ステータス・クリア・レジスタ(0x05)
平均化レジスタ(0x07)
2回の移動平均出力を出すかどうかのフラグ。デフォルトはなしです。
割り込みレベル・レジスタ(0x08~0x0d)
上限、下限、ヒステリシスの値を16ビットで設定します。
◆読み出し関連
サーミスタ温度計のレジスタ(0x0e、0x0f)
内蔵の温度計のデータが2バイト(12ビット、2の補数)で読み出せます。最大値+125℃=0x7d0、零度=0x000、-20℃=0x940
割り込みテーブル・レジスタ(0x10~0x17)
ピクセル温度データ(0x80~0xff)
ピクセル1は下位バイトが0x80、上位バイトが0x81に入っています。連続してピクセル64まで同じように収納されています。
●テスト・プログラム
パワーオン・リセット後の状態でデータを読み出せます。smbusライブラリを利用します。ブロック読み出し関数は最大32バイトまでなので、1行分の16バイトをまとめて読み出します。スレーブ・アドレスの次に送るコマンドは読み出すレジスタのアドレスです。
読み出したデータの符号は無視しています。linedataにはlist形式で、温度データが入っています。温度の値に従って色を決め(color関数)、画面に8×8のマトリクスで表示します。画面を操作するために、エスケース・シーケンスを使っています。\x1b[はエスケープ・シーケンスに入るときのコードです。36mは水色、38;5;124mは暗い赤色です。温度が上がるほど明るい赤色を指定しました。描画しているのはスペース2文字です(20℃以下はドット2文字)。
#!/usr/bin/env python
import smbus
import time
bus = smbus.SMBus(1)
addr = 0x68
def color(temp):
if temp <20 :
return("\b\x1b[36m\x1b[7m..")
if temp >=20 and temp<22 :
return("\b\x1b[38;5;124m \x1b[36m")
if temp >=22 and temp<24 :
return("\b\x1b[38;5;161m \x1b[36m")
if temp >=24 and temp<26 :
return("\b\x1b[38;5;198m \x1b[36m")
if temp >=26 and temp<28 :
return("\b\x1b[38;5;200m \x1b[36m")
if temp >=28 and temp<30 :
return("\b\x1b[38;5;212m \x1b[36m")
if temp >=30 and temp<32 :
return("\b\x1b[38;5;219m \x1b[36m")
if temp >=32 :
return("\b\x1b[38;5;225m \x1b[36m")
while 1:
time.sleep(0.1)
linedata=[]
for i in range(8) :
data = bus.read_i2c_block_data(addr , 0x80+0x10*i, 16)
oneline =[]
for j in range(8) :
oneline.append( (int((data[2*j+1] & 0x07) *256 + data[2*j]))*0.25 )
linedata.append(oneline)
# print linedata
print "\x1b[36m\x1b[7m0 1 2 3 4 5 6 7 "
for i in range(8):
for j in range(8):
print color(linedata[i][j]),
print i
print "\x1b[10F" #10 line move
※2017/12/27 読み出した上位データにマスクをかけるところを修正。07->0x07
●実行結果
センサの上で手を動かすと、ほとんどリアルタイムに温度分布が変わります。
データを補間して 64×64の表示にできれば、よりモノの動きがはっきりしそうです。
※2017/12/27 データを補間し32×32の表示をします。グレースケール(ANSI escape code)です。約22℃が一番暗く、温度が高くなるにつれて明るくなります。
#!/usr/bin/env python
import numpy as np
from PIL import Image #pip install Pillow
import smbus
import time
bus = smbus.SMBus(1)
addr = 0x68
def readdata() :
linedata=[]
for i in range(8) :
data = bus.read_i2c_block_data(addr,0x80+0x10*i,16)
oneline =[]
for j in range(8) :
oneline.append( (int((data[2*j+1] & 0x07) *256 + data[2*j]))*0.25 )
linedata.append(oneline)
return(linedata)
#main
while 1:
time.sleep(0.05)
linedata = readdata()
a = np.asarray(linedata)
b = Image.fromarray(np.uint8(a))
c = b.resize((32,32),Image.BICUBIC)
d = np.asarray(c)
print "\x1b[36m\x1b[7m0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2"
for i in range(32):
for j in range(32):
print "\b\x1b[38;5;"+str(int(d[i][j])+216)+"m \x1b[36m",
print i
print "\x1b[34F" #line up
※執筆時点;2017-11-29版をダウンロードし、sudo apt-get update と sudo apt-get upgrade -y および sudo rpi-update で更新し、カーネルはuname -a で確認。4.9.70でした。
※プログラムを仮にamg8833.pyという名前で/home/piに保存すると、sudo chmod 755 amg8833.py で実行権を付け、ターミナルから、python amg8833.pyで実行します。I2CやSPIのグループにpiユーザが属しているので、sudoは不要です。
プログラム・リストは、表示の関係でTabキーが無視されるので、スペースに代えてあります。また、リスト中を2回クリックすると全選択になるので、CTRL-Cでコピーし、テキスト・エディタにCTRL-Vで貼り付けて利用してください。ラズパイに持っていくと、リターン・コードなどが化けていることがあるので、一度消して、ラズパイのテキスト・エディタで改行してください。
※I2Cの有効化は、この説明を参照ください。1-Wireと同じく、I2CやSPIもEnableにチェックを入れています。