macsbug

M5Stack Thermal Camera with AMG8833

leave a comment »

M5STACK で AMG8833 Thermal sensor を 動かしました。         2018.06.08

AMG8833 Thermal sensor は 3942円で高価です。
AMG8833 熱センサーは 画素数 8×8ピクセルで(24×8)x(24×8)に補間されています。
hkoffer氏作成の M5Stack-Thermal-Camera- を使用しました。
ただし このリストでは 表示の向きが正しく表示しない為、スケッチを修正致しました。

機能:
1 . AMG8833 Thermal sensor 8×8 pixel を(24×8)x(24×8)に補間しています。
2 . Sight added & temperature
3 . Auto max temperature
4 . Auto min temperature
5. センスする距離は約30cm です。(仕様は 人検知が可能な距離:最長7m )

Adafruit AMG88xx Library:
1. AMG88xx GridEYE 8×8 IRカメラ用のライブラリです。
2. AMG8833 I2C 接続。address = 0x69
3. TFT FeatherWing – 2.4″ 320×240 Touchscreen For All Feathers
4. Adafruit AMG8833 Featherwingで動作します。

補足:
_ 現在、テスト領域全体の最高温度のみが示されており、最初は最大温度と
_ 最小温度の自動調整を追加し、中心視界の温度を表示することを意図しています。


.
準備:

No Nomen Link Price Transport
1 AMG8833 Matrice IR 8*8
Thermal Imager Module
Aliexpress :
Your Cee Store    $35.99
3942円 9day
2 adafruit Library Adafruit_AMG88xx  –
3 hoofer sketch & Library M5Stack-Thermal-Camera-

Your Cee Store の輸送期間は 9日 で速いです。

2018.06.08 現在:3942円 ( 1$ 109.5 円換算) $35.99

追記:2018.08.12
Aliexpress : Sean_Wang Electronics Store:$38.30, 4247円(1$ 111円換算)

MOUSER : Pansonic AMG8833 単体1個2582円。

追記:2018.09.06
Aliexpress:Your Cee Store:$34.19, 3942円。輸送期間=15日。

Panasonic 赤外線アレイセンサ Grid-EYE(AMG88)
用途:高機能家電(電子レンジ・エアコン),オフィス省エネ(空調・照明制御),
_  デジタルサイネージ,自動ドア・エレベータ。
AMG8833 : 3.3V, 高性能タイプ ハイゲイン: 0 °C ~ 80 °C
AMG8834 : 3.3V, 高性能タイプ ローゲイン:−20 °C ~ 80 °C
AMG8853 : 5.0V, 高性能タイプ ハイゲイン: 0 °C ~ 80 °C
AMG8854 : 5.0V, 高性能タイプ ローゲイン:−20 °C ~ 80 °C

スケッチ構成:
thermal_cam_interpolate
_ thermal_cam_interpolate.ino
_ interpolation.cpp


.
配線:

PROT Board に 以下の4本を配線します。

組み立て:
裏蓋ケースを作り組み上げました。


.
参考:

Adafruit:AMG88xx thermal sensor
Adafruit AMG8833 8×8 Thermal Camera Sensor:pdf
YouTube:M5Stack Thermal Imaging Camera
twitter : Offer DIYER
Thingiverse : M5Stack Thermal Imaging Camera Case:3Dプリントケース
HACKADAY:WHO SAID THERMAL CAMERAS WEREN’T ACCESSIBLE TO THE MASSES?
Pansonic 赤外線アレイセンサ Grid=EYE (AMG88)
Infrared array sensor “Grid-EYE” AMG88 * *:参考仕様書


.
スケッチ修正:現象と対策。
May 12, 2018 の M5Stack-Thermal-Camera- は 修正が必要です。
1. 画像が横向き:M5.Lcd.setRotation(0) を M5.Lcd.setRotation(1)に変更します。
2. 文字と画像の縦が逆、画像の左右が逆:
_ void drawpixels の float val = get_point(p, rows, cols, x, y); を
_ float val = get_point(p, rows, cols, cols-x, rows-y); にし 縦を逆にします。
_ これにより正常に表示しました。


.
感想:

AMG8833 の画素数は 8×8 です。そして価格は高価です。
_ 8×8 のサイズでは 荒すぎ、価格が高くて意味がありませんでした。
_ そこへ hkoffer氏 により 24×24 が可能となり 見やすくなりました。
_ 高価ですが 24×24 なら体験したく購入しました。

_ 国内 スイッチサイエンスでの価格は 今回の業者より千円程高く購入対象にならず。
_ Aliexpress の Your Cee Store からは なんと 9日で届くと言う速さでした。

_ 温度分布の表示は まずまずの感じでした。


.
スケッチ:

thermal_cam_interpolate
_ thermal_cam_interpolate.ino
_ interpolation.cpp

// M5Stack Thermal Camera with AMG8833 : 2018.06.08 Modified by macsbug
/***************************************************************************
  This is a library for the AMG88xx GridEYE 8x8 IR camera
  This sketch makes an inetrpolated pixel thermal camera with the
  GridEYE sensor and a 2.4" tft featherwing:
	 https://www.adafruit.com/product/3315
  Designed specifically to work with the Adafruit AMG8833 Featherwing
          https://www.adafruit.com/product/3622
  These sensors use I2C to communicate. The device's I2C address is 0x69
  Adafruit invests time and resources providing this open source code,
  please support Adafruit andopen-source hardware by purchasing products
  from Adafruit!
  Written by Dean Miller, James DeVito & ladyada for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
 ***************************************************************************/
// AMG8833 thermal sensor : https://github.com/adafruit/Adafruit_AMG88xx
// https://github.com/hkoffer/M5Stack-Thermal-Camera-/blob/master/thermal_cam_interpolate.ino
// Github : https://macsbug.wordpress.com/2018/06/08/m5stack-thermal-camera-with-amg8833/
//==========================================================================
#include <M5Stack.h>
#include "M5StackUpdater.h"  // SD UPDATER
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_AMG88xx.h>
byte MINTEMP = 20; //low range of the sensor (this will be blue on the screen)
byte MAXTEMP = 32; //high range of the sensor (this will be red on the screen)
const uint16_t camColors[] = { 0x480F,   //the colors we will be using
 0x400F,0x400F,0x400F,0x4010,0x3810,0x3810,0x3810,0x3810,0x3010,0x3010,
 0x3010,0x2810,0x2810,0x2810,0x2810,0x2010,0x2010,0x2010,0x1810,0x1810,
 0x1811,0x1811,0x1011,0x1011,0x1011,0x0811,0x0811,0x0811,0x0011,0x0011,
 0x0011,0x0011,0x0011,0x0031,0x0031,0x0051,0x0072,0x0072,0x0092,0x00B2,
 0x00B2,0x00D2,0x00F2,0x00F2,0x0112,0x0132,0x0152,0x0152,0x0172,0x0192,
 0x0192,0x01B2,0x01D2,0x01F3,0x01F3,0x0213,0x0233,0x0253,0x0253,0x0273,
 0x0293,0x02B3,0x02D3,0x02D3,0x02F3,0x0313,0x0333,0x0333,0x0353,0x0373,
 0x0394,0x03B4,0x03D4,0x03D4,0x03F4,0x0414,0x0434,0x0454,0x0474,0x0474,
 0x0494,0x04B4,0x04D4,0x04F4,0x0514,0x0534,0x0534,0x0554,0x0554,0x0574,
 0x0574,0x0573,0x0573,0x0573,0x0572,0x0572,0x0572,0x0571,0x0591,0x0591,
 0x0590,0x0590,0x058F,0x058F,0x058F,0x058E,0x05AE,0x05AE,0x05AD,0x05AD,
 0x05AD,0x05AC,0x05AC,0x05AB,0x05CB,0x05CB,0x05CA,0x05CA,0x05CA,0x05C9,
 0x05C9,0x05C8,0x05E8,0x05E8,0x05E7,0x05E7,0x05E6,0x05E6,0x05E6,0x05E5,
 0x05E5,0x0604,0x0604,0x0604,0x0603,0x0603,0x0602,0x0602,0x0601,0x0621,
 0x0621,0x0620,0x0620,0x0620,0x0620,0x0E20,0x0E20,0x0E40,0x1640,0x1640,
 0x1E40,0x1E40,0x2640,0x2640,0x2E40,0x2E60,0x3660,0x3660,0x3E60,0x3E60,
 0x3E60,0x4660,0x4660,0x4E60,0x4E80,0x5680,0x5680,0x5E80,0x5E80,0x6680,
 0x6680,0x6E80,0x6EA0,0x76A0,0x76A0,0x7EA0,0x7EA0,0x86A0,0x86A0,0x8EA0,
 0x8EC0,0x96C0,0x96C0,0x9EC0,0x9EC0,0xA6C0,0xAEC0,0xAEC0,0xB6E0,0xB6E0,
 0xBEE0,0xBEE0,0xC6E0,0xC6E0,0xCEE0,0xCEE0,0xD6E0,0xD700,0xDF00,0xDEE0,
 0xDEC0,0xDEA0,0xDE80,0xDE80,0xE660,0xE640,0xE620,0xE600,0xE5E0,0xE5C0,
 0xE5A0,0xE580,0xE560,0xE540,0xE520,0xE500,0xE4E0,0xE4C0,0xE4A0,0xE480,
 0xE460,0xEC40,0xEC20,0xEC00,0xEBE0,0xEBC0,0xEBA0,0xEB80,0xEB60,0xEB40,
 0xEB20,0xEB00,0xEAE0,0xEAC0,0xEAA0,0xEA80,0xEA60,0xEA40,0xF220,0xF200,
 0xF1E0,0xF1C0,0xF1A0,0xF180,0xF160,0xF140,0xF100,0xF0E0,0xF0C0,0xF0A0,
 0xF080,0xF060,0xF040,0xF020,0xF800,
};
Adafruit_AMG88xx amg;
#define AMG_COLS 8
#define AMG_ROWS 8
float pixels[AMG_COLS * AMG_ROWS];
#define INTERPOLATED_COLS 24
#define INTERPOLATED_ROWS 24
int max_v =  0;
int min_v = 80;
float get_point(float *p,uint8_t rows,uint8_t cols,int8_t x,int8_t y);
void set_point(float *p,uint8_t rows,uint8_t cols,int8_t x,int8_t y,float f);
void get_adjacents_1d(float *src, float *dest, uint8_t rows, uint8_t cols, 
                      int8_t x, int8_t y);
void get_adjacents_2d(float *src, float *dest, uint8_t rows, uint8_t cols,
                      int8_t x, int8_t y);
float cubicInterpolate(float p[], float x);
float bicubicInterpolate(float p[], float x, float y);
//==========================================================================
void interpolate_image(float *src, uint8_t src_rows, uint8_t src_cols, 
                       float *dest, uint8_t dest_rows, uint8_t dest_cols);
//==========================================================================
void setup(){
  M5.begin();
  Wire.begin(); 
  if(digitalRead(BUTTON_A_PIN) == 0){updateFromFS(SD);ESP.restart();} // SD
  M5.setWakeupButton(BUTTON_B_PIN);
  M5.Lcd.begin();
  M5.Lcd.setRotation(1);  // 0 to 1 :Modified
  M5.Lcd.fillScreen(TFT_BLACK);
  int icolor = 255;
  for (int irow = 16; irow <= 223;  irow++){
    M5.Lcd.drawRect(0, 0, 35, irow, camColors[icolor]);
    icolor--;
  }
  infodisplay();
  if (!amg.begin()){ while (1){delay(1);}}
}
//==========================================================================
void loop() {
  if (M5.BtnA.pressedFor(1000)){MINTEMP = min_v;min_v = 80;infodisplay();}
  if (M5.BtnA.wasPressed()) {
    if (MINTEMP <= 0){MINTEMP = MAXTEMP - 1;infodisplay();
    }else{MINTEMP--;infodisplay();
    }
  }
  if (M5.BtnB.pressedFor(1000)){ M5.powerOFF();}
  if (M5.BtnC.pressedFor(1000)){MAXTEMP = max_v;max_v = 0;infodisplay();}
  if (M5.BtnC.wasPressed()) {
    if (MAXTEMP >= 80){MAXTEMP = MINTEMP + 1;infodisplay();
    }else{MAXTEMP++;infodisplay();
    }
  }
  M5.update();
  amg.readPixels(pixels);   //read all the pixels
  for (int i = 1; i <= AMG88xx_PIXEL_ARRAY_SIZE; i++){}
  float dest_2d[INTERPOLATED_ROWS * INTERPOLATED_COLS];
  interpolate_image(pixels, AMG_ROWS, AMG_COLS, dest_2d, 
    INTERPOLATED_ROWS, INTERPOLATED_COLS);
  uint16_t boxsize = min(M5.Lcd.width() / INTERPOLATED_COLS, 
    M5.Lcd.height() / INTERPOLATED_COLS);
  drawpixels(dest_2d, INTERPOLATED_ROWS, INTERPOLATED_COLS, 
    boxsize, boxsize, false);
  max_v = INT_MIN;
  //  int max_i = 0;
  int spot_v = pixels[28];
  for (int itemp = 0;itemp < sizeof(pixels) / sizeof(pixels[0]);itemp++){
    if ( pixels[itemp] > max_v ){max_v = pixels[itemp];//max_i = itemp;
    }
    if ( pixels[itemp] < min_v ){min_v = pixels[itemp];//max_i = itemp;
    }
  }
  M5.Lcd.setTextSize(2);
  M5.Lcd.fillRect (284,  18, 36, 16, TFT_BLACK);
  M5.Lcd.fillRect (284, 130, 36, 16, TFT_BLACK);
  M5.Lcd.setCursor(284,  18);
  M5.Lcd.setTextColor(TFT_WHITE);
  if ((max_v > 80) | (max_v < 0)) {
    M5.Lcd.setTextColor(TFT_RED);
    M5.Lcd.printf("Err");
  }else{
    M5.Lcd.printf("%dC",max_v);
    M5.Lcd.setCursor(284, 130);
    M5.Lcd.printf("%dC",spot_v);
    M5.Lcd.drawCircle(160, 120,   6, TFT_WHITE);
    M5.Lcd.drawLine  (160, 110, 160, 130, TFT_WHITE);
    M5.Lcd.drawLine  (150, 120, 170, 120, TFT_WHITE);
  }
}
//==========================================================================
void infodisplay(void) {  /***infodisplay()*****/
  M5.Lcd.setTextColor(TFT_WHITE);
  // M5.Lcd.setCursor(288, 230);
  // M5.Lcd.printf("Power");
  M5.Lcd.fillRect(0, 0, 36, 16, TFT_BLACK);
  M5.Lcd.setTextSize(2);
  M5.Lcd.setCursor(0, 1);
  M5.Lcd.printf("%dC",MAXTEMP);
  M5.Lcd.setCursor(0, 225);
  M5.Lcd.fillRect(0, 225, 36, 16, TFT_BLACK);
  M5.Lcd.printf("%dC",MINTEMP);
  M5.Lcd.setCursor(284, 0);
  M5.Lcd.printf("Max");
  M5.Lcd.setCursor(284, 100);
  //  M5.Lcd.printf("Spot");
  M5.Lcd.drawCircle(300, 120, 6, TFT_WHITE);
  M5.Lcd.drawLine(300, 110, 300, 130, TFT_WHITE);
  M5.Lcd.drawLine(290, 120, 310, 120, TFT_WHITE);
}
//==========================================================================
void drawpixels(float *p, uint8_t rows, uint8_t cols, uint8_t boxWidth, 
                uint8_t boxHeight, boolean showVal) {
  int colorTemp;
  for (int y = 0; y < rows; y++) {
    for (int x = 0; x < cols; x++) {
      float val = get_point(p, rows, cols, cols-x, rows-y); // Modified
      if (val >= MAXTEMP) colorTemp = MAXTEMP;
      else if (val <= MINTEMP) colorTemp = MINTEMP;
      else colorTemp = val;
      uint8_t colorIndex = map(colorTemp, MINTEMP, MAXTEMP, 0, 255);
      colorIndex = constrain(colorIndex, 0, 255);
      uint16_t color;  //draw the pixels!
      color = val * 2;
      M5.Lcd.fillRect(40 + boxWidth * x, boxHeight * y,
                      boxWidth, boxHeight, camColors[colorIndex]);
    }
  }
}
//==========================================================================

Written by macsbug

6月 8, 2018 @ 11:55 pm

カテゴリー: ESP32, M5STACK

コメントを残す