【Arduino】非接触温度センサ(GY-906)をつかってみた

こんなこと、やります。
- Arduinoで非接触温度センサGY-906を使う
- GY-906で物体の温度と環境温度の測定
- M5StickC PLUSでHATモジュール化
- メディアンフィルタで測定精度を上げる
準備
GY-906ライブラリのインストール
Arduino IDEをお使いの場合は、ライブラリマネージャで「Adafruit MLX90614」検索し 「Adafruit-MLX90614-Library」のバージョン1.1.x をインストールします。最新の2.0.0を使うと、本記事のプログラムでは動かない可能性があります。

https://github.com/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();
Adafruit_MLX90614 mlx
void setup() {
.begin(9600);
Serial.begin();
mlx}
void loop() {
.print("Ambient = "); Serial.print(mlx.readAmbientTempC());
Serial.print("*C\tObject = "); Serial.print(mlx.readObjectTempC()); Serial.println("*C");
Serial// Serial.print("Ambient = "); Serial.print(mlx.readAmbientTempF());
// Serial.print("*F\tObject = "); Serial.print(mlx.readObjectTempF()); Serial.println("*F");
.println();
Serial(1000);
delay}
ソースコードの解説
プログラム中のObject
が「対象物の赤外線から得た温度」です。Ambient
は環境温度、つまり外気温を意味します。センサ自体が熱せられてしまうと、外気温も上がってしまうので注意しましょう。
プログラムでは摂氏温度を取得しましたが、華氏温度で取得したい場合は、readObjectTempF
を使ってください。
体温を測定してみた
実際に指を近づけて体温を測定してみました。こちらの映像のとおり、かなり接近させないと正確な温度測定は難しいです。
M5StickC PLUS改良版
ここからはM5StickC
PLUSを使った改良版をご紹介します。GY-906
は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();
Adafruit_MLX90614 mlx = Filter();
Filter filter
#define BUTTON_A 37
bool enableMesure = true;
void measureTemp() {
.println("Starting measure temp...");
Serialsize_t s_len = 100;
float s[s_len];
float ambientTemp = mlx.readAmbientTempC();
for (size_t i = 0; i < s_len; i++) {
[i] = mlx.readObjectTempC();
s}
float objectTemp = filter.medianFilter(s, s_len);
(ambientTemp, objectTemp);
displayLCD();
playBeep}
void setup() {
.begin();
M5
while(!setCpuFrequencyMhz(10)){ // ←必須(CPU: 240MHz, 160, 80, 40, 20, 10)
;
}
.begin(0, 26); // ←必須(G0->SDA, G26->SCL)
Wire.begin();
mlx
.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.");
M5
}
void loop(){
.update();
M5if(M5.BtnA.wasPressed()){
.println("M5.BtnA.wasPressed()");
Serial
if (enableMesure) {
= false;
enableMesure ();
measureTemp= true;
enableMesure }
}
}
void displayLCD(float amb, float obj) {
.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);
M5
}
void playBeep() {
.Beep.tone(3000);
M5(50);
delay.Beep.mute();
M5(50);
delay.Beep.tone(3000);
M5(50);
delay.Beep.mute();
M5(50);
delay}
ソースコードの注意点
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:
();
Filterfloat 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];
[i] = s[j];
s[j] = tmp;
s}
}
}
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}
}
sizeof(array)
はsizeof(int *)
と同じことになってしまいます。
正しい例
こちらのように、関数の呼び出し側であらかじめ要素数を計算し、引数へ渡しましょう。
void hoge(int array[], size_t len) {
for (size_t i = 0; i < len; i++) {
();
doSomething}
}
色々なものを測定してみた
HAT化した非接触温度センサとM5StickC
PLUSを使って、色々なものを測定して遊んでみました。
フライパンの温度や、はんだごての温度など、直接さわれない高温なモノの温度測定も可能です。正確さはそれほどないですが、興味のある時にサクッと温度測定できるという手軽さはなかなかの魅力ではないでしょうか。
関連記事
- ESP32でAdafruit STEMMA Soil Sensorを使って土壌水分量と温度の測定
- M5StickC PLUSの加速度センサで振動測定と周波数特性
- ArduinoでTFT LCDディスプレイ(ST7789)を使ってみる
- DS18B20の使い方|Arduino・ESP32・Raspberry Pi
- ESP32でST7735 TFT LCD液晶ディスプレイを使ってみる