Pages: [1]   Go Down
Author Topic: Melexis Infrared Thermometer Speed  (Read 575 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 4
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Recently, I purchased an Arduino and some other various assorted parts from Sparkfun, including a Melexis Infrared Thermometer ( http://www.sparkfun.com/products/9570 )

I wired up the unit according to these instructions, using this arduino code (posted below): http://bildr.org/2011/02/mlx90614-arduino/

After a little bit of farting around, I managed to get some usable data from the sensor into Processing.
My dilemma is that the temperature data only comes in a few times a second.

What can I do to squeeze more data samples out of this nifty little sensor in a given timeframe?

I'm a newbie to electronics, but I'm pretty familiar with programming.  Here's the arduino code:
Code:
#include <i2cmaster.h>


void setup(){
    Serial.begin(19200);
    Serial.println("Setup...");
    
    i2c_init(); //Initialise the i2c bus
    PORTC = (1 << PORTC4) | (1 << PORTC5);//enable pullups
}

void loop(){
    int dev = 0x5A<<1;
    int data_low = 0;
    int data_high = 0;
    int pec = 0;
    
    i2c_start_wait(dev+I2C_WRITE);
    i2c_write(0x07);
    
    // read
    i2c_rep_start(dev+I2C_READ);
    data_low = i2c_readAck(); //Read 1 byte and then send ack
    data_high = i2c_readAck(); //Read 1 byte and then send ack
    pec = i2c_readNak();
    i2c_stop();
    
    //This converts high and low bytes together and processes temperature, MSB is a error bit and is ignored for temps
    double tempFactor = 0.02; // 0.02 degrees per LSB (measurement resolution of the MLX90614)
    double tempData = 0x0000; // zero out the data
    int frac; // data past the decimal point
    
    // This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
    tempData = (double)(((data_high & 0x007F) << 8) + data_low);
    tempData = (tempData * tempFactor)-0.01;
    
    float celcius = tempData - 273.15;
    float fahrenheit = (celcius*1.8) + 32;

//    Serial.print("Celcius: ");
//    Serial.println(celcius);

    Serial.println(fahrenheit);
//    Serial.println(fahrenheit);

//    delay(10); // wait a second before printing again
}

And here's the processing script:

Code:
import processing.serial.*;

Serial myPort;        // The serial port
int xPos = 0;         // horizontal position of the graph
int yPos = 0;         // vertical position of the graph
String nString = "lol";
float pinByte = 0;
void setup () {
  // set the window size:
  size(100, 100);        
strokeWeight(1);
  // List all the available serial ports
  println(Serial.list());
  // I know that the first port in the serial list on my mac
  // is always my  Arduino, so I open Serial.list()[0].
  // Open whatever port is the one you're using.
  myPort = new Serial(this, Serial.list()[1], 19200);
  // don't generate a serialEvent() unless you get a newline character:
  myPort.bufferUntil('\n');
  // set inital background:
  background(0);
}
void draw () {
  // everything happens in the serialEvent()
}

void serialEvent (Serial myPort) {
  // get the ASCII string:
  String inString = myPort.readStringUntil('\n');

  if ((inString != null)&&(inString.equals(nString)!=true)){
    nString = inString;
    // trim off any whitespace:
    inString = trim(inString);
    // convert to an int and map to the screen height:
    float inByte = float(inString);
    print(inByte+"\n");
    inByte = map(inByte, 79, 90, 0, 255);

    // draw the line:
    stroke(inByte);
    line(xPos, yPos, xPos, yPos);
//    background(inByte);
    // at the edge of the screen, go back to the beginning:
    if (xPos >= width) {
      xPos = 0;
      yPos++;
    }
    else {
      // increment the horizontal position:
      xPos++;
      pinByte = inByte;
    }
  }
}

Basically, the arduino sends the temperature in Fahrenheit through a serial cable at 19200 baud (increasing it does nothing) to the processing application which takes the temperature (ignoring duplicates) and graphs them in a scan-line pattern across the domain.  Unfortunately, this could take a while at the current speed of transmissions.

I heard that this thermometer could do PWM?  How would I be able to take advantage of that for speed?

If the arduino can't extract the data fast enough alone, would this be more suitable?
http://www.sparkfun.com/products/9813

Alternatively, can I have the arduino recieve data really fast from the sensor, store it in a buffer, and then dump the data later?

Thanks.
« Last Edit: June 17, 2011, 09:50:16 am by zalo » Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 170
Posts: 12465
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


what you can do is rewrite to something like:

Code:
setup()
{
  ...
  start_sensor();
 
}
loop()
{
  wait until ready;
  t = fetch temperature();
  start_sensor();
  write to processing
}
 
This (re)starts the sensor directly after you read it.
While the sensor do its work you process the new arrived data, so when you're finished the sensor is allready halfway a new value.

Hope this helps
Rob

Please use the # button for code (that gives the scrollable window).
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 170
Posts: 12465
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

To optimize you could try code below:
* removed the floating point math => long math

Code:
unsigned long tempData = word(data_high, data_low) & 0x7FFF;

tempData *= 100;  // to keep it in int range 
tempData *= 2;     // tempFactor
tempData -= 1;
long celsius = tempData - 27315;
long fahrenheit = celsius * 18 + 320;

Serial.print(celsius / 100, DEC);
Serial.print(".");
Serial.println(celsius % 100, DEC);

Serial.print(fahrenheit / 100, DEC);
Serial.print(".");
Serial.println(fahrenheit % 100, DEC);

you might compact it to a oneliner:

Code:
long celsius = (word(data_high, data_low) & 0x7FFF) * 200L - 27316;
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

0
Offline Offline
Shannon Member
****
Karma: 161
Posts: 10445
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Well I've looked at the datasheet for 10 minutes now and still can't find what maximum sample rate the sensor supports - badly written datasheet... PWM might give more readings a second, but its hard to know without more study (I note it has a 17bit ADC on board - these low power sensor ADCs tend to be slow.

But a general observation:  its a temperature sensor, its inherently low bandwidth, you probably won't get any useful extra information by reading its output any faster.
Logged

[ I won't respond to messages, use the forum please ]

New Jersey
Offline Offline
Faraday Member
**
Karma: 49
Posts: 3420
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

What is your project doing that 'a few times a second' isn't sufficient for?
Logged

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 239
Posts: 24371
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
What is your project doing that 'a few times a second' isn't sufficient for
I'm guessing "trying to build a thermal imager".
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

0
Offline Offline
Newbie
*
Karma: 0
Posts: 4
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks robtillart and MarkT for your help

I implemented the code from your second post, robtillart, but it had a negligible effect on sample rate.  smiley-sad

I had a little more trouble reading into the first post you made.  Considering that I am new to microcontroller-
programming, and I filched the code straight from the bildr post, I was unable to discern which lines set it and reset it.
A pointer or two in that direction would be greatly appreciated smiley

MarkT, thanks for taking the time to look through the datasheet.  I too am frustrated at the lack of some of the information.  The Sparkfun eval board said it could update at 38400bps, though, that's gibberish to me. smiley-sad

AWOL, you are right on the money.  What makes the project I'm attempting slightly different from the usual servo-scanner imager, is that I've figured out a way to do ultra-high speed scanning using a motor, a servo, and some polar coordinate processing.  Similar in principle to this:

Though, my implementation would have an adjustable angle on the mirror.
This thermometer here is the only thing is vaguely unknown territory.   smiley-sad

Thanks for all of your help so far!
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 170
Posts: 12465
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


OK I will give it a try based upon your code (and my integer math variant)

(code not compiled or tested)
Code:
#include <i2cmaster.h>

void setup()
{
    Serial.begin(115200);
    Serial.println("Setup...");
   
    i2c_init(); //Initialise the i2c bus
    PORTC = (1 << PORTC4) | (1 << PORTC5);//enable pullups

   // START CONVERSION
    i2c_start_wait(dev+I2C_WRITE);
    i2c_write(0x07);
}

int dev = 0x5A<<1;
int data_low = 0;
int data_high = 0;
int pec = 0;

void loop()
{
    // READ VALUE
    i2c_rep_start(dev+I2C_READ);
    data_low = i2c_readAck(); //Read 1 byte and then send ack
    data_high = i2c_readAck(); //Read 1 byte and then send ack
    pec = i2c_readNak();
    i2c_stop();

    // REQUEST NEW VALUE
    i2c_start_wait(dev+I2C_WRITE);
    i2c_write(0x07);
   
    // PROCESS "PREVIOUS"
    long celsius = (word(data_high, data_low) & 0x7FFF) * 200L - 27316;
    long fahrenheit = (celsius * 18 + 32000)/10; 

    Serial.print(celsius / 100, DEC);
    Serial.print(".");
    Serial.println(celsius % 100, DEC);

    Serial.print(fahrenheit / 100, DEC);
    Serial.print(".");
    Serial.println(fahrenheit % 100, DEC);
}
As you follow the code you will see that before processing a new request is send, and instead of waiting for the answer we use the time to process the prev value.

Is it so more clear?
Rob
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Global Moderator
UK
Offline Offline
Brattain Member
*****
Karma: 239
Posts: 24371
I don't think you connected the grounds, Dave.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Serial.println(fahrenheit % 100, DEC);
Won't that make 3.5 and 3.05 print the same value?
Logged

"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 170
Posts: 12465
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Definitely true (as I said not tested),  - the purpose of the sketch is to show the reversal of the START and READ cycle, not to be 100% robust
Think the OP can fix smiley-wink




Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

0
Offline Offline
Newbie
*
Karma: 0
Posts: 4
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Alright, I see how it works, and it worked after a little bit of tinkering.

It seems the arduino is processing the temperatures fast enough on it's own though...

It's sending data at an extremely high speed, but it often reports duplicate values.  

This is the raw data graphed (between 81 degrees and 91 degrees Fahrenheit) using rob's latest code:

The code increments the graph 1 pixel to the right every time it receives a sample.  The stair-step pattern is caused by duplicate samples.
On the plus side, it filled up extremely fast, so I know the arduino is capable of sending them that fast.
It gets faster with the increased baud rate.

This is what the graph looks like when filtered to ignore the duplicate samples:

It took almost a minute to acquire this much data (the fluctuations are me moving my hand around).
It fills up at the same speed, whether its 300 baud or 115200 baud, when I filter the duplicates (less duplicates at 300).

EDIT: Oh, and to make the code work, I had to add:
Code:
int dev = 0x5A<<1;
before the first time it was called in the setup(), And a second time after the setup before the loop()
« Last Edit: June 17, 2011, 06:05:34 pm by zalo » Logged

Pages: [1]   Go Up
Jump to: