"Low cost" PIR sensor with 64 elements, great for robotic stuff

May 11, 2008
22,557
1,471
126
The AMG8831 is a neat sensor. It is a IR sensor that measures directly temperature from 64 IR elements in 8x8 array. and has an I2C bus.
It is based on MEMS technology, so out of the box it is pretty accurate. You have to read out the array of pixels and convert the value to degrees celcius. In a sense it is a tiny IR camera with a very low resolution. But good enough to detect movement and with the right software, blob detection is possible. There is already some examples on the internet. And examples for the arduino exist as well. It is an expensive sensor. It cost me around 40 euro. But it is well spend.
Because this sensor has some very neat properties, it is difficult to buy. Expect a back ground check and it can even be that you are refused as a potential customer.


I thought it would be neat when i build my talking fish to give it some rudimentary eye sight. For my future little droid it would also be handy, giving it another sensor to not only detect movement but also the temperature. With this sensor alone, you can give your robot part of the intelligence of a pit viper. This snake has thermal vision and also watches for movement to prevent it from biting warm stones instead of prey.

I would love to reverse-engineer one of these flying orbs (youtube video) one day and attach some sensors to it so that it would follow me around.

https://www.youtube.com/watch?v=pF0uLnMoQZA

First i am going to make a tiny FLIR camera to get to know this neat little sensor. I already have my little nokia 6100LCD, the plan is to read out the values, do some false color imaging conversion and create a false color image together with some temperature reading and averaging of the center 4 pixels.

Right now i am at the early stage of getting it all to work. And my trusty Saleae logic analyzer is still worth any penny of it.

Some pictures :

img2.jpg~original


I have some SMD components on the other side.
img3.jpg~original


It seems i have communication, the AMG8831 is responding :
img1.jpg~original
 
Last edited:
May 11, 2008
22,557
1,471
126
As you can see, the Saleae logic analyzer can also interpret the I2C protocols.
Very handy for debugging.

img4.jpg~original
 

Red Squirrel

No Lifer
May 24, 2003
70,592
13,807
126
www.anyf.ca
Fun. Been wanting to play around with i2c. I have some i2c humidity/temp sensors and ADCs to play with from my last Digikey order. More stuff I can accidentally blow up. :p
 
May 11, 2008
22,557
1,471
126
Fun. Been wanting to play around with i2c. I have some i2c humidity/temp sensors and ADCs to play with from my last Digikey order. More stuff I can accidentally blow up. :p

You do not want to blow up this sensor, it is quite expensive. I payed 39 euro for it.
I am still working on it to get a FLIR camera.

https://en.wikipedia.org/wiki/Forward_looking_infrared

I hope that today i can get some decent programming done to show a few pictures. And after that i can continue with the movement algorithms.
I still need to add safety code with time outs. Now when the sensor would not respond or there is no sensor attached, the code will hang forever. Bit amateuristic.
And i need to clean up the FLIR display code.
 
May 11, 2008
22,557
1,471
126
Now i can make use of my preliminary work i did with the 6100LCD. ^_^.

Here are some pictures of giving the temperature in three ways :

My end screen when disabling the FLIR :

img5.jpg


Measurements :

img6.jpg


Temperature of the center of the sensor.
The highest measured temperature.
And the lowest measured temperature.

The accuracy is 0.25C. It can be there will be some offset that needs to be calibrated away. I have not done that yet.

The FLIR screen (The dark blue square) is disabled because it was buggy and i had a revelation on how to properly do it.

I have to get the min and max temperature. Scale that difference up to about a 256 values. After that, all i need to do is to write a function for the microcontroller to map the highest temperature to the brightest color and the lowest temperature to the lowest tint of the color blue (colors in brightness mapped from 0 to 255). And every temperature value in between is rounded off to a color between the min and max value(A value between 0 and 255). After that, select for each pixel one of these values. Then jump to a 256 entry color table to choose the color. :)

The color table i am still working on.
I am going to write a program in Microsoft Visual studio C that generates a text file with c code ( a constant array), with the color map. That i can just copy/paste into my microcontroller IDE and compile it.

This sensor is great for keeping track of your pet as well.

Edit :

The pictures in this thread are stored at photobucket.
I noticed photobucket is not always able to present all pictures. Reloading helps when pictures are missing.
 
Last edited:

Red Squirrel

No Lifer
May 24, 2003
70,592
13,807
126
www.anyf.ca
Wow that's pretty neat, so it basically moves the sensor around to map out the area? That's something that has actually kinda crossed my mind as a project when I get better at electronics. Even bare IR camera sensors are expensive. (100's of bucks)
 
May 11, 2008
22,557
1,471
126
Wow that's pretty neat, so it basically moves the sensor around to map out the area? That's something that has actually kinda crossed my mind as a project when I get better at electronics. Even bare IR camera sensors are expensive. (100's of bucks)

No, it is a grid of 64 (i think pyro electric) static elements. 64 pixels.
These pixels can be read out as a digital value that is a multiple of 0.25C.
It has a lens that focuses Long wave Infrared radiation. It has a limitation how sharp it sees but you can have fun with it. You could say it is near sighted. With a distance of less than a meter, it can see pretty good.

Basically, you read out the 64 12 bit digital values (as 128 bytes).
I have a c function that determines the lowest temperature and the highest temperature from that array. Then i scale it up to the amount of colors.
Fixing the highest temperature to the brightest color and the lowest temperature to the darkest color.

I am now working on a function which has 48 colors but it can easily be upscaled.
I am first going to eat and then continue programming. :)
Hopefully i can show a picture later today.
 
May 11, 2008
22,557
1,471
126
Well, i get some better rudimentary picture out of it :

I limited it now to 48 colors.
Not yet quite working as i would like it but it does something :
When i move my hand around, i can see a white blob moving around on the screen. ^_^.
I have it set at a refresh rate of 10fps.
I still need to figure out why there are black spots in between.
I have also not yet set the amg8831 to perform a moving average.
I have some settings to test.
But the main thing works, it can detect movement.

Unfortunately, photobucket is becoming really slow with loading.

Picture 1, no hand, just open space :
img7.jpg~original



Picture 2 ,one hand above it :
img8.jpg~original



here is a example demo code for a flir :

Code:
// RGB 12bit color : RRRR GGGG BBBB
// temporary colortable
const uint16_t    g_falsecolortable[]={
0x001,
0x002,
0x003,
0x004,
0x005,
0x006,
0x007,
0x008,
0x009,
0x00A,
0x00B,
0x00C,
0x00D,
0x00E,
0x00F,
0x10F,
0x20F,
0x30F,
0x40F,
0x50F,
0x60F,
0x70F,
0x80F,
0x90F,
0xA0F,
0xB0F,
0xC0F,
0xD0F,
0xE0F,
0xF0F,
0xF1F,
0xF2F,
0xF3F,
0xF4F,
0xF5F,
0xF6F,
0xF7F,
0xF8F,
0xF9F,
0xFAF,
0xFBF,
0xFCF,
0xFDF,
0xFEF,
0xFFF,
};


Code:
void ExecuteFlirModus(void)
{
	
	uint16_t				temperature_buffer[64];
	uint16_t				raw_value_buffer[64];
	uint8_t					timer_id;
	flir_t					flir_data;
		
	SetSpiTo_Lcd();
	SetupFLirScreenOnLcd();			

	timer_id = (uint8_t)RequestTimer(100);

	while(GetPinValue(BUTTON1))	
	{
		if((Timer(timer_id))==0)
		{
			ReadArrayAmg8831(raw_value_buffer);
			Amg8831ConvertRawToTemperature(raw_value_buffer,temperature_buffer);
			UpdateFlirTemperature(temperature_buffer,&flir_data);
			UpdateFlirScreen(temperature_buffer,&flir_data);
			

			ReloadTimer(timer_id, 100);
		}
	}		

	ReleaseTimer(timer_id);
	FLirEndScreen();
	setSpiTo_Sd();
}

Code:
void UpdateFlirScreen(uint16_t *pointer, flir_t *ps_flir)
{
	lcd6100_t					displayobject; //display object
	uint32_t					range;		
	uint32_t					colorstep;
	uint32_t					colorindex;
	uint32_t					x,y;
	uint32_t					index;
	uint32_t					delta_temp;
	uint16_t					pixel_color_array[64];
	

	range = ps_flir->high_temp - ps_flir->low_temp;	
	//PrintString("range 1 = %d.\r\n>",range);
	//range = range * 10;
	//PrintString("range 2 = %d.\r\n>",range);
	
	colorstep = range / AMOUNTOFCOLORS; //
	//PrintString("csz  = %d.\r\n>",colorstep);
	
	// Convert temperatures to a color.
	for(index=0;index < 64;index++)
	{
		//PrintString("index = %d.\r\n>",index);
		delta_temp = *pointer - ps_flir->low_temp;
		//PrintString("dtemp 1= %d.\r\n>",delta_temp);
		colorindex = delta_temp / colorstep;
		//PrintString("color index = %d.\r\n>",colorindex);
		
		if(colorindex > 47) 
		{
			colorindex = 47;
		}
		
		pixel_color_array[index] = g_falsecolortable[colorindex];
		pointer++;
	}
	
	index = 0;
	for(y=0; y < 8;y++) 
	{
		displayobject.ystart = 10 + (y << 3);
		displayobject.yend = 17 + (y << 3);		
		
		for(x=0;x < 8;x++)
		{
			displayobject.color = pixel_color_array[index];
			displayobject.xstart = 30 + (x << 3);
			displayobject.xend =  37 + (x << 3);			

			LcdFillWindow(&displayobject);
			//PrintString("index = %d.\r\n>",index);
			index++;
		}
	}
	
}

Code:
void UpdateFlirTemperature(uint16_t *pointer, flir_t *ps_flir)
{
	lcd6100_t					displayobject; //display object
	uint32_t					index;		
	uint16_t					low_temp;
	uint16_t					high_temp;
	uint16_t					spot_temp;
	uint16_t					*ptr;
	uint8_t						t_array[8];
	int8_t						ch_array[8];
	
	


	// Get lowest temperature 
	ptr = pointer;
	low_temp = 1 << 15;
	for(index=0;index < 64;index++)
	{
		if(*ptr < low_temp)
		{
			low_temp = *ptr;
		}
		ptr++;
	}
	//PrintString("low temp value = %d.\r\n>",(uint32_t)low_temp);
	ps_flir->low_temp = low_temp;


	// Get highest temperature 	
	ptr = pointer;
	high_temp = 0;
	for(index=0;index < 64;index++)
	{
		if(*ptr > high_temp)
		{
			high_temp = *ptr;
		}
		ptr++;
	}
	//PrintString("high temp value = %d.\r\n>",(uint32_t)high_temp);
	ps_flir->high_temp = high_temp;

	//Get center spot temperature 
	ptr = pointer + 27;
	spot_temp = *ptr;
	ptr++;
	spot_temp += *ptr;
	ptr = pointer + 35;
	spot_temp += *ptr;
	ptr++;
	spot_temp += *ptr;

	spot_temp = spot_temp >> 2;
	//PrintString("spot temp value = %d.\r\n>",(uint32_t)spot_temp);
	ps_flir->spot_temp = spot_temp;
	
	MemSet(ch_array,0,8);
	MemSet(t_array,0,8);
	u32toa((uint32_t)spot_temp,t_array);
	FormatStringFlirTemperature(t_array,ch_array);
	
	displayobject.color = YELLOW;	
	displayobject.xstart = 64;
	displayobject.ystart = 96;
	displayobject.bcolor = BLACK;	
	displayobject.fontstyle = FONT_SMALL;
	LcdWriteString(&displayobject, ch_array);

	MemSet(ch_array,0,8);
	MemSet(t_array,0,8);
	u32toa((uint32_t)high_temp,t_array);
	FormatStringFlirTemperature(t_array,ch_array);

	displayobject.color = YELLOW;	
	displayobject.xstart = 64;
	displayobject.ystart = 106;
	displayobject.bcolor = BLACK;	
	displayobject.fontstyle = FONT_SMALL;
	LcdWriteString(&displayobject, ch_array);

	MemSet(ch_array,0,8);
	MemSet(t_array,0,8);
	u32toa((uint32_t)low_temp,t_array);
	FormatStringFlirTemperature(t_array,ch_array);
	
	displayobject.color = YELLOW;	
	displayobject.xstart = 64;
	displayobject.ystart = 116;
	displayobject.bcolor = BLACK;	
	displayobject.fontstyle = FONT_SMALL;
	LcdWriteString(&displayobject, ch_array);
}

Code:
void FormatStringFlirTemperature(uint8_t * src, int8_t *dst)
{
	*dst = *src;
	dst++;
	src++;
	*dst = *src;
	dst++;
	src++;
  *dst='.';
	dst++;
	*dst = *src;
	dst++;
	src++;
	*dst = *src;
	dst++;
	*dst='C';
}
 
Last edited:

sm625

Diamond Member
May 6, 2011
8,172
137
106
Why is g_falsecolortable so nonlinear? Most of the table entries are either 0 or F for red with very few grades inbetween.
 
May 11, 2008
22,557
1,471
126
I am still experimenting with the color table :
To prevent errors, i let the preprocessor calculate the size of the falsecolortable array :

My previous table was better for determining colors :
Oh well, i can try it for now.

Code:
const uint16_t    g_falsecolortable[]={
0x001,
0x002,
0x003,
0x004,
0x005,
0x006,
0x007,
0x008,
0x009,
0x00A,
0x00B,
0x00C,
0x00D,
0x00E,
0x00F,
0x100,
0x200,
0x300,
0x400,
0x500,
0x600,
0x700,
0x800,
0x900,
0xA00,
0xB00,
0xC00,
0xD00,
0xE00,
0xF00,
0x010,
0x020,
0x030,
0x040,
0x050,
0x060,
0x070,
0x080,
0x090,
0x0A0,
0x0B0,
0x0C0,
0x0D0,
0x0E0,
0x0F0,
0x110,
0x220,
0x330,
0x440,
0x550,
0x660,
0x770,
0x880,
0x990,
0xAA0,
0xBB0,
0xCC0,
0xDD0,
0xEE0,
0xFF0,
}; 
#define	COLORBYTESUSED sizeof(g_falsecolortable)
#define AMOUNTOFCOLORS COLORBYTESUSED / sizeof(uint16_t)
#define AMOUNTOFCOLORSMINUSONE AMOUNTOFCOLORS-1

My at the moment tiny flir struct. ( Will grow when i am going to determine movement) :)
Code:
// Flir struct.
typedef struct s_flir
{
	uint16_t					low_temp;
	uint16_t					high_temp;
	uint16_t					spot_temp;
}flir_t;

Updated flir display function :

Code:
void UpdateFlirScreen(uint16_t *pointer, flir_t *ps_flir)
{
	lcd6100_t					displayobject; //display object
	uint32_t					range;		
	uint32_t					colorstep;
	uint32_t					colorindex;
	uint32_t					x,y;
	uint32_t					index;
	uint32_t					delta_temp;
	uint16_t					pixel_color_array[64];
	

	range = ps_flir->high_temp - ps_flir->low_temp;	
	
	colorstep = range / AMOUNTOFCOLORS; //
	
	// Convert temperatures to a color.
	for(index=0;index < 64;index++)
	{
		delta_temp = *pointer - ps_flir->low_temp;

		colorindex = delta_temp / colorstep;
		
		if(colorindex > AMOUNTOFCOLORS) 
		{
			colorindex = AMOUNTOFCOLORSMINUSONE;
		}
		
		pixel_color_array[index] = g_falsecolortable[colorindex];
		pointer++;
	}
	
	index = 0;
	for(y=0; y < 8;y++) 
	{
		displayobject.ystart = 10 + (y << 3);
		displayobject.yend = 17 + (y << 3);		
		
		for(x=0;x < 8;x++)
		{
			displayobject.color = pixel_color_array[index];
			displayobject.xstart = 34 + (x << 3);
			displayobject.xend =  41 + (x << 3);			

			LcdFillWindow(&displayobject);
			//PrintString("index = %d.\r\n>",index);
			index++;
		}
	}
	
}



For more information about the 6100 lcd :
http://forums.anandtech.com/showthread.php?t=2456524
 
May 11, 2008
22,557
1,471
126
I have finally a decent false color table with 90 colors.
I have been messing around with a rgb color picker to see what would be the best way to emulate a real FLIR camera with a false color image. Properly done, as mentioned by Schmide, i should be calculating a HSL and HSV value and converting that to a color. But i found that a bit to much for a 64 pixel FLIR. So i made a color table that is sort of ok.

Code:
// false colortable
// RRRR GGGG BBBB

const uint16_t    g_falsecolortable[]={
0x001,
0x002,
0x003,
0x004,
0x005,
0x006,
0x007,
0x008,
0x009,
0x00A,
0x00B,
0x00C,
0x00D,
0x00E,
0x00F,

0x01F,
0x02F,
0x03F,
0x04F,
0x05F,
0x06F,
0x07F,
0x08E,
0x09D,
0x0AC,
0x0BB,
0x0CA,
0x0D9,
0x0E8,
0x0F7,

0x1F6,
0x2F5,
0x3F4,
0x4F3,
0x5F2,
0x6F1,
0x7F0,

0x7E0,
0x7D0,
0x7C0,
0x7B0,
0x8B0,
0x9B0,
0xAB0,
0xBB0,

0xBA0,
0xB90,
0xB80,
0xB70,
0xB60,
0xB50,
0xB40,
0xB30,
0xB20,
0xB10,
0xB00,

0xC00,
0xD00,
0xE00,
0xF00,

0xF10,
0xF20,
0xF30,
0xF40,
0xF50,
0xF60,
0xF70,
0xF80,
0xF90,
0xFA0,
0xFB0,
0xFC0,
0xFD0,
0xFE0,
0xFF0,

0xFF1,
0xFF2,
0xFF3,
0xFF4,
0xFF5,
0xFF6,
0xFF7,
0xFF8,
0xFF9,
0xFFA,
0xFFB,
0xFFC,
0xFFD,
0xFFE,
0xFFF,
}; 


#define	COLORBYTESUSED sizeof(g_falsecolortable)
#define AMOUNTOFCOLORS COLORBYTESUSED / sizeof(uint16_t)
#define AMOUNTOFCOLORSMINUSONE AMOUNTOFCOLORS-1

Now i can start working on the automatic range function because it still does not work properly.
 
May 11, 2008
22,557
1,471
126
Well, i do now some better averaging so the thermal noise is less present.

And i can amplify the signal in the image with a simple trick of changing the colorstep between colorstep and colorstep/2.

Two pictures.

I am holding my left hand down with my index finger raised down in the top right corner.

Amplification off :
img9.jpg~original


Amplification on :
img11.jpg~original