【Arduino】非接触温度センサ(GY-906)をつかってみた
こんなこと、やります。
- Arduinoで非接触温度センサGY-906を使う
- GY-906で物体の温度と環境温度の測定
- M5StickC PLUSでHATモジュール化
- メディアンフィルタで測定精度を上げる
つかうもの
つかうものは、Arduinoと非接触温度センサGY-906です。
非接触温度センサGY-906
非接触温度センサGY-906は、赤外線センサのMLX90614を搭載したセンサモジュールです。I2C対応のデジタルセンサです。電源電圧は、5Vと3V3のどちらでもOKです。
Arduinoボード
Arduino Uno Rev3を使用しました。
▼ もちろん、ほかのArduinoをお使いになってもらっても構いません。
もしまだ、Arduinoをお持ちでないようでしたら、 おすすめArduinoどれを選べばいい?Arduinoで電子工作をはじめる方へ をご覧ください。
開発環境
この記事で使用した開発環境は次のとおりです。私はPlatform IOを使ってますが、Arduino IDEで構いません。
項目 | バージョン |
---|---|
統合開発環境 | Visual Studio Code x Platform IO |
パソコン | macOS Big Sur 11.0.1 |
準備
GY-906ライブラリのインストール
Arduino IDEをお使いの場合は、ライブラリマネージャで「Adafruit MLX90614」検索し 「Adafruit-MLX90614-Library」のバージョン1.1.x をインストールします。最新の2.0.0を使うと、本記事のプログラムでは動かない可能性があります。
GitHub-adafruit / Adafruit-MLX90614-Library
Arduinoで非接触温度センサGY-906を使う
Arduinoで非接触温度センサGY-906を使ってターゲットの温度と、外気温を取得してみます。
ArduinoとGY-906の配線
ArduinoとGY-906の配線図です。
Arduinoの3.3Vをセンサモジュールへ供給し、SCLとSDAをそれぞれつなぎます。GY-906センサモジュールは、プルアップ抵抗が内蔵されているのでそのまま繋ぐことが可能です。
ソースコード(Arduino版)
こちらがGY-906を使った基本的なプログラムになります。
#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_MLX90614.h>
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
void setup() {
Serial.begin(9600);
mlx.begin();
}
void loop() {
Serial.print("Ambient = "); Serial.print(mlx.readAmbientTempC());
Serial.print("*C\tObject = "); Serial.print(mlx.readObjectTempC()); Serial.println("*C");
// Serial.print("Ambient = "); Serial.print(mlx.readAmbientTempF());
// Serial.print("*F\tObject = "); Serial.print(mlx.readObjectTempF()); Serial.println("*F");
Serial.println();
delay(1000);
}
ソースコードの解説
プログラム中のObjectが「対象物の赤外線から得た温度」です。Ambientは環境温度、つまり外気温を意味します。センサ自体が熱せられてしまうと、外気温も上がってしまうので注意しましょう。 プログラムでは摂氏温度を取得しましたが、華氏温度で取得したい場合は、readObjectTempFを使ってください。
体温を測定してみた
実際に指を近づけて体温を測定してみました。こちらの映像のとおり、かなり接近させないと正確な温度測定は難しいです。
赤外線センサですのであらかじめケースで覆われている方が扱いやすく、精度も高そうです。
▼ また、体温測定が目的でしたら、素直に製品を買われることをおすすめします。
M5StickC PLUS改良版
ここからはM5StickC PLUSを使った改良版をご紹介します。GY-906はHATモジュールにしてみました。
用意するもの
M5StickC PLUSの使い方は M5StickC PLUSでArduinoをはじめよう! をご覧ください。
HAT化について
M5StickC PLUSでセンサを扱いやすくするため、エッチングで基板製作してセンサをHAT化しました。もちろんユニバーサル基板でも作れますし、スイッチサイエンスさんから出ているユニバーサル基板内蔵のHATモジュールを使ってもよさそうです。
M5StickC PLUSとGY-906の配線
M5StickC PLUS | GY-906 |
---|---|
GND | GND |
3V3 | VIN |
G0 | SDA |
G26 | SCL |
センサをHAT化したかったので、G0、G26を使ったI2C通信を行います。
GROVEケーブルを使って、G32(SDA)、G33(SCL)に接続しても可能です。
プログラムの仕様
これからつくるプログラムは、次のとおりです。
- M5StickC PLUSのAボタンを押して、温度測定の開始
- 測定が完了したらビープ音を鳴らし、測定を停止する
- 対象物の温度を100回サンプルし、メディアンフィルタで中央値を計算
- ディスプレイに、対象物の温度と外気温を表示する
ソースコード
こちらが、M5StickC PLUS版に改良されたソースコードとなります。ただし、Filter.hは自作ライブラリですので、後述を参考に実装してください。
#include <M5StickCPlus.h>
#include <Adafruit_MLX90614.h>
#include <Wire.h>
#include "Filter.h"
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
Filter filter = Filter();
#define BUTTON_A 37
bool enableMesure = true;
void measureTemp() {
Serial.println("Starting measure temp...");
size_t s_len = 100;
float s[s_len];
float ambientTemp = mlx.readAmbientTempC();
for (size_t i = 0; i < s_len; i++) {
s[i] = mlx.readObjectTempC();
}
float objectTemp = filter.medianFilter(s, s_len);
displayLCD(ambientTemp, objectTemp);
playBeep();
}
void setup() {
M5.begin();
while(!setCpuFrequencyMhz(10)){ // ←必須(CPU: 240MHz, 160, 80, 40, 20, 10)
;
}
Wire.begin(0, 26); // ←必須(G0->SDA, G26->SCL)
mlx.begin();
M5.Axp.ScreenBreath(10);
M5.Lcd.fillScreen(WHITE);
M5.Lcd.setTextColor(BLACK);
M5.Lcd.setTextSize(2);
M5.Lcd.setCursor(5, 10);
M5.Lcd.printf("Press the A button to start and end measurement.");
}
void loop(){
M5.update();
if(M5.BtnA.wasPressed()){
Serial.println("M5.BtnA.wasPressed()");
if (enableMesure) {
enableMesure = false;
measureTemp();
enableMesure = true;
}
}
}
void displayLCD(float amb, float obj) {
M5.Lcd.fillScreen(WHITE);
M5.Lcd.setTextSize(1);
M5.Lcd.setCursor(5, 10);
M5.Lcd.printf("Ambient temperature", amb);
M5.Lcd.setTextSize(3);
M5.Lcd.setCursor(5, 25);
M5.Lcd.printf("%.1f", amb);
M5.Lcd.setTextSize(1);
M5.Lcd.setCursor(5, 70);
M5.Lcd.printf("Object temperature");
M5.Lcd.setTextSize(5);
M5.Lcd.setCursor(5, 85);
M5.Lcd.printf("%.1f", obj);
}
void playBeep() {
M5.Beep.tone(3000);
delay(50);
M5.Beep.mute();
delay(50);
M5.Beep.tone(3000);
delay(50);
M5.Beep.mute();
delay(50);
}
ソースコードの注意点
setCpuFrequencyMhz(10)でCPUのクロック周波数を10MHzに指定しないと動きませんでした。 また、G0、G26をI2Cとして使う場合は、Wire.begin(0, 26, 400000);のように指定します。メディアンフィルタの実装
先ほどのプログラム中のFilterクラスについて解説します。このクラスは自作ライブラリで、メディアンフィルタの関数が実装されてます。
メディアンフィルタとは
メディアンフィルタとは、サンプルを昇順または降順にならべて、その中央値を採用するフィルタです。平均値と違い、大幅にズレた値などを無視できるため、画像のノイズ除去などに使われます。
並べ替えて、真ん中の値を採用する
図のように、周りの数字が1、2、3のように低いのに、明らかに不自然な7という大きなセンサノイズが入った場合を考えてみます。
メディアンフィルタでは、サンプル(周囲の値)を小さい順に並べ、真ん中の値を採用します。至ってシンプルです。 平均値の場合はノイズ値も加算されてしまいますが、メディアンフィルタですとセンサノイズをキレイにに除去できます。この利点を活かして、画像のフィルタリングなどでよく使われます。
今回の温度測定でも、手ブレなどによりセンサノイズが混入しますので、メディアンフィルタで少しでも正確な温度を測定できないか試してみました。
ソースコード
次に示すのが、メディアンフィルタを実装しているFilterクラスのソースコードです。 C++のクラスでライブラリ化してみました。Filter.hとFilter.cppをそれぞれ作成し、.inoと同じ場所に保存して使ってください。
Filter.h
#ifndef Filter_h
#define Filter_h
#include <Arduino.h>
class Filter {
public:
Filter();
float medianFilter(float s[], size_t len);
};
#endif
Filter.cpp
#include "Filter.h"
Filter::Filter() {
}
float Filter::medianFilter(float s[], size_t len) {
for (size_t i=0; i<len; ++i) {
for (size_t j=i+1; j<len; ++j) {
if (s[i] > s[j]) {
float tmp = s[i];
s[i] = s[j];
s[j] = tmp;
}
}
}
int m = len / 2;
return s[m];
}
C言語の配列の注意点
メディアンフィルタのライブラリをつくっている時に、大変つまづいたことがありますので述べておきます。 それは、C言語で配列を引数に渡す時のことです。
ダメな例
こちらのプログラムでは、sizeof(array)の要素数を正しく取得できません。理由は、関数の引数に渡された配列がポインタ型になるためです。
void hoge(int array[]) {
for (size_t i = 0; i < sizeof(array) / sizeof(array[0]); ++i) {
doSomething();
}
}
正しい例
こちらのように、関数の呼び出し側であらかじめ要素数を計算し、引数へ渡しましょう。
void hoge(int array[], size_t len) {
for (size_t i = 0; i < len; i++) {
doSomething();
}
}
色々なものを測定してみた
HAT化した非接触温度センサとM5StickC PLUSを使って、色々なものを測定して遊んでみました。
フライパンの温度や、はんだごての温度など、直接さわれない高温なモノの温度測定も可能です。正確さはそれほどないですが、興味のある時にサクッと温度測定できるという手軽さはなかなかの魅力ではないでしょうか。