MLX90620 / MLX90621 - 16X4 pixel IR thermal array

yes, of course :slight_smile:

HI,

i have found an distributor for Germany. Which type of sensor of the MLX 90620 should i use the 60° or 40°?

Thanks a lot.

Cu kami

Hi,

anyone who can tell me if i should use the 60° or 40° FOV??
And should i need a Lens?

Thanks a lot.

Cu kami

Nauman048:
Hi all
I am trying to communicate using SPI protocol between two arduino uno boards. I have writthen a very simple code to transfer a single character from master. The code is as following

#include <SPI.h>
#include "pins_arduino.h"

void setup (void)
{
}

void loop (void)
{

digitalWrite(SS, HIGH); // ensure SS stays high

SPI.begin ();

delay (5000); // 5 seconds delay to start logic analyser.

// enable Slave Select
digitalWrite(SS, LOW); // SS is pin 10

// send test string
SPI.transfer ( 'c');

// disable Slave Select
digitalWrite(SS, HIGH);

// turn SPI hardware off
SPI.end ();

while (1); //loop
}

Please correct the code if its not right. And I really want to know that how to recieve that character on arduino uno in slave mode. There is a command SPI.transfer() to send data on SPI where as I haven't seen any command to recieve it.

Thanks and regards

Hi, wrong topic...

kami83:
Hi,

anyone who can tell me if i should use the 60° or 40° FOV??
And should i need a Lens?

Thanks a lot.

Cu kami

it depends on your intended application, and which one you can find (I was looking for the 40° version but futureelectronics had only the 60° one, so I bought that...)

Hi,

i would like to make good picture for a distance like 1-2 meters. What is with a Lens? Do i need one?

Thx a lot.

Cu kami

You won't get a good picture with 64 pixels.

with the 40° version @2m distance you'll get a horizontal view of 1,46 mt, so about 9 squared centimeters per pixel
with the 60° version @2m distance you'll get a horizontal view of 2,31 mt, so about 14 squared centimeters per pixel

I'm not familiar with lenses for this type of sensors, so nothing I can say about this could help you... I just know that the mlx90620 works just fine without them. I don't know if particular lens exists and could help to narrow the FOV

there have ready module via I2C
http://www.roboard.com/G212.html

kami83:
i am also really interested in building my own cheap camera, but i cannot get any sensor here in Germany.
Is there any chance to get some? Any tips?

Sourcing the part seems to be a problem.
I ordered one here from as-electronic (Germany): http://as-electronic.net/shop/article_MLX90620ESF-BAD/MLX90620ESF-BAD-16x4-IR-Matrix-Temperatursensor.html?sessid=00GGQRHtRxMwPyV6emEwYDQGYumL5IhN16aK7VHOgiTEIWxkFn615nzhkErgWGDs&shop_param=cid%3D18%26aid%3DMLX90620ESF-BAD%26

Shipped within two days.

Below are the temperature values I get. The sensor is pointing towards a wall, so the temperatures should be almost the same.

-43.29 -25.06 -20.19 -14.03 -17.91 -9.14  -28.29 -14.59 -13.57 0.49   -4.85  -14.13 -10.58 -0.23  -2.00  -4.07  
-16.22 6.06   3.53   -4.15  2.72   8.47   2.10   -3.24  1.14   7.40   9.65   1.90   -7.16  7.83   6.58   3.11   
3.07   6.51   8.03   1.24   3.46   0.64   8.97   0.92   1.76   7.03   4.71   3.91   7.54   12.93  7.92   7.25   
-7.14  5.69   8.91   4.91   4.54   5.32   8.59   1.41   5.62   8.11   10.34  2.61   6.35   -8.17  0.14   1.68

This is the calibration information from my sensor:

a_ij:
-87 -82 -86 -84 -78 -76 -70 -74 -74 -71 -71 -69 -72 -66 -66 -70 
-66 -65 -65 -68 -70 -64 -62 -64 -63 -59 -62 -64 -58 -59 -58 -62 
-60 -59 -56 -57 -57 -51 -55 -52 -53 -50 -53 -54 -54 -50 -49 -51 
-45 -45 -48 -47 -47 -43 -44 -48 -48 -43 -45 -42 -45 -39 -44 -44

b_ij:
-60 -60 -60 -68 -51 -55 -51 -60 -51 -51 -51 -68 -60 -43 -43 -51 
-47 -51 -47 -43 -34 -51 -43 -51 -47 -43 -43 -47 -43 -43 -43 -43 
-43 -43 -43 -77 -34 -38 -43 -51 -38 -43 -43 -38 -43 -34 -34 -34 
-38 -34 -43 -34 -34 -34 -34 -34 -30 -30 -34 -30 -34 -38 -43 -30

alpha_ij:
1.01E-8 1.29E-8 1.37E-8 1.36E-8 1.16E-8 1.48E-8 1.35E-8 1.48E-8 1.26E-8 1.57E-8 1.54E-8 1.50E-8 1.37E-8 1.53E-8 1.60E-8 1.61E-8 
1.41E-8 1.69E-8 1.71E-8 1.65E-8 1.61E-8 1.78E-8 1.79E-8 1.69E-8 1.56E-8 1.75E-8 1.84E-8 1.82E-8 1.55E-8 1.84E-8 1.89E-8 1.82E-8 
1.68E-8 1.94E-8 1.91E-8 1.90E-8 1.66E-8 1.79E-8 1.89E-8 1.76E-8 1.64E-8 1.77E-8 1.84E-8 1.73E-8 1.65E-8 1.66E-8 1.68E-8 1.68E-8 
1.36E-8 1.57E-8 1.65E-8 1.51E-8 1.49E-8 1.49E-8 1.57E-8 1.54E-8 1.46E-8 1.41E-8 1.47E-8 1.29E-8 1.30E-8 1.26E-8 1.39E-8 1.29E-8

If you compare the calibration information (espc. a_ij and b_ij) with the temperature you will notice a correlation. Is my sensor miscalibrated?
If you have such an sensor, please print the calibration data and post it here. I'd like to know if other sensors have the same huge variance between each pixel.

EDIT: This was caused by useing 3.3V instead of the recommended 2.6V supply, despite that fact the specification says "3.6V max" :frowning:

small patch to calculate alpha_ij on the Arduino instead of a spreadsheet :slight_smile:

  float da0_scale = pow(2, -EEPROM_DATA[0xe3]);
  float alpha_const = (float)(((unsigned int)EEPROM_DATA[0xe1] << 8) + (unsigned int)EEPROM_DATA[0xe0]) * pow(2, -EEPROM_DATA[0xe2]);
  for(int i=0; i<=63; i++) {
    float alpha_var = (float)EEPROM_DATA[0x80 + i] * da0_scale;
    alpha_ij[i] = (alpha_const + alpha_var);
  }

Add it before the end of "void varInitialization(byte EEPROM_DATA[])".

Hi maxbot and IlBaboomba - thank you very much for the example code! It got me started very quickly. I hope you don't mind, but I added quite a few comments so I could better understand the code. I also created a sketch to calculate the alphas.

The repo is here: https://github.com/nseidle/MLX90620_Example

One main improvement was the removal of float v_ir_tgc_comp[64]. v_ir_tgc_comp is only calculated once so an array of floats can be removed. This saves a good pile (256bytes) of RAM.

Let me know if you see any problems or changes that can be made. This is a neat (but expensive!) little sensor.
-Nathan

//Calculate the temperatures seen for each pixel
//Relies on the raw irData array
//Returns an 64-int array called temperatures
void calculate_TO()
{
  float v_ir_off_comp;
  float v_ir_tgc_comp;
  float v_ir_comp;

  //Calculate the offset compensation for the one compensation pixel
  //This is a constant in the TO calculation, so calculate it here.
  int cpix = readCPIX_MLX90620(); //Go get the raw data of the compensation pixel
  float v_cp_off_comp = (float)cpix - (a_cp + (b_cp/pow(2, b_i_scale)) * (Tambient - 25)); 

  for (int i = 0 ; i < 64 ; i++)
  {
    v_ir_off_comp = irData[i] - (a_ij[i] + (float)(b_ij[i]/pow(2, b_i_scale)) * (Tambient - 25)); //#1: Calculate Offset Compensation 

    v_ir_tgc_comp = v_ir_off_comp - ( ((float)tgc/32) * v_cp_off_comp); //#2: Calculate Thermal Gradien Compensation (TGC)

    v_ir_comp = v_ir_tgc_comp / emissivity; //#3: Calculate Emissivity Compensation

    temperatures[i] = sqrt( sqrt( (v_ir_comp/alpha_ij[i]) + pow(Tambient + 273.15, 4) )) - 273.15;
  }
}

Hi,

just got the chance to order a Panasonic GRID-Eye AMG8851 (5 Volt) or AMG8831 (3.3 Volt).

What did you think which one is better the MLX or the GRID-Eye?

Thanks a lot.

Cu kami83

kami83:
Hi,

i would like to make good picture for a distance like 1-2 meters. What is with a Lens? Do i need one?

Thx a lot.

Cu kami

Probably a bit late to answer the question but it could help others.
I can't remember where I read it but if my memory don't fool me, the MLX90620 works in the 5µm to 16µm range. At those wavelength glass is black so you can't use classical optics.

Hi all

I have been following this post for awhile and decided to try and implement the thermocam on the cheap thermocam website with the MLX90620. Using the some of the code on that site and Nathan's code I develop a Processing sketch and an associated Arduino sketch for the way I set things up. Since I borrowed so much of the code from the posts I decided to share what I have so far. Its operational but not perfect.

Here is the link: Thermal Imager Sketches - Google Drive

Hope this helps.

Thermal_Imager Processing Sketch.7z (9.37 KB)

Hi CyberMerln and all,

Thank you for the information. I also did some tests with the MLX90620-BAB.
I was a bit disappointed by the results but I certainly still have code/configuration/tuning issues.

One simple test that fails is to light up a candle and (manually) move the sensor around so that each of the 64 pixel picks up the heat according to the move.

I do not currently have the time to investigate more but I was wondering if such a simple test worked ok for others (and I guess so!).

BTW, I did not use the spreadsheet but the code rmie posted earlier.

Cheers

Hi,

thanks a lot for the answer. I am still thinking about buying the MLX90620 or the Grideye?

Cu kami

Hi,

Thanks for all the information and code. I am trying to get this working on an arduino Mega2560, but it is not communicating at all. Do I have to change something since the SDA/SCL ports (20 & 21) are different? I also found according to the schematic that there are 2 hardware resistors pulled to +5v on the SDA and SCL ports. Could that be the issue?

Thanks!

Sorry, there were no changes required, I just had it wired wrong. :blush: Got it working now. Thanks!

Hello,

I would greatly appreciate guidance with the following problem: There is no data being printed to the Serial Monitor (I have checked the speed and it is correctly set at 115200 baud).

The code for the Sketch I am refering to is at the bottom of this post. Reference: Arduino and MLX90620 16X4 pixel IR thermal array - Reply #11 on: December 25, 2012, 03:35:30 pm MLX90620 / MLX90621 - 16X4 pixel IR thermal array - Exhibition / Gallery - Arduino Forum

I am very new to programming and the Arduino and would appreciate your guidance to get the "Arduino and MLX90620 16X4 pixel IR thermal array" Sketch running. I have the Sketch and the library loaded into the Arduino IDE, the Sketch compiles and uploads to the Arduino with out generating any error messages.

The following is the configuration of the hardware:

Arduino: "OSEPP Uno R3 Plus board" OSEPP - OSEPP™ Uno R3 Plus
Sensor: MLX90620 16x4 IR array used on the RoBoard Module RM-G212 http://www.roboard.com/G212.html

I have confirmed that the Arduino and MLX90620 on the RoBoard Module RM-G212 are communicating via i2c by using a Sketch that reports all the addresses avaliable on an i2c device. Results are as follows:

Scanning...
I2C device found at address 0x50 !
I2C device found at address 0x51 !
I2C device found at address 0x52 !
I2C device found at address 0x53 !
I2C device found at address 0x54 !
I2C device found at address 0x55 !
I2C device found at address 0x56 !
I2C device found at address 0x57 !
I2C device found at address 0x60 !
done

Your help will be greatly appreciated.

/*
 * Attention! I commented out the alpha_ij array, so if you're going to compile the sketch you'll get for sure an error.
 * You should replace all 64 values with the alpha_ij calculated using the values stored in your MLX90620's EEPROM. 
 * I suggest you to make an EEPROM dump, print it on the Serial port and store it in a file. From there, with the help of a spreadsheet (Libreoffice, Google Docs, Excel...) calculate your own alpha_ij values. 
 * Please also pay attention to your emissivity value: since in my case it was equal to 1, to save SRAM i cut out that piece of calculation. You need to restore those lines if your emissivity value is not equal to 1. 
 */

#include <i2cmaster.h>

int freq = 16;  //Set this value to your desired refresh frequency

int IRDATA[64];
byte CFG_LSB, CFG_MSB, PTAT_LSB, PTAT_MSB, CPIX_LSB, CPIX_MSB, PIX_LSB, PIX_MSB;
int PIX, v_th, CPIX;
float ta, to, emissivity, k_t1, k_t2;
float temperatures[64];
int count=0;
unsigned int PTAT;
int a_cp, b_cp, tgc, b_i_scale;

int a_ij[64];
int b_ij[64];
//float alpha_ij[64] = {1.591E-8, 1.736E-8, 1.736E-8, 1.620E-8, 1.783E-8, 1.818E-8, 1.992E-8, 1.748E-8, 1.864E-8, 2.056E-8, 2.132E-8, 2.033E-8, 2.097E-8, 2.324E-8, 2.388E-8, 2.161E-8, 2.155E-8, 2.394E-8, 2.353E-8, 2.068E-8, 2.353E-8, 2.633E-8, 2.708E-8, 2.394E-8, 2.499E-8, 2.778E-8, 2.731E-8, 2.580E-8, 2.539E-8, 2.796E-8, 2.871E-8, 2.598E-8, 2.586E-8, 2.801E-8, 2.830E-8, 2.633E-8, 2.609E-8, 2.894E-8, 2.924E-8, 2.633E-8, 2.464E-8, 2.778E-8, 2.894E-8, 2.673E-8, 2.475E-8, 2.737E-8, 2.796E-8, 2.679E-8, 2.394E-8, 2.708E-8, 2.714E-8, 2.644E-8, 2.347E-8, 2.563E-8, 2.493E-8, 2.388E-8, 2.179E-8, 2.440E-8, 2.504E-8, 2.295E-8, 2.033E-8, 2.283E-8, 2.295E-8, 2.155E-8};  //<-- REPLACE THIS VALUES WITH YOUR OWN!
//float v_ir_off_comp[64];  //I'm going to merge v_ir_off_comp calculation into v_ir_tgc_comp equation. It's not required anywhere else, so I'll save 256 bytes of SRAM doing this.
float v_ir_tgc_comp[64];
//float v_ir_comp[64];		//removed to save SRAM, in my case v_ir_comp == v_ir_tgc_comp



void config_MLX90620_Hz(int Hz){
  byte Hz_LSB;
  switch(Hz){
    case 0:
      Hz_LSB = B00001111;
      break;
    case 1:
      Hz_LSB = B00001110;
      break;
    case 2:
      Hz_LSB = B00001101;
      break;
    case 4:
      Hz_LSB = B00001100;
      break;
    case 8:
      Hz_LSB = B00001011;
      break;
    case 16:
      Hz_LSB = B00001010;
      break;
    case 32:
      Hz_LSB = B00001001;
      break;
    default:
      Hz_LSB = B00001110;
  }
  i2c_start_wait(0xC0);
  i2c_write(0x03);    
  i2c_write((byte)Hz_LSB-0x55); 
  i2c_write(Hz_LSB);   
  i2c_write(0x1F);  
  i2c_write(0x74);  
  i2c_stop();
}

void read_EEPROM_MLX90620(){
  byte EEPROM_DATA[256];
  i2c_start_wait(0xA0);    
  i2c_write(0x00);
  i2c_rep_start(0xA1);
  for(int i=0;i<=255;i++){
    EEPROM_DATA[i] = i2c_readAck();
  }
  i2c_stop();
  varInitialization(EEPROM_DATA);
  write_trimming_value(EEPROM_DATA[247]);
}

void write_trimming_value(byte val){
  i2c_start_wait(0xC0);
  i2c_write(0x04); 
  i2c_write((byte)val-0xAA); 
  i2c_write(val);   
  i2c_write(0x56);  
  i2c_write(0x00);  
  i2c_stop();
}

void calculate_TA(){ 
  ta = (-k_t1 + sqrt(square(k_t1) - (4 * k_t2 * (v_th - (float)PTAT))))/(2*k_t2) + 25; 	//it's much more simple now, isn't it? :)
}

void calculate_TO(){
  float v_cp_off_comp = (float) CPIX - (a_cp + (b_cp/pow(2, b_i_scale)) * (ta - 25)); //this is needed only during the to calculation, so I declare it here.
  
  for (int i=0; i<64; i++){
    v_ir_tgc_comp[i] = IRDATA[i] - (a_ij[i] + (float)(b_ij[i]/pow(2, b_i_scale)) * (ta - 25)) - (((float)tgc/32)*v_cp_off_comp);
    //v_ir_comp[i]= v_ir_tgc_comp[i] / emissivity;									//removed to save SRAM, since emissivity in my case is equal to 1. 
    //temperatures[i] = sqrt(sqrt((v_ir_comp[i]/alpha_ij[i]) + pow((ta + 273.15),4))) - 273.15;
    temperatures[i] = sqrt(sqrt((v_ir_tgc_comp[i]/alpha_ij[i]) + pow((ta + 273.15),4))) - 273.15;	//edited to work with v_ir_tgc_comp instead of v_ir_comp
  }
}


void read_IR_ALL_MLX90620(){
  i2c_start_wait(0xC0);
  i2c_write(0x02);      
  i2c_write(0x00);     
  i2c_write(0x01);       
  i2c_write(0x40);       
  i2c_rep_start(0xC1);
  for(int i=0;i<=63;i++){
    PIX_LSB = i2c_readAck(); 
    PIX_MSB = i2c_readAck(); 
    IRDATA[i] = (PIX_MSB << 8) + PIX_LSB;
  }
  i2c_stop();
}

void read_PTAT_Reg_MLX90620(){
  i2c_start_wait(0xC0);
  i2c_write(0x02);
  i2c_write(0x90);
  i2c_write(0x00);
  i2c_write(0x01);
  i2c_rep_start(0xC1);
  PTAT_LSB = i2c_readAck();
  PTAT_MSB = i2c_readAck();
  i2c_stop();
  PTAT = ((unsigned int)PTAT_MSB << 8) + PTAT_LSB;
}

void read_CPIX_Reg_MLX90620(){
  i2c_start_wait(0xC0);
  i2c_write(0x02);
  i2c_write(0x91);
  i2c_write(0x00);
  i2c_write(0x01);
  i2c_rep_start(0xC1);
  CPIX_LSB = i2c_readAck();
  CPIX_MSB = i2c_readAck();
  i2c_stop();
  CPIX = (CPIX_MSB << 8) + CPIX_LSB;
}

void read_Config_Reg_MLX90620(){
  i2c_start_wait(0xC0);
  i2c_write(0x02);
  i2c_write(0x92);
  i2c_write(0x00);
  i2c_write(0x01);
  i2c_rep_start(0xC1);
  CFG_LSB = i2c_readAck();
  CFG_MSB = i2c_readAck();
  i2c_stop();
}

void check_Config_Reg_MLX90620(){
  read_Config_Reg_MLX90620();
  if ((!CFG_MSB & 0x04) == 0x04){
    config_MLX90620_Hz(freq);
  }
}

void varInitialization(byte EEPROM_DATA[]){
  v_th = (EEPROM_DATA[219] <<8) + EEPROM_DATA[218];
  k_t1 = ((EEPROM_DATA[221] <<8) + EEPROM_DATA[220])/1024.0;
  k_t2 =((EEPROM_DATA[223] <<8) + EEPROM_DATA[222])/1048576.0;
  
  a_cp = EEPROM_DATA[212];
  if(a_cp > 127){
    a_cp = a_cp - 256;
  }
  b_cp = EEPROM_DATA[213];
  if(b_cp > 127){
    b_cp = b_cp - 256;
  }
  tgc = EEPROM_DATA[216];
  if(tgc > 127){
    tgc = tgc - 256;
  }

  b_i_scale = EEPROM_DATA[217];

  emissivity = (((unsigned int)EEPROM_DATA[229] << 8) + EEPROM_DATA[228])/32768.0;

  for(int i=0;i<=63;i++){
    a_ij[i] = EEPROM_DATA[i];
    if(a_ij[i] > 127){
      a_ij[i] = a_ij[i] - 256;
    }
    b_ij[i] = EEPROM_DATA[64+i];
    if(b_ij[i] > 127){
      b_ij[i] = b_ij[i] - 256;
    }
  }
}

void Temperatures_Serial_Transmit(){
  for(int i=0;i<=63;i++){
    Serial.println(temperatures[i]);
  }
}

void setup(){
  pinMode(13, OUTPUT);
  Serial.begin(115200);
  i2c_init(); 
  PORTC = (1 << PORTC4) | (1 << PORTC5);
  delay(5);
  read_EEPROM_MLX90620();
  config_MLX90620_Hz(freq);
}

void loop(){
  if(count ==0){		//TA refresh is slower than the pixel readings, I'll read the values and computate them not every loop. 
    read_PTAT_Reg_MLX90620();
    calculate_TA();
    check_Config_Reg_MLX90620();
  }
  count++;
  if(count >=16){
    count = 0;
  }
  read_IR_ALL_MLX90620();
  read_CPIX_Reg_MLX90620();
  calculate_TO();
  Temperatures_Serial_Transmit();
}

Cheers, Bob

I am attempting to use the MLX90602 sketch found on the Arduino Forum: MLX90620 / MLX90621 - 16X4 pixel IR thermal array - Exhibition / Gallery - Arduino Forum « Reply #2 on: October 10, 2012, 03:38:33 am »» .

Question: I have included the required library (i2cmaster.h )is included in the sketch, however I have been told that there are many versions floating around – possibly I have one that does not function correctly resulting in a compile error message (below)?

Request: Would it be possible for someone to direct me to a copy of i2cmaster.h that is known to work with this sketch?

Currently, the i2cmaster.h library I am using results in the following compile error message:

processing.app.debug.RunnerException
at processing.app.debug.Compiler.getCommandCompilerS(Compiler.java:498)
at processing.app.debug.Compiler.compileFiles(Compiler.java:201)
at processing.app.debug.Compiler.compileLibraries(Compiler.java:590)
at processing.app.debug.Compiler.compile(Compiler.java:97)
at processing.app.Sketch.build(Sketch.java:1572)
at processing.app.Sketch.build(Sketch.java:1551)
at processing.app.Editor$DefaultRunHandler.run(Editor.java:1925)
at java.lang.Thread.run(Thread.java:619)

My development environment:

Arduino:
Hardware: OSEPP Uno R3 Plus
Software: IDE 1.5.2

MLX90602:
MLX90620 16x4 IR array used on the RoBoard Module RM-G212 http://www.roboard.com/G212.html

PC:
Hardware: Lenovo ideacenter
Processor: i7-2600 @ 3.40 Ghz
RAM: 8.00 GB
System: 64 bit

Software: Windows Home Premium, with Service pack 1 installed
All current Windows7 updates installed