LoginSignup
0
3

More than 3 years have passed since last update.

サーモグラフィAMG8833のデータをPythonでリアルタイムに可視化

Posted at

はじめに

この記事は,8x8の赤外線アレイセンサ「AMG8833」をArduinoから利用して,そのデータをリアルタイムにPCに送信しPython(PyQt5,PyQtGraph)で可視化したときの記録です.

下の画像のような感じでリアルタイムに可視化しています.amg8833.gif

Arduino

Arduinoはサーモグラフィのデータを取得し,PC(Python)にシリアル通信で送信します.

AMG8833

今回はスイッチサイエンスのConta™ サーモグラフィー AMG8833搭載を使用しています.

スイッチサイエンスによると

各素子ごとの温度測定範囲は0℃~80℃です。測定エリアはセンサ正面(上下左右約60度)の四角錘で、このエリアを8x8ピクセルに分割した2次元画像が得られます。

またAMG8833を簡単に使えるようにConta™ ベースシールドを利用しています.

データ取得&送信

スイッチサイエンスのページにはAMG8833のライブラリがいくつか挙げられていますが,ここではSparkFunのSparkFun_GridEYE_Arduino_Libraryを利用しています.以下のプログラムはサンプルプログラムを少し変えただけです.

シリアル通信では,8x8=64個の温度データを「,」区切りの文字列として送信しています.

amg8833-serial.ino
#include <SparkFun_GridEYE_Arduino_Library.h>
#include <Wire.h>

float pixelTable[64];

GridEYE grideye;

void setup() {
  Wire.begin();
  // スイッチサイエンスのAMG8833のアドレスはデフォルトでは0x68に設定されている.
  grideye.begin(0x68);
  Serial.begin(115200);
}

void loop() {
  // 8x8=64個のピクセルに対して温度を取得しgrideyeに保存する.
  for(unsigned char i = 0; i < 64; i++){
    pixelTable[i] = grideye.getPixelTemperature(i);
  }
  // すべてのピクセルの温度を","で区切り1行に並べてシリアル通信で送信する.
  for(unsigned char i = 0; i < 64; i++){
    Serial.print(pixelTable[i]);
    if(i != 63){
      Serial.print(",");
    }
  }
  Serial.println();
  delay(50);
}

Python

Arduinoから受け取った温度データをもとに,ヒートマップをリアルタイムに表示します.

ライブラリ

  • pyserial - シリアル通信
  • numpy
  • pyqt5
  • pyqtgraph - リアルタイム描画
  • (matplotlib) - カラーマップ

Pythonでデータ可視化といえばmatplotlibですが,matplotlibでリアルタイムに画面を更新するには重すぎるという欠点があります.そのためmatplotlibではなく,軽量なpyqtgraphというライブラリを利用しています.

といいつつ今回は,温度データを色(RGBA)に変換するためにmatpotlibの一部を使っています.pyqtgraphでも近いことはできるようですが,その場合は自分でカラーマップに使う色を指定する必要があるようです.ここではデフォルトでカラーマップを用意してくれているmatplotlibを使います.

データ受信&ヒートマップ表示

heatmap.py
from pyqtgraph.Qt import QtGui, QtCore
import matplotlib.cm as cm
import matplotlib as mpl
import pyqtgraph as pg
import numpy as np
import serial

# ヒートマップを見やすくするためにTEMP_MAX=40.0に設定
TEMP_MIN = 0.0
TEMP_MAX = 40.0

app = QtGui.QApplication([])

win = pg.GraphicsLayoutWidget(show=True, title="AMG8833")
win.resize(600,600)
win.setWindowTitle('AMG8833')
pg.setConfigOptions(antialias=True)

view = win.addViewBox()
view.setAspectLocked(True)

img = pg.ImageItem(border='w')
view.addItem(img)

# 温度を色に変換するためのColor Map
norm = mpl.colors.Normalize(vmin=TEMP_MIN, vmax=TEMP_MAX)
cmap = cm.jet
m = cm.ScalarMappable(norm=norm, cmap=cmap)

# シリアル通信
ser = serial.Serial("COM13", 115200, timeout=1)

# 8x8の温度データ
data = np.zeros((8, 8))

def get_data():
    global data, ser
    if ser.in_waiting:
        # Arduinoからデータ受信
        # データ取得時には何かとエラーが出るので簡単に例外処理
        try:
            line = ser.readline().decode().strip()
            temps = [float(t) for t in line.split(",")]
            data = np.array(temps).reshape((8, 8))
        except:
            pass

def update_plot():
    global img, data
    img.setImage(m.to_rgba(data))

# 50msごとにデータ受信
timer1 = QtCore.QTimer()
timer1.timeout.connect(get_data)
timer1.setInterval(50)
timer1.start()

# 100msごとにヒートマップ更新  
timer2 = QtCore.QTimer()
timer2.timeout.connect(update_plot)
timer2.setInterval(100)
timer2.start()

if __name__ == '__main__':
    import sys
    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()

上のプログラムではデータ受信とヒートマップ更新を別のQTimerに分けています.データを受信するたびにヒートマップを更新していると,ヒートマップの更新が間に合わなくなることがあります.それを防ぐために別々にデータ受信とヒートマップ更新を個別にできるようにしています.

参考リンク

0
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
3