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