DIY Thermal Imaging System for under $200
One of the first things we heard when we started talking to firefighters about the potential for a heads-up display was “give us more and cheaper access to thermal imaging.” Being the tinkerers that we are, we thought we’d try to cobble something together with an Arduino and some off-the-shelf sensors. Luckily, some other folks in the Arduino community forged the way, so we didn’t have to start from scratch. Our thanks to Stephan Martin for his original write-up detailing his thermoscanner.
What we used:
- 1 - Arduino Uno
- 1 – Breadboard
- 1 – Mini Breadboard
- A Bunch of Breadboard Jumpers
- 2 – Micro Servos
- 1 – Pan and Tilt Bracket Kit
- 1 – Devantech TPA81 8×1 Thermopile Array
- 1 – Random box for mounting everything
Putting it together:
I’ll admit, this was my first Arduino project. Because of that I decided it would probably be safer to use the breadboard rather than soldering anything, that turned out to be a good idea as I didn’t get everything wired up correctly the first time around. To help you avoid the same mistakes I made I created a wiring schematic that should show you where everything plugs in.
To make the build a little easier, I mounted the mini-breadboard on the pan and tilt brackets and plugged the thermopile array into the mini-breadboard. That also made it easier to wire the thermopile to the Arduino since I didn’t have to solder or try to fashion a suitable connector. The last thing left to do is to mount the pan servo. I went for a very low-tech solution: cut a small hole in a heavy cardboard box just big enough for the servo. If you go this route as well I’d recommend using a small screw in the mounting bracket on the servo to add some stability, otherwise the servo will wiggle itself out of your mount.
Making it work:
Once you have your thermal imaging camera assembled you’ll need some software to make it all work. Before we get to the actual software now is a good time to test that you have the thermopile array wired correctly. My thanks to Jason Winningham in the Arduino Forum for posting the following code to test the TPA81:
// prototype code for interfacing Devantech TPA81 thermopile array
// http://www.robot-electronics.co.uk/htm/tpa81tech.htm
//
// Jason Winningham
// 27 june 2007
// Reposted by Tanagram
// http://spill.tanagram.com/2010/11/24/diy-thermal-imaging/
// Made available under the GNU Lesser General Public License (LGPL)
// http://www.gnu.org/licenses/lgpl.html
// November 24, 2010
#include <Wire.h>
#define TPA81ADDR (0xd0>>1)
void setup()
{
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(9600); // start serial for output
Serial.print("starting TPA81 test\n");
}
void loop()
{
byte b;
int i;
for (i=1; i<=9; i++)
{
Wire.beginTransmission(TPA81ADDR);
Wire.send(i);
Wire.endTransmission();
Wire.requestFrom(TPA81ADDR, (int) 1);
while(Wire.available() < 1)
{ ; }
b = Wire.receive(); // receive a byte as character
Serial.print(b, DEC);
Serial.print(" ");
}
Serial.println("");
delay(2000); // Sample as low as 1ms
}
Load that into your Arduino, open the Serial Monitor, and you should see a series of 9 integers returned every two seconds. Those will be the ambient temperature and the temperature from each of the eight thermopiles in the array, all in degrees Celsius.
Once you have confirmed that your thermopile array is working correctly, it’s time to install the thermoscanner software. Before you load the Arduino and Processing sketches you’ll need the AFSoftSerial library for Arduino. There are two parts to the software, the Arduino code and an additional Processing sketch that controls the thermoscanner and displays the results.
Thermoscanner Arduino Sketch:
//test by d2k2 24.09.2009
// Reposted by Tanagram
// http://spill.tanagram.com/2010/11/24/diy-thermal-imaging/
// Made available under the GNU Lesser General Public License (LGPL)
// http://www.gnu.org/licenses/lgpl.html
// November 24, 2010
#include <Servo.h>
#include <AFSoftSerial.h>
#include <Wire.h>
#define TPA81ADDR (0xd0>>1)
Servo myServoPan; // create servo object to control a servo
Servo myServoTilt; // create servo object to control a servo
AFSoftSerial mySerial = AFSoftSerial(3, 2);
char CurrentServo;
int value;
int valueA; //Storage
int valueB;
int fresh = 0;
int Read = 0;
int runVal = 0;
void setup()
{
Wire.begin(); // join i2c bus (address optional for master)
myServoPan.attach(9); // attaches the servo on pin 9 to the servo object
myServoTilt.attach(10); // attaches the servo on pin 10 to the servo object
pinMode(13, OUTPUT);
Serial.begin(57600);
Serial.println("Scanturm V0.1");
}
void loop() // run over and over again
{
get_keyboard_commands();
}
void get_keyboard_commands() {
myServoPan.write(valueA);
myServoTilt.write(valueB);
if ( Serial.available()) {
// read in a string
Read = Serial.read();
if (Read == 200){
runVal = 0;
// Serial.println("Reset");
};
switch (runVal) {
case 0:
runVal = 1;
break;
case 1:
valueA = Read;
runVal = 2;
break;
case 2:
valueB = Read;
runVal = 3;
case 3:
SendTPA();
/*
Serial.print(": ");
Serial.print(val);
Serial.println("$");
*/
//runVal = 1;
break;
}
}
}
void SendTPA(){
//Send the TPA81 Data back to the PC:
byte b;
int i;
for (i=1; i<=9; i++)
{
Wire.beginTransmission(TPA81ADDR);
Wire.send(i);
Wire.endTransmission();
Wire.requestFrom(TPA81ADDR, (int) 1);
while(Wire.available() < 1)
{ ; }
b = Wire.receive(); // receive a byte as character
Serial.print(b, DEC);
Serial.print(";");
}
Serial.println("");
}
Thermoscanner Processing Sketch:
//d2k2 24.09.2009 shows values from the TPA81
//prestage for putting the sensor on the scan turrent
// Reposted by Tanagram
// http://spill.tanagram.com/2010/11/24/diy-thermal-imaging///
Made available under the GNU Lesser General Public License (LGPL)
// http://www.gnu.org/licenses/lgpl.html
// November 24, 2010
import processing.serial.*;
Serial myPort; // Create object from Serial class
int lf = 10; // Linefeed in ASCII
String myString;
int[] val = {1,1,1,1,1,1,1,1,1};
int MaxT=100;
int MinT=20;
int pan = 40;
int tilt = 0;
String[] list = null;
int MaxT2 = 0;
int MinT2 = 255;
boolean result = false;
boolean run = false;
long time;
long lastrun = 0;
long runT;
void setup()
{
size(400, 400);
String portName = Serial.list()[1];
myPort = new Serial(this, portName, 57600);
myPort.buffer(1);
}
void draw()
{
time = millis();
runT = lastrun - time;
String myTest = "";
if ( myPort.available() > 0) { // If data is available,
myString = myPort.readStringUntil(lf);
if (myString != null)
{
list = split(myString, ';');
myTest = list[0];
if(int(myTest)>0)
{
result = true;
val[1] = int(list[8]);
val[2] = int(list[7]);
val[3] = int(list[6]);
val[4] = int(list[5]);
val[5] = int(list[4]);
val[6] = int(list[3]);
val[7] = int(list[2]);
val[8] = int(list[1]);
val[0] = int(list[0]);
//check for new max/min events
if(MaxT2min(val))
{
MinT2 = min(val);
}
//Draw another Line, right at the Pan Position
//Pan is about everywhere from 10 to 170
//so i need to update every Pan Pixel and just try it like that now
float Col = 0;
for(int i = 1;i<9; i = i+1){
Col = map(val[i],MinT,MaxT,0,255);
color drp = color(Col,Col,Col);
for(int i2 = 1; i2 < 5; i2 = i2+1){
set(pan+pan, (i*4)+75+i2+tilt+tilt+4*i-100,drp);
}
for(int i2 = 1; i2 < 5; i2 = i2+1){
set(pan+1+pan,(i*4)+75+i2+tilt+tilt+4*i-100,drp);
}
}
}
}
//background(255); // Set background to white
//Draw them 9 Pixels in a line:
/*
int Size = 45;
float Col = 0;
for (int i = 1; i < 9; i = i+1) { rect((Size*i)-Size+5, 5, Size, Size); Col = map(val[i],MinT,MaxT,0,255); fill(0,0,Col); } */ } if(millis()>lastrun)
{
if(run == true)
{
//Now i need to check if i got a result:
if(result == true)
{
//Now i need to check if im at the end of my motion:
if(pan < 150)
{
//Now i can move
pan = pan + 1;
SetServo();
lastrun = millis()+100;
}
else
{
run = false;
}
}
}
}
}
void keyPressed() {
if( key == '6'){
pan = pan+1;
SetServo();
println("Pan: " + pan);
println("Tilt: " + tilt);
}
if( key == '4'){
pan = pan-1;
SetServo();
println("Pan: " + pan);
println("Tilt: " + tilt);
}
if( key == '8'){
tilt = tilt-2;
SetServo();
println("Pan: " + pan);
println("Tilt: " + tilt);
}
if( key == '2'){
tilt = tilt+2;
SetServo();
println("Pan: " + pan);
println("Tilt: " + tilt);
}
if( key == '5'){
SetServo();
println("Pan: " + pan);
println("Tilt: " + tilt);
}
if( key == '1'){
pan = 40;
SetServo();
println("Pan: " + pan);
println("Tilt: " + tilt);
}
if( key == '3'){
run = true;
}
}
void SetServo(){
result = false;
myPort.write(200); //init
myPort.write(tilt); //tilt
myPort.write(pan); //pan
delay(100);
myPort.write(80); //trigger read
}
Both sketches come from Stephan Martin’s write-up of his thermoscanner project. After the sketch is loaded up to your Arduino you should be able to run the Processing sketch and start your first thermal imaging scan. To control your thermal imaging scanner use the number keys on your keyboard:
- 1 – Reset pan servo to 40°
- 2 – Increase tilt servo by 2°
- 3 - Run the scanner
- 4 - Reduce pan servo by 1°
- 5 - unused
- 6 - Increase pan servo by 1°
- 7 - unused
- 8 - Increase tilt servo by 2°
- 9 - unused
To run a complete scan requires two passes, and takes these steps:
- Make sure the Processing sketch is running
- Press 1 and wait for the pan servo to reset to 40°
- Press 3 and wait until the pan servo completes it’s rotation
- Press 1 to reset the pan servo to the start position again
- Press 8 to increase the tilt servo by 2°
- Press 3 to start the next pan rotation
After that you should have a complete scan without any gaps. If you can control the servos with the keyboard but the scan doesn’t run when you press 3 double check your wiring for the thermopile array. If the Processing sketch doesn’t receive any input from the thermopile array it won’t execute the scan.
The output
Here is what the output should look like.
But what does this all mean?
Quite honestly, we’re not entirely sure yet. But we have a much better understanding of how thermal imaging works, and that means we’ll be better able to determine if thermal imaging can be a realistic piece of what is going to go into a heads-up display for firefighters.
Disclaimer and Licensing
While this project is functional it is prone to “seizures” and could use improvement. The source code and plans above are available to all being made available to all under the GNU Lesser General Public License (LGPL). If you use this please maintain the references to Tanagram and the original authors of the code above. Also, if you make improvements we’d love to know about it. You can either post a comment, link to this post, or send an email to contact [at-symbol] tanagram.com. Have fun!
Image Gallery
- Thermal Imaging Scan
- DIY Thermal Imaging Scanner
- Thermal Imaging Camera Schematic
- Pan/Tilt Schematic
Posted by Timothy Mills on November 24, 2010







18 Comments on DIY Thermal Imaging System for under $200
By DIY Thermal Imaging « adafruit industries blog on December 2, 2010 at 3:50 pm
[...] DIY Thermal Imaging, Tim writes – One of the first things we heard when we started talking to firefighters about the potential for a heads-up display was “give us more and cheaper access to thermal imaging.” Being the tinkerers that we are, we thought we’d try to cobble something together with an Arduino and some off-the-shelf sensors. Luckily, some other folks in the Arduino community forged the way, so we didn’t have to start from scratch. Our thanks to Stephan Martin for his original write-up detailing his thermoscanner. Filed under: arduino — by adafruit, posted December 2, 2010 at 4:50 pm Comments (0) [...]
By S Huntley on December 2, 2010 at 5:12 pm
It’s a “head-up” display. “Heads up” is what you say to people when you’ve hit a ball their way. A head-up display is a display you can see with your head up.
By macegr on December 2, 2010 at 5:18 pm
Hahah…please find an external power source for your servos. It’ll work WAY better if you aren’t (1) powering it from the same 5V source as the arduino (2) powering it from USB.
By JC on December 3, 2010 at 11:30 am
I think it would be a lot simpler to use a webcam and remove the low-pass filter of the sensor, and placing a visible light filter (e.g. the dark window of an IR remote for near IR) in front of the lens.
That way you turn the camera to an IR camera, and get thermal imaging.
Something like this: http://www.hoagieshouse.com/IR/
By madsci on December 3, 2010 at 8:08 pm
JC – It would be cool if you could do that, but webcams are only receptive to shortwave IR, whereas “seeing heat” requires capturing longwave IR. That’s why thermal imaging setups are so expensive.
By earlgreytea on December 3, 2010 at 8:38 pm
adding on to madsci’s comment above –
webcams use silicon, which have a cutoff at 1.2um.
the devantech thermopile manual states that its spectral response is from 2.2um – 22um (pretty much determined by what they use as their IR absorber material).
By W1N9Zr0 on December 3, 2010 at 9:35 pm
The servo might be twitching because you’re sending the commands to it too fast, my futaba s3003 does that too. Adding more time between the pulses fixed it for me.
By DIY thermal imaging for under $200 | Products & Tech News on December 4, 2010 at 1:10 am
[...] love the detailed build log for a el-cheapo thermal imaging project. One of the first things we heard when we started talking to firefighters about the potential for a [...]
By DIY thermal imaging for under $200 - machine quotidienne on December 4, 2010 at 3:14 am
[...] love the detailed build log for a el-cheapo thermal imaging project. One of the first things we heard when we started talking to firefighters about the potential for a [...]
By LilBoonjis » Blog Archive » DIY thermal imaging for under $200 on December 4, 2010 at 9:26 pm
[...] like the detailed build log for a el-cheapo thermal imaging project. One of the first things we heard when we started talking to firefighters about the potential for a [...]
By DIY thermal imaging for under $200 | dev.SquareCows.com on December 4, 2010 at 11:01 pm
[...] love the detailed build log for a el-cheapo thermal imaging project. One of the first things we heard when we started talking to firefighters about the potential for a [...]
By Egon MacGyver on December 5, 2010 at 12:44 pm
Anyone have any ideas on how to make it more handheld and portable than stationary?
By salec on December 6, 2010 at 4:46 am
For firefighters It would be better to make their heads the scanners actuators and to read the position (direction where IR sensors “look”) through means of gyroscopes or acceleration sensors. It would make it faster, more flexible and more intuitive.
Perhaps even better would be to avoid visualization and convert temperature readings from two “eyes” into stereo audio signal, then let them train using it efficiently in dark room exercises. If viper snakes can use similar low-resolution biological temperature sensors to hunt their prey, then humans can be trained to use artificial IR sensors to find warm bodies in zero visibility too.
By Timothy Mills on December 6, 2010 at 9:34 am
@S Huntly – We could argue semantics all day long. Head-up and heads-up can be used interchangeably, at least according to all of the research and literature we’ve read. But I agree, “heads up” without a hyphen is what you yell when you’ve hit a ball towards someone.
@macegr – Thanks for the feedback on the servo performance. I’ll give it a shot. This was my first foray into this kind of project, so I’m not above admitting that I really had no idea what I was doing.
@salec – I was thinking the same thing about mounting this sensor to a firefighter’s helmet. I was also thinking that if you combine the scans from more than one firefighter in a close proximity you could get a little higher resolution. We hadn’t made the connection to how vipers see. Thanks for the lead and we’ll check it out.
By The Amp Hour #20 — Military Electronics and Our First WOTWs! | The Amp Hour on December 6, 2010 at 10:18 pm
[...] Hi-Res stuff is expensive difficult! We’re impressed by Jeri’s new TSA hack but Chris realized how much he expects Hi-res for images. Same for a new project using an Arduino for an IR camera. [...]
By salec on December 7, 2010 at 5:12 pm
Well, vipers don’t actually see IR, they sense it.
http://charmcitycurrent.com/bmorescientific/2010/03/18/heat-sensing-vipers/
For us humans, haptic or auditory interface to sensors would probably be the optimal fit.
By BaccaTrading on December 12, 2010 at 10:38 am
Thanks for the information! I have been into this for a while. Your post was really helpful!
By Electronics-Lab.com Blog » Blog Archive » DIY Thermal Imaging System for under $200 on December 16, 2010 at 11:20 am
[...] Thermal Imaging System for under $200 - [Link] Tags: Arduino, Imaging, thermal Filed in Sensor | 1 views No Comments [...]
Write a Comment on DIY Thermal Imaging System for under $200
Comments on DIY Thermal Imaging System for under $200 are now closed.