Go Down

Topic: Arduino and MLX90620 16X4 pixel IR thermal array (Read 38994 times) previous topic - next topic

plataham367

Sorry, there were no changes required, I just had it wired wrong. :smiley-red:  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 http://forum.arduino.cc/index.php?topic=126244.0

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" http://osepp.com/products/arduino-compatible-boards/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.

Code: [Select]
/*
* 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

Cheers, Bob

I am attempting to use the MLX90602 sketch found on the Arduino Forum:  http://forum.arduino.cc/index.php?topic=126244.0 « 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

Cheers, Bob

ngy78

Hi Bob,

I was having the same problem. I found this page:

http://bildr.org/2011/02/mlx90614-arduino/

There is a link to a version of i2cmaster that is compatible with the forum sketch.

Neil

Hi Neil,

Thanks for the information.  As it turns out I found this last week and didn't think to post what I found back on the Forum.  How is you project going?

thanks again,

Bob
Cheers, Bob

Pobana

I'm interested in this thermal sensor of yours.
I'm looking to detect a change in temperature of a mass of air in the sky (a thermal that provides lift for a glider).  This would be several hundred yards away.  Would you device recognize this?
John

Laughing-gravy

It wouldn't work.
The air in the thermal is transparent, so it neither absorbs nor radiates any light. The thermal might be warmer, but since it is not generating any infrared it cannot be seen by an infrared imager.

rickcjmac

I am trying to implement the code provided (mega thanks for sharing your work!) but the code freezes on the command
Code: [Select]
i2c_start_wait(MLX90620_EEPROM_WRITE);
I am using the I2CMaster library from the MLX90614 forum, which works for that sensor, because the link in this thread is dead now. Has anyone had a similar experience?

I am using an Arduino Uno with an MLX90620 and the code from this forum exactly as provided.

Thank you so much for your help!

Richard

rickcjmac

I was confusing the bottom view for the top view in the data sheet, thus my wiring was backwards. It is working now!  XD Super big thanks again for contributing your work!

Richard

turkoale

hello everyone. very interesting this thread is very helpful. I am making an application with the MLX90620 with opencv in linux, I am testing the example of nseidle that is very well documented. The problem that some erroneous pixels and negative values ??pull. It can be a noise problem? I have to use a lens to filter interference??
These are the calcuation alpha data and some temperature readings:

Code: [Select]
alpha0: 33030
alpha0_scale: 41
delta_alpha_scale: 34
emissitivity: 1.00000
Copy and paste the following block of text into the MLX90620_Example sketch:

float alpha_ij[64] = {
  1.51949E-8, 1.64173E-8, 1.58352E-8, 1.50203E-8, 1.75814E-8, 1.88038E-8, 1.86292E-8, 1.72322E-8,
  2.00262E-8, 2.07829E-8, 2.06082E-8, 1.89784E-8, 2.20052E-8, 2.29948E-8, 2.28201E-8, 2.10157E-8,
  2.38097E-8, 2.43917E-8, 2.43917E-8, 2.28201E-8, 2.52066E-8, 2.56141E-8, 2.49738E-8, 2.28201E-8,
  2.59633E-8, 2.59633E-8, 2.56141E-8, 2.31694E-8, 2.53813E-8, 2.66036E-8, 2.61962E-8, 2.31694E-8,
  2.57887E-8, 2.66036E-8, 2.61962E-8, 2.29948E-8, 2.61962E-8, 2.66036E-8, 2.61962E-8, 2.25873E-8,
  2.63708E-8, 2.59633E-8, 2.57887E-8, 2.24127E-8, 2.61962E-8, 2.57887E-8, 2.49738E-8, 2.15978E-8,
  2.49738E-8, 2.57887E-8, 2.47992E-8, 2.09575E-8, 2.43917E-8, 2.47992E-8, 2.38097E-8, 1.99680E-8,
  2.34022E-8, 2.38097E-8, 2.25873E-8, 1.92113E-8, 2.17724E-8, 2.21798E-8, 2.13649E-8, 1.77561E-8,
};


45.05, 49.02, 24.12, 17.72, -32.80, 8.95, nan, 33.00, 51.56, 53.42, 52.29, 51.43, 53.97, 53.44, 58.38, 53.99,
38.36, 53.60, 53.60, 52.93, 54.30, 55.94, 54.60, 52.07, 54.93, 55.67, 55.19, 56.01, 56.62, 56.56, 56.10, 56.01,
54.90, 55.81, 56.82, 55.12, 56.10, 56.21, 55.74, 54.89, 56.51, 56.77, 56.73, 57.04, 56.82, 58.18, 56.14, 55.85,
57.65, 57.82, 55.63, 56.99, 57.52, 57.24, 58.49, 58.47, 55.67, 57.78, 56.67, 55.94, 56.43, 56.55, 55.41, 57.92,

47.81, 50.26, 22.41, 23.29, -25.35, 14.70, nan, 33.70, 52.55, 54.82, 52.76, 52.99, 55.28, 54.28, 55.90, 55.82,
40.73, 55.58, 55.97, 55.90, 56.58, 57.78, 55.76, 53.79, 57.13, 56.40, 56.31, 54.77, 56.62, 57.27, 55.74, 55.18,
56.38, 56.53, 57.90, 56.78, 56.82, 58.68, 56.10, 57.84, 57.58, 57.49, 55.62, 57.04, 57.18, 57.09, 56.14, 56.73,
57.65, 58.18, 58.67, 57.88, 56.75, 57.99, 58.49, 56.59, 56.49, 57.39, 55.83, 56.93, 55.55, 57.82, 56.30, 56.86,

46.44, 47.76, 24.96, 17.72, -34.39, 10.63, nan, 33.00, 52.55, 54.35, 51.80, 50.90, 53.97, 53.86, 55.90, 54.91,
37.88, 54.00, 54.00, 52.93, 54.68, 55.19, 53.44, 53.36, 55.30, 55.67, 54.82, 54.77, 55.88, 56.56, 55.74, 54.77,
55.64, 55.45, 56.10, 55.12, 56.46, 56.56, 56.46, 56.59, 56.51, 55.30, 56.36, 55.77, 57.18, 56.36, 56.52, 56.29,
57.28, 56.36, 56.02, 56.54, 55.58, 55.71, 56.52, 56.59, 56.49, 56.99, 57.50, 56.44, 56.43, 57.40, 56.30, 56.86,


in same pixels the value is negative, and other is nan. Are broken these pixels on my sensor? :~
thanks for helping :)

Ro0000

Hi everyone,

I've been wanting to create a thermal camera of some kind for years now, and now that I'm at Uni I have the lab space and all the other things to finally be able to create it. I've looked through this forum, and there are some truly wonderful ideas around! In particular, this MLX90620 and Arduino project is amazing!

My aim is to make a thermal camera that displays the image in real time, with colour representation (red hot, blue cold). I've seen the EVB90620 with the MLX90620 sensor on board working on a laptop, displaying the image in real time, so I know it's possible. If the code in the above posts is run, will it display an image, or display temperature readings for each pixel? If the latter, I'm sure making a GUI wouldn't be too difficult (he says...).

Oh, and I looked into the Panasonic Grid-EYE sensor (AMG8851), but unless you're from the 'states, they _WILL NOT_ deliver it - they think you'll use it to create a nuke or something :/

Thanks guys,

Roland

Ro0000

Hi again,

I've downloaded the code that is shown at the bottom of this forum -  Reference: Arduino and MLX90620 16X4 pixel IR thermal array - Reply #11 on: December 25, 2012, 03:35:30 pm http://forum.arduino.cc/index.php?topic=126244.0, and I have also downloaded Mr. Peter Fluery's i2cmaster library, as the link to the other i2c library described below does not work anymore. Also, I've connected the circuit properly to my Arduino Uno:

SDA - 4.7k pull-up to 3.3v line,
SCL - 4.7k pull-up to 3.3v line also,
VDD - straight to 3.3v,
VSS - Ground (GND)

The circuit should work, however, when I measure the SDA & SCL lines on an oscilloscope, I just get a flat line on both inputs. How can this be? When I take away the SCL line, and measure that, the oscilloscope springs to life, and shows the clock and data waves correctly, but when returned, both lines go flat again.

Does anybody know what could be the problem here, or am I just doing something incredibly stupid?

Cheers,

Ro

Ro0000

Oh no, my regulator blew somewhere along the line, so there was less than 2.5v being supplied to VDD, so it couldn't have worked. After replacing this (and the other components for good measure), the MLX90620 communicates effectively with the Uno, so I can get on to the meatier part of the project!

francesco80

Hi all!

I'm interested in using this sensor for outdoor fire detection.
Do you think it can works? What abt the maximum distance for a reliable detection of this kind of event?
Thankyou in advance for your replies!

Ro0000

Hi francesco80!

I managed to get my hands on the evaluation kit that Melexis provides for this sensor, and we were testing to see how far we could see a human face indoors - not quite as hot as a fire I'll admit, but just to see what kind of range we could get. Our maximum range was about 7 meters, but we could barely see any red on the visual at that distance. Bare in mind that was just a human face, so the heat of the fire would no doubt be visible at a much longer range.

This is probably the best sensor for this kind of application, as the Panasonic grid-EYE can only be bought if you are a citizen of the US, and the TPA 81 is strictly mono-chromatic, as well as only being an 8x1 pixel array.

Hope that helps!

Ro

Go Up