Raspbery Piでリアルタイム温度検知をしてみる
赤外線センサとseabornを使ってリアルタイム温度検知機構を作りました
できるもの
Raspberry Piから実行してます。この赤いセンサから温度を測定し、ヒートマップがリアルタイムで表示されます。だいたい1 FPSで動きます。
リアルタイムで温度検知できた〜〜 pic.twitter.com/eMuCRSRnsf
— チズチズ (@chizu_potato) September 15, 2020
Raspberry Piで使えるようにする
自分はAMG8833という赤外線温度センサを買いました。これを買った8月は新型某ロナの影響でネットに全く商品がなくて秋葉原に買い出しに行くことになったのですが、秋葉原でも全然売ってませんでした。唯一売っていた店があって安堵です。
これは、そのままだとピンが接続できないので頑張って半田付けする必要があります。
裏で留めておきました。
安定のI2C通信です。
Raspberry Piに接続
Raspberry Pi側にピンを接続します。
- SDA:SDA1
- SCL:SCL1
- 3.3V:3V3
- GND:GND
- INT:なし
sudo i2cdetect -y 1
を実行して、接続されてるか確認します。
人によっては68に出てくることもあると思います。出てこない人は接触を確認するか、Raspberry PiでのI2C通信について調べると対処法がわかると思います。
pi@raspberrypi:~ $ sudo i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- 69 -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
サンプルコーディング
amg8833を扱うためにAdafruit社のライブラリを使用します。
sudo pip3 install adafruit-circuitpython-amg88xx
サンプルプログラムを実行してみます。
import time
import busio
import board
import adafruit_amg88xx
# I2Cバスの初期化
i2c_bus = busio.I2C(board.SCL, board.SDA)
# アドレスを68に指定
sensor = adafruit_amg88xx.AMG88XX(i2c_bus, addr=0x68)
time.sleep(.1)
# 8x8の表示
print(sensor.pixels)
sensor.pixels
でそのときそのときのセンサを読み取ってくれます。
実行
上のコードを基にopencvのwindowで表示させてみました。matplotlibのグラフのデータは直接opencvに渡すことができないのでpngに吐き出してから再度読み込んでます。
cap
はWebカメラに関するコードですが、今回は使わないのでコメントアウトしています。応用として透過させることもできるので色々試しがいがあります。
import time
import busio
import board
import cv2
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import adafruit_amg88xx
i2c_bus = busio.I2C(board.SCL, board.SDA)
sensor = adafruit_amg88xx.AMG88XX(i2c_bus)
time.sleep(.1)
def draw_heatmap(data):
ax = sns.heatmap(data, annot=True)
ax.set_ylim(len(data), 0)
# plt.show()
plt.savefig("img.png")
plt.clf()
return None
# cap = cv2.VideoCapture(-1)
cv2.namedWindow("img")
k = 0
while k != 13:
print("capture")
# cap.read()
# r, img = cap.read()
draw_heatmap(np.array(sensor.pixels))
img = cv2.imread("img.png")
cv2.imshow("img", img)
k = cv2.waitKey(1)
応用例1:透過させてみる
まず、addWeighted
という関数で画像の合成ができます。(重み付き平均で良い感じに合成)
ヒートマップを作成するところは前と変わっていませんが、Webカメラで取得した画像と合成してみました。
また、cv2.waitKey
が遅かったのでmatplotlib
でリアルタイム描画させました。
while True:
# plotデータの更新
r, frame = cap.read()
draw_heatmap(np.array(sensor.pixels))
img = cv2.imread("/home/pi/Desktop/festival/img.png")
img = cv2.addWeighted(frame, 1, img, 0.2, 0)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img)
plt.pause(1)
使ってみるとこんなふうになります。温度を伝えたければ合成はやめたほうがいいと思います。ただノリで人を感知するくらいなら使いみちはありそうです。
グラフを透過させてみた〜〜 pic.twitter.com/IjBp2lQBYJ
— チズチズ (@chizu_potato) September 16, 2020
応用例2:体温測定
手元にある小さなディスプレイに検知した最大の温度を表示させる機構を作ってみました。
描画させない分、軽快に動くようになりました。これなら割と実用性ありそう?
リアルタイム体温測定器 pic.twitter.com/aWBtCRTee4
— チズチズ (@chizu_potato) September 16, 2020
import time
import busio
import board
import cv2
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import adafruit_amg88xx
i2c_bus = busio.I2C(board.SCL, board.SDA)
sensor = adafruit_amg88xx.AMG88XX(i2c_bus)
time.sleep(.1)
print(sensor.pixels)
def draw_heatmap(data):
ax = sns.heatmap(data, annot=True)
ax.set_ylim(len(data), 0)
# plt.show()
plt.savefig("/home/pi/Desktop/festival/img.png")
plt.clf()
return None
cap = cv2.VideoCapture(-1)
cv2.namedWindow("img")
k = 0
while k != 13:
print("capture")
# cap.read()
r, img = cap.read()
draw_heatmap(np.array(sensor.pixels))
img = cv2.imread("/home/pi/Desktop/festival/img.png")
cv2.imshow("img", img)
k = cv2.waitKey(1)
思ったこと
cv2.waitKey
が遅い
C++で実装されてるOpenCVでも言われてます。特にRaspberry Piという小さなハードウェアで動かすときは代替手段が必要っぽいです。(matplotlibのpause、Tkinterなど)
SSH経由でリアルタイムの描画ができない
何でそんなに無理にやろうとするかというと、モニタにHDMIを繋げるのが億劫だからという理由だけなのですがGUI描画ができたらいいな〜とか思ってます。
追記:VNCでできました
VNCで接続できたわ これで人生easy mode pic.twitter.com/GDETBnqLmq
— チズチズ (@chizu_potato) September 17, 2020