Thermal camera on an Arduino Uno
An AMG8833 Grid-EYE sees an 8x8 picture of temperatures and an ST7735 paints it in a thermal palette, hottest pixel underneath. The whole build, an Arduino Uno and 2 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.
Teaching? Assign it to your class in one click.
Intermediate About 30 minutes to build and run. Runs in your browser. Free, and no account needed.
The parts retail for about $77. On Mokxi they're free.
What you'll learn
- Reading a thermal sensor over I2C
- Mapping temperature to a color palette
- Driving a color TFT over SPI
- Drawing only what changed
- Finding the maximum in an array
- Difficulty: Intermediate
- Time: About 30 minutes
- Board: Arduino Uno R3
- Parts: 4
How it works
An AMG8833 Grid-EYE sensor reports 64 temperatures, an 8 by 8 picture, ten times a second. The sketch reads them over I2C and paints each one as a 16 by 16 pixel square on a 1.8 inch ST7735 screen.
The color comes from a thermal palette: blue at 20 C, through purple and red to orange, and yellow at 36 C and above. The hottest reading is printed under the picture. To save time, the sketch only repaints a square when its color changes.
Parts list
4 parts, plus the jumper wires. They retail for about $77; on Mokxi they're free.
- 1 × Arduino Uno R3In Starter Kit, Claw Machine Kit, Vending Machine Kit.
- 1 × Full-size breadboard
- 1 × Thermal camera, AMG8833
- 1 × TFT display, 1.8 inch ST7735
Wiring table
Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.
| Part and pin | Connects to |
|---|---|
| Thermal camera, AMG8833 pin SCL | Arduino Uno R3 pin SCL |
| Thermal camera, AMG8833 pin SDA | Arduino Uno R3 pin SDA |
| TFT display, 1.8 inch ST7735 pin SCK | Arduino Uno R3 pin 13 |
| TFT display, 1.8 inch ST7735 pin SDA | Arduino Uno R3 pin 11 |
| TFT display, 1.8 inch ST7735 pin CS | Arduino Uno R3 pin 10 |
| TFT display, 1.8 inch ST7735 pin A0 | Arduino Uno R3 pin 9 |
| TFT display, 1.8 inch ST7735 pin RESET | Arduino Uno R3 pin 8 |
| Thermal camera, AMG8833 pin VIN | Arduino Uno R3 pin 5V |
| TFT display, 1.8 inch ST7735 pin VCC | Arduino Uno R3 pin 5V |
| TFT display, 1.8 inch ST7735 pin LED | Arduino Uno R3 pin 5V |
| Thermal camera, AMG8833 pin GND | Arduino Uno R3 pin GND |
| TFT display, 1.8 inch ST7735 pin GND | Arduino Uno R3 pin GND |
The code
The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.
// Thermal camera: an AMG8833 Grid-EYE and an ST7735 color screen.
//
// SDA, SCL the AMG8833 (address 0x69), VIN and GND from the rails
// pins 10, 9, 8 the screen's CS, A0 (DC) and RESET
// pins 11, 13 the screen's SDA (MOSI) and SCK; VCC and LED from the rails
//
// The Grid-EYE gives sixty-four temperatures ten times a second. Each one is
// painted as a 16x16 square, eight across and eight down, in a thermal
// palette from blue at 20 C through red to yellow at 36 C and over, so a
// hand stands out against a room. The hottest pixel's temperature is written
// under the picture.
//
// The screen is driven a pixel at a time over the pins, so a frame takes a
// while; the sketch only repaints the squares whose color changed.
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <Adafruit_AMG88xx.h>
Adafruit_ST7735 tft(10, 9, 8);
Adafruit_AMG88xx amg;
float pixels[AMG88xx_PIXEL_ARRAY_SIZE];
uint16_t shown[AMG88xx_PIXEL_ARRAY_SIZE];
int lastHot = -1000;
// 20 C to 36 C onto blue, purple, red, orange, yellow.
uint16_t colorFor(float c) {
int t = (int)((c - 20.0) * 16.0); // 0..256 over 16 degrees
if (t < 0) t = 0;
if (t > 255) t = 255;
uint8_t r, g, b;
if (t < 64) {
r = (uint8_t)(t * 2); g = 0; b = (uint8_t)(128 + t);
} else if (t < 128) {
r = (uint8_t)(128 + (t - 64) * 2); g = 0; b = (uint8_t)(192 - (t - 64) * 3);
} else if (t < 192) {
r = 255; g = (uint8_t)((t - 128) * 2); b = 0;
} else {
r = 255; g = (uint8_t)(128 + (t - 192) * 2); b = (uint8_t)((t - 192) * 3);
}
return tft.color565(r, g, b);
}
void setup() {
Serial.begin(115200);
Serial.println("Mokxi Arduino Uno: thermal camera");
tft.initR(INITR_BLACKTAB);
tft.fillScreen(ST77XX_BLACK);
if (!amg.begin()) {
Serial.println("no AMG8833: check SDA, SCL and power");
while (1) delay(10);
}
for (int i = 0; i < AMG88xx_PIXEL_ARRAY_SIZE; i++) shown[i] = 0xFFFF;
delay(100);
}
void loop() {
amg.readPixels(pixels);
float hottest = pixels[0];
int where = 0;
for (int i = 0; i < AMG88xx_PIXEL_ARRAY_SIZE; i++) {
if (pixels[i] > hottest) {
hottest = pixels[i];
where = i;
}
uint16_t color = colorFor(pixels[i]);
if (color != shown[i]) {
shown[i] = color;
tft.fillRect((i % 8) * 16, (i / 8) * 16, 16, 16, color);
}
}
int hot = (int)(hottest * 10.0 + 0.5);
if (hot != lastHot) {
lastHot = hot;
tft.fillRect(0, 132, 128, 16, ST77XX_BLACK);
tft.setCursor(4, 134);
tft.setTextColor(ST77XX_WHITE);
tft.setTextSize(1);
tft.print("hottest ");
tft.print(hot / 10);
tft.print('.');
tft.print(hot % 10);
tft.print(" C");
Serial.print("hottest ");
Serial.print(hot / 10);
Serial.print('.');
Serial.print(hot % 10);
Serial.print(" C at row ");
Serial.print(where / 8);
Serial.print(", column ");
Serial.println(where % 8);
}
delay(100);
}
Code walkthrough
The key functions of the sketch, and what each one does.
colorFor sketch.ino
Takes a temperature and scales 20 C to 36 C onto 0 to 255, clamping outside that range. Then it picks red, green and blue values from four bands to make blue, purple, red, orange and yellow.
// 20 C to 36 C onto blue, purple, red, orange, yellow.
uint16_t colorFor(float c) {
int t = (int)((c - 20.0) * 16.0); // 0..256 over 16 degrees
if (t < 0) t = 0;
if (t > 255) t = 255;
uint8_t r, g, b;
if (t < 64) {
r = (uint8_t)(t * 2); g = 0; b = (uint8_t)(128 + t);
} else if (t < 128) {
r = (uint8_t)(128 + (t - 64) * 2); g = 0; b = (uint8_t)(192 - (t - 64) * 3);
} else if (t < 192) {
r = 255; g = (uint8_t)((t - 128) * 2); b = 0;
} else {
r = 255; g = (uint8_t)(128 + (t - 192) * 2); b = (uint8_t)((t - 192) * 3);
}
return tft.color565(r, g, b);
}setup sketch.ino
Starts the screen and clears it to black, then looks for the sensor. If it is missing it prints a message and stops. It then sets every remembered color to a value that forces a first full paint.
void setup() {
Serial.begin(115200);
Serial.println("Mokxi Arduino Uno: thermal camera");
tft.initR(INITR_BLACKTAB);
tft.fillScreen(ST77XX_BLACK);
if (!amg.begin()) {
Serial.println("no AMG8833: check SDA, SCL and power");
while (1) delay(10);
}
for (int i = 0; i < AMG88xx_PIXEL_ARRAY_SIZE; i++) shown[i] = 0xFFFF;
delay(100);
}loop sketch.ino
Reads the 64 pixels, finds the hottest and repaints each square whose color changed. When the hottest value, rounded to a tenth, changes it redraws the label and prints its row and column.
void loop() {
amg.readPixels(pixels);
float hottest = pixels[0];
int where = 0;
for (int i = 0; i < AMG88xx_PIXEL_ARRAY_SIZE; i++) {
if (pixels[i] > hottest) {
hottest = pixels[i];
where = i;
}
uint16_t color = colorFor(pixels[i]);
if (color != shown[i]) {
shown[i] = color;
tft.fillRect((i % 8) * 16, (i / 8) * 16, 16, 16, color);
}
}
int hot = (int)(hottest * 10.0 + 0.5);
if (hot != lastHot) {
lastHot = hot;
tft.fillRect(0, 132, 128, 16, ST77XX_BLACK);
tft.setCursor(4, 134);
tft.setTextColor(ST77XX_WHITE);
tft.setTextSize(1);
tft.print("hottest ");
tft.print(hot / 10);
tft.print('.');
tft.print(hot % 10);
tft.print(" C");
Serial.print("hottest ");
// ... 10 more lines in the editorTroubleshooting
The usual mistakes with this circuit, and the fix for each.
- The sketch says no AMG8833 This project
Check SDA and SCL between the Uno and the sensor, and its VIN and GND. - The screen stays black This project
Check CS on pin 10, A0 on pin 9, RESET on pin 8, SCK on pin 13, SDA on pin 11, and that LED and VCC are on 5V. - Everything is one color This project
The palette only covers 20 C to 36 C. A room outside that range clamps to the end colors. - The sensor is not found on I2C. The address is 0x69 by default, or 0x68 when the AD_SELECT pin is tied to ground, and many scanners miss the other. Thermal camera
Scan the bus and use the address you find. Connect SDA and SCL to the right pins with pull-ups to 3.3 V, and join the grounds. - The image is blocky and slow, or the values look odd. It has only 8 by 8 pixels at up to 10 frames per second, and the reading is in 0.25 C steps. Thermal camera
Read the 64 pixels over I2C at no more than 10 Hz. Interpolate to smooth the picture. Power it from 3.3 V, since the chip is a 3.3 V part. - The screen is blank or white. TFT display
Check all the SPI wires: SCK, MOSI, CS, DC and RST, plus power and the backlight pin. Many modules need the LED pin tied to 3.3 V, with a resistor on some. Use the right library init. - Colors are wrong, or the picture is shifted with a noisy edge. TFT display
Pick the tab color your library asks for, such as INITR_BLACKTAB or GREENTAB, until the picture is clean. Swap red and blue if the colors are reversed. Rotation changes the offset. - Upload fails or nothing runs after wiring pins 0 and 1 to a module. Arduino Uno R3
Pins 0 and 1 are the USB serial port. Move the module to other pins, or unplug it while uploading. Also check the right board is selected.
Change it and keep it
Open it in the editor, change the circuit or the code, and keep your version in a free account.