MEMS温度センサを使おう

投稿者:

発売前新発売の商品ですがオムロンのMEMS温度センサを使って簡易サーモグラフィーみたいなものを作りました。
今回使った温度センサは、非接触で4x4の範囲の温度を測ることができます(1x8のものもあります)。一般的なサーモグラフィー用の温度センサに比べると解像度がかなり低いのですが、そのぶんお手頃価格で購入できます。
MEMS thermal sensor by OMRON D6T-44L-06
なお、スイッチサイエンスでは、4x4のほうの温度センサ(形D6T-44L-06)とケーブル(ハーネス)を近日中に販売開始します販売しています。興味を持たれた方は販売開始までしばらくお待ちください。温度センサハーネスを発売しました。

Arduinoと温度センサの間はI2Cで通信するので、I2C通信の機能が割り振られているAnalogピンにセンサを接続します。(今回使ったのはArduino Duemilanoveですが、Unoでも同じです。Leonardoだと違うので、適宜変更してください)

MEMS thermal sensor by OMRON D6T-44L-06
ピン配置は左からGND、VCC(5V)、SDA、SCL

温度センサのピン配置はセンサ(レンズ)を上に向けた時に、コネクタに向かって右からGND、VCC(5V)、SDA、SCLですので、

  • SCL - A5
  • SDA - A4
  • VCC - A3
  • GND - A2

と接続しました。VCCとGNDは正しくは電源とGNDの端子につなぐべきですが、この温度センサは消費電流が標準で5mAと低消費電力なので、GPIOポートを出力にしてHighとLowに設定することで電源を供給し、接続の手間を減らしています。
MEMS thermal sensor + Arduino

I2C通信を行うためにWireライブラリを入れています。ただ温度センサから送られてくるデータは35バイトなので、32バイト以上も受信するためにfenrirさんのWireExtライブラリも使っています。

やっていることはさほど難しくなくて、シリアルポートから0x01が送られてきたら温度センサから温度データを読み出してシリアルポートに送り出すだけです。デバッグで楽をするためにテキストで送信しましたが、送信データ量を減らしたいならバイナリで送信したほうがいいでしょう。長くなるのでソースコードは記事の最後に付けておきます。ソースではJSONで送信する関数も入れておきました。(JSON出力は未テストなので間違ってたらごめんなさい)
なお、改行コードはCR+LF(0x0D+0x0A)です。

画面表示がないとつまらないので、PCで受信して画面表示することにしました。開発言語はProcessingです。ソースは同じく最後に付けておきます。Arduinoにデータのリクエストを送信し、少し待ってからシリアルポートをチェックし、データが来ていたら全部のデータが受信できるまでまたしばらく待ってから受信します。受信したデータはカンマ区切りのテキストなので、splitで分割してfloatで浮動小数点数値に変換して配列に格納します。あとは温度ごとに色を設定してから四角を描いて、を16回繰り返して1回分の処理が完了します。温度の数値も表示しておきました。こういったリアルタイムの画像表示をするプログラムをさっと作りたいときにはProcessingが便利ですね。
MEMS thermal sensor + Arduino + Processing

そんなわけで、繰り返しにはなりますが4x4のほうの温度センサ(形D6T-44L-06)とケーブル(ハーネス)を近日中に販売開始します販売しています。興味を持たれた方は販売開始までしばらくお待ちください。温度センサハーネスを発売しました。

// D6T-44L test program for Arduino
// D6T_test_Arduino.ino
// 2013/03/27 http://www.switch-science.com

#include <Wire.h>
#include <WireExt.h>

#define D6T_addr 0x0A
#define D6T_cmd 0x4C

int rbuf[35];
float tdata[16];
float t_PTAT;

void setup()
{
  Wire.begin();
  Serial.begin(9600);
  Serial.flush();
  
  pinMode(17,OUTPUT);    // 電源(VCC)用設定 D17(A3)ピン
  digitalWrite(17,HIGH);
  pinMode(16,OUTPUT);    // 電源(GND)用設定 D16(A2)ピン
  digitalWrite(16,LOW);
}

void loop()
{
  int i;

  if (Serial.available() > 0) {     // 受信したデータが存在したら
    int inByte = Serial.read();     // 受信データを読み込む
    if (inByte == 0x0001) {         // 送られてきたデータが0x01だったら

      Wire.beginTransmission(D6T_addr);
      Wire.write(D6T_cmd);
      Wire.endTransmission();

      if (WireExt.beginReception(D6T_addr) >= 0) {
        i = 0;
        for (i = 0; i < 35; i++) {
          rbuf[i] = WireExt.get_byte();
        }
        WireExt.endReception();

        t_PTAT = (rbuf[0]+(rbuf[1]<<8))*0.1;
        for (i = 0; i < 16; i++) {
          tdata[i]=(rbuf[(i*2+2)]+(rbuf[(i*2+3)]<<8))*0.1;
        }
//      output_json(); // JSONで出力
        output_csv();  // CSVで出力
      }
    }
  }
}

// CSVで温度を出力(PTATなし)
void output_csv() {
  for (int i = 0; i < 16; i++) {
    Serial.print(tdata[i]);
    if (i < 15) {
      Serial.print(",");
    } 
    else {
      Serial.println();
    }
  }
}

// JSONで温度を出力(PTATあり)
void output_json() {
  Serial.println("{");
  Serial.print("\"PTAT\":");
  Serial.print(tdata[0]);
  Serial.println(",");
  Serial.print("\"TEMP\":[");
  for (int i = 1; i < 15; i++) {
    Serial.print(tdata[i]);
    Serial.print(",");
  }
  Serial.print(tdata[15]);
  Serial.println("]}");
}
/*
  D6T-44L test program for Processing
  2013/03/26 www.switch-science.com
*/

import processing.serial.*;

float[] tdata = new float[17]; // 温度を入れる配列(PTAT込みで来ることも考えて17要素分確保)
float tptat; // PTAT
String portName; // シリアルポート名
int serialport = 0; // 接続するシリアルポート番号を指定する
                    // Macの場合、/dev/tty.*のポートを選択してください。
String buf; // 受信バッファ
color[] tcolor = {#400040,#000080,#006060,#008000,#C0C000,#E0A000,#E00000,#F08080}; // 色テーブル

Serial myPort;  // Create object from Serial class

void setup() {
  size(640,640);
  println(Serial.list());
  portName = Serial.list()[serialport];
  myPort = new Serial(this, portName, 9600);
  myPort.clear();

}
void draw() {
  myPort.write(0x01); // データのリクエストをする
  delay(100); // 100ms待つ(すぐにシリアルポートの受信チェックをしないため)
  while (myPort.available() > 0) { // シリアルポートにデータが来ていたら
    delay(300); // 300ms待つ(データ全体が送信されるのを待つため)
    buf = myPort.readString(); // 受信
    myPort.clear();  // シリアルポート受信バッファのクリア
    tdata = float(split(buf, ','));  // データをカンマで分割し、floatで配列に格納
    for (int i = 0; i < 16; i++) { // 各エリアごとに色を設定し、四角を描画する
      if (tdata[i] < 0) {
        fill(tcolor[0]);
      } else if (tdata[i] < 5) {
        fill(tcolor[1]);
      } else if (tdata[i] < 10) {
        fill(tcolor[2]);
      } else if (tdata[i] < 15) {
        fill(tcolor[3]);
      } else if (tdata[i] < 20) {
        fill(tcolor[4]);
      } else if (tdata[i] < 25) {
        fill(tcolor[5]);
      } else if (tdata[i] < 30) {
        fill(tcolor[6]);
      } else  {
        fill(tcolor[7]);
      }
      rect((i % 4)*160, (i / 4)*160, (i % 4)*160+160, (i / 4)*160+160);
      if (tdata[i]<5) {fill(255);} else {fill(0);}
      textAlign(CENTER, CENTER);
      textSize(20);
      text(str(tdata[i]),(i % 4)*160+80, (i / 4)*160+80);
    }
  }
}