Artık Wio Terminal ve Grove – Infrared Temperature Sensor Array (AMG8833) ile uygun fiyatlı bir termal kamera yapabilirsiniz. Tüm bileşenlerin toplam maliyeti 80 dolardan azdır ve kolayca düşük maliyetli bir FLIR™ gibi bir termal görüntüleme kamerası edinebilirsiniz.

Kızılötesi nedir ve nasıl “görülür” ve kullanılır
Öncelikle, kızılötesine hızlıca bir göz atalım. Kızılötesi (IR), veya kızılötesi ışık, dalga boyları görünür ışıkla karşılaştırıldığında daha uzun olan elektromanyetik radyasyondur (EMR), bu da onu genel koşullarda insan gözüne görünmez kılar. Oda sıcaklığına yakın nesneler tarafından yayılan çoğu termal radyasyon kızılötesidir. (Kaynak: Wikipedia)
İnsan gözleri, görünür ışıktan daha uzun dalga boylarına sahip olduğu için kızılötesi ışığı “göremez”, ancak bir termal kızılötesi kamera basit bir çözüm sunabilir. Kızılötesi enerjiyi algılayabilir ve bunu farklı renklerle bir resme dönüştürerek algılanan nesnelerin sıcaklığını gösterebilir.
Aşağıda IR termal görüntüleme kamerasının bazı tipik uygulamaları bulunmaktadır:
- Tıbbi bakımda temassız sıcaklık ölçümleri
- Yangın önleme sistemleri
- İzinsiz giriş/Hareket algılama
- Varlık algılama / Kişi konumlandırma
- Akıllı evler için algılama elemanları
Kendi IR Termal Görüntüleme Kameranızı Yapın
Biraz geriye gidecek olursak, Grove – Infrared Temperature Sensor Array (AMG8833) çözünürlüğü yalnızca 8 x 8 (64 Piksel) olup, bazı durumlarda yeterli olabilir. Bu nedenle, kodda daha iyi bir gösterim için 70 x 70 (4900 Piksel) genişletmek için Doğrusal Enterpolasyon kullanılır.
Bu demo, Kris Kasprzak’ın videosundan ilham alınarak hazırlanmıştır. Wio Terminal ve Grove – Infrared Temperature Sensor Array (AMG8833) ile uyumlu hale getirmek için birkaç değişiklik yapılmıştır. Çoğu grafik, genel performansı ve daha hızlı kare hızını artırmak için önce TFT LCD Sprite’larına çizilmektedir. Ayrıca ekranın ortasında bir nişangah ekledik ve nişangah üzerindeki sıcaklığı gösteriyoruz. Bu arada, Wio Terminal üzerindeki sağ düğmeye tıklayarak ekrandaki referans çizgisini açıp kapatabilirsiniz.


Donanım Gereksinimleri
- Wio Terminal
- Grove – Infrared Temperature Sensor Array (AMG8833)
- Wio Terminal Pil Şasisi
- Grove – Wrapper (Grove’unuzu sabitlemek ve demoyu güvenli tutmak için kullanılır)
Not: Bu yazıda kullanılan Wio Terminal ve pil şasisi, test için demo amaçlıdır, bu nedenle görünümü sağdaki resimlerden biraz farklıdır. Örneğin, Wio Terminal’in düğmesi mavi olmalı ve pil şasisinin dış kabuğu beyaz olmalıdır.

Yazılım Gereksinimleri
- LCD ekran Kütüphanesini
Seeed_Arduino_LCDyükleyin, daha fazla bilgi için Wio Terminal LCD sayfasını ziyaret edin. - Seeed_AMG8833 depolama alanını ziyaret edin ve tüm repo’yu yerel sürücünüze indirin.
- Artık Seeed_AMG8833 kütüphanesini Arduino IDE’ye yükleyebilirsiniz. Arduino IDE’yi açın ve
sketch->Include Library->Add .ZIP Libraryseçeneğine tıklayın ve indirdiğinizSeeed_AMG8833dosyasını seçin.
- Artık Seeed_AMG8833 kütüphanesini Arduino IDE’ye yükleyebilirsiniz. Arduino IDE’yi açın ve
Kurulum Talimatları
- Grove – Infrared Temperature Sensor Array (AMG8833) cihazını Wio Terminal’in Grove I2C Arayüzüne takın.
- Tam kodu buradan indirin veya bu sayfanın sonundaki kodu kopyalayın.
- Kodu yükleyin.
Artık Wio Terminal’i açabilir ve yeni IR termal görüntüleme kameranızı deneyebilirsiniz!


Github & Forum’umuzda Daha Fazlasını Keşfedin
Wio Terminal hakkında daha fazla bilgi mi edinmek istiyorsunuz? Yepyeni Forum’umuz yayınlandı ve tartışmamıza katılmanızı bekliyor! Sorularınızı veya Wio Terminal ile ilgili herhangi bir teknik sorunu forumumuzda paylaşmaktan çekinmeyin. Seslerinizi duymak için sabırsızlanıyoruz ve tüm önerilere açığız!
Eğer Wio Terminal’in ne olduğunu bilmeyenler varsa, birlikte bir göz atalım!
Wio Terminal’in Kısa Tanıtımı
Wio Terminal fiziksel dünya ile I/O oluşturmak için basit ve küçük bir cihazdır. Realtek RTL8720DN tarafından desteklenen kablosuz bağlantıya sahip ATSAMD51 tabanlı bir geliştirme kartıdır.
Tam Kod
Not: Bu IR Termal Görüntüleme Kamerası’nın performansını ve kare hızını artırmak için Wio Terminal CPU Hızını 200MHz’e yükseltebilirsiniz. Seçin Tools -> CPU Speed -> 200MHz(Overclock)

/*
Bu program, bir 8 x 8 termal kamera okuma dizisini büyütmek içindir
10 kat büyütecek ve 240 x 320 boyutunda gösterecektir
enterpolasyon lineerdir ve "yeterince iyi"dir, çünkü ekran 5-6-5 renk paletine sahiptir
Nihai toplam dizi, yalnızca iç noktaların 70 x 70'lik bir dizisidir
Revizyonlar
1.0 Kasprzak İlk kod
1.1 Anson(Seeed Studio) Grove - Kızılötesi Sensör(AMG8833) ile Wio Terminal'e uyarlanmıştır
*/
#include <Seeed_AMG8833_driver.h>
#include <TFT_eSPI.h> // Grafik kütüphanesini dahil et (bu, sprite fonksiyonlarını içerir)
TFT_eSPI tft = TFT_eSPI();
TFT_eSprite Display = TFT_eSprite(&tft); // "tft" nesnesine işaretçi ile "img" Sprite nesnesi oluştur
// işaretçi, pushSprite() tarafından TFT'ye itmek için kullanılır
unsigned long CurTime;
uint16_t TheColor;
// bazı başlangıç renkleriyle başla
uint16_t MinTemp = 25;
uint16_t MaxTemp = 35;
// enterpolasyonlu renkler için değişkenler
byte red, green, blue;
// satır/sütun enterpolasyonu için değişkenler
byte i, j, k, row, col, incr;
float intPoint, val, a, b, c, d, ii;
byte aLow, aHigh;
// bir ekran "pikselinin" boyutu
byte BoxWidth = 3;
byte BoxHeight = 3;
int x, y;
char buf[20];
// ekran ızgarasını açıp kapatmak için değişken
int ShowGrid = -1;
// 8 x 8 ölçülen pikseller için dizi
float pixels[64];
// enterpolasyonlu dizi için dizi
float HDTemp[80][80];
// kamera nesnesini oluştur
AMG8833 ThermalSensor;
// Izgarayı açıp kapat
void toggleGrid() {
ShowGrid = ShowGrid *-1;
Display.fillRect(15, 15, 210, 210, TFT_BLACK);
yield();
}
void setup() {
Serial.begin(115200);
// ekranı başlat ve arka planı siyah yap
tft.begin();
tft.fillScreen(TFT_BLACK);
// Izgarayı açıp kapatmak için kesme
pinMode(WIO_KEY_A, INPUT);
attachInterrupt(digitalPinToInterrupt(WIO_KEY_A), toggleGrid, FALLING);
// ekran döndürmesini ayarla (gerekirse 0'a değiştirmeniz gerekebilir)
tft.setRotation(3);
// bir açılış ekranı göster
tft.setCursor(20, 20);
tft.setTextColor(TFT_BLUE, TFT_BLACK);
tft.print("Termal ");
tft.setTextColor(TFT_RED, TFT_BLACK);
tft.print("Kamera");
// sensörün açılmasına izin ver
bool status = ThermalSensor.init();
delay(100);
if (!status) {
Serial.print("AMG8833 başlatılamadı");
}
// başlangıç testi için kamerayı oku
ThermalSensor.read_pixel_temperature(pixels);
// durumu kontrol et ve sonuçları göster
if (pixels[0] < 0) {
while (1) {
tft.setCursor(20, 40);
tft.setTextColor(TFT_RED, TFT_BLACK);
tft.print("Okuma: BAŞARISIZ");
delay(500);
}
}
else {
tft.setCursor(20, 40);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
tft.print("Okuma: TAMAM");
delay(2000);
}
tft.fillScreen(TFT_BLACK);
Display.createSprite(TFT_HEIGHT, TFT_WIDTH);
Display.fillSprite(TFT_BLACK);
// renk enterpolasyon rutinleri için kesme noktalarını al
// bu fonksiyon, sıcaklık ölçeği değiştiğinde çağrılır
Getabcd();
// sensörlerin maksimum ve minimum değerleriyle eşleşen bir efsane çiz
DrawLegend();
}
void loop() {
CurTime = millis();
// sıcaklık alanı için büyük beyaz bir kenar çiz
Display.fillRect(10, 10, 220, 220, TFT_WHITE);
// sensörü oku
ThermalSensor.read_pixel_temperature(pixels);
// şimdi 8 x 8 sensör dizisine sahibiz
// daha büyük bir ekran elde etmek için enterpolasyon yap
// önce 8 sensör pikseli arasında 70 sütun noktasını enterpole et
for (row = 0; row < 8; row ++) {
for (col = 0; col < 70; col ++) {
// ilk dizi noktasını al, sonra bir sonraki
// ayrıca sonraki satırlar için 8 artırmanız gerekiyor
aLow = col / 10 + (row * 8);
aHigh = (col / 10) + 1 + (row * 8);
// her 10 sütun için enterpolasyon miktarını al
// burada, performansı yüksek tutmak için basit lineer enterpolasyon yapıyoruz ve
// ekran 5-6-5 renk paleti olduğu için şatafatlı enterpolasyon düşük renk derinliğinde kaybolur
intPoint = (( pixels[aHigh] - pixels[aLow] ) / 10.0 );
// her sütunu artırmak için ne kadar artırılacağını belirle (temelde 0-9)
incr = col % 10;
// enterpolasyonlu değeri bul
val = (intPoint * incr ) + pixels[aLow];
// 70 x 70 dizisine kaydet
// çünkü ekran dışarıya işaret ediyor, satır verilerini transpoze etmek için satırı ters çevir
HDTemp[ (7 - row) * 10]
= val;
}
}
// şimdi 70 sütun ile ham veriye sahibiz
// her 70 sütunu enterpole et
// Arduino'yu unutun..hız olarak yeterince hızlı değil..Teensy > 72 mhz ile başlangıç noktasıdır
for (col = 0; col < 70; col ++) {
for (row = 0; row < 70; row ++) {
// ilk dizi noktasını al, sonra bir sonraki
// ayrıca sonraki sütunlar için 8 artırmanız gerekiyor
aLow = (row / 10 ) * 10;
aHigh = aLow + 10;
// her 10 sütun için enterpolasyon miktarını al
// burada, performansı yüksek tutmak için basit lineer enterpolasyon yapıyoruz ve
// ekran 5-6-5 renk paleti olduğu için şatafatlı enterpolasyon düşük renk derinliğinde kaybolur
intPoint = (( HDTemp[aHigh]
- HDTemp[aLow]
) / 10.0 );
// her sütunu artırmak için ne kadar artırılacağını belirle (temelde 0-9)
incr = row % 10;
// enterpolasyonlu değeri bul
val = (intPoint * incr ) + HDTemp[aLow]
;
// 70 x 70 dizisine kaydet
HDTemp[ row ]
= val;
}
}
// 70 x 70 dizisini göster
DisplayGradient();
// Ekranın ortasında bir nişangah
Display.drawCircle(115, 115, 5, TFT_WHITE);
Display.drawFastVLine(115, 105, 20, TFT_WHITE);
Display.drawFastHLine(105, 115, 20, TFT_WHITE);
// Sprite'ı ekrana it
Display.pushSprite(0, 0);
// Ekranın ortasında sıcaklığı göster
tft.setRotation(3);
tft.setTextColor(TFT_WHITE);
tft.drawFloat(HDTemp[35][35], 2, 90, 20);
// Kare hızını yazdırmak için bu satırı açın
Serial.print("Kare hızı: "); Serial.println(1/(0.001*(millis() - CurTime)));
}
// sonuçları görüntülemek için fonksiyon
void DisplayGradient() {
tft.setRotation(4);
// 70 satır boyunca geç
for (row = 0; row < 70; row ++) {
// titreme olmayan bir ızgara çizmenin hızlı yolu--her 10 pikseli 2x2 yapmak, 3x3 yerine
// ızgaradan sonra çizim yapmak çok fazla titreme yapar
if (ShowGrid < 0) {
BoxWidth = 3;
}
else {
if ((row % 10 == 9) ) {
BoxWidth = 2;
}
else {
BoxWidth = 3;
}
}
// sonra her 70 sütun boyunca geç
for (col = 0; col < 70; col++) {
// titreme olmayan bir ızgara çizmenin hızlı yolu--her 10 pikseli 2x2 yapmak, 3x3 yerine
if (ShowGrid < 0) {
BoxHeight = 3;
}
else {
if ( (col % 10 == 9)) {
BoxHeight = 2;
}
else {
BoxHeight = 3;
}
}
// nihayet her 70 x 70 noktayı çizebiliriz, enterpolasyonlu rengi almak için çağrıya dikkat edin
Display.fillRect((row * 3) + 15, (col * 3) + 15, BoxWidth, BoxHeight, GetColor(HDTemp[row]
));
}
}
}
// hızlı ama etkili renk enterpolasyon rutinim
uint16_t GetColor(float val) {
/*
değeri geçin ve R G B'yi hesaplayın
bunu yapmanın birkaç yayımlanmış yolu var, ben temelde R G B'yi grafikleştirdim ve basit lineer denklemler geliştirdim
tekrar 5-6-5 renkli bir ekran, R G B renk hesaplaması için doğru sıcaklık gerektirmeyecektir
denklemler
http://web-tech.ga-usa.com/2012/05/creating-a-custom-hot-to-cold-temperature-color-gradient-for-use-with-rrdtool/index.html adresine dayanmaktadır
*/
red = constrain(255.0 / (c - b) * val - ((b * 255.0) / (c - b)), 0, 255);
if ((val > MinTemp) & (val < a)) {
green = constrain(255.0 / (a - MinTemp) * val - (255.0 * MinTemp) / (a - MinTemp), 0, 255);
}
else if ((val >= a) & (val <= c)) {
green = 255;
}
else if (val > c) {
green = constrain(255.0 / (c - d) * val - (d * 255.0) / (c - d), 0, 255);
}
else if ((val > d) | (val < a)) {
green = 0;
}
if (val <= b) {
blue = constrain(255.0 / (a - b) * val - (255.0 * b) / (a - b), 0, 255);
}
else if ((val > b) & (val <= d)) {
blue = 0;
}
else if (val > d) {
blue = constrain(240.0 / (MaxTemp - d) * val - (d * 240.0) / (MaxTemp - d), 0, 240);
}
// ekranın renk eşleme fonksiyonunu kullanarak 5-6-5 renk paletini elde et (R=5 bit, G=6 bit, B=5 bit)
return Display.color565(red, green, blue);
}
// sıcaklık ile RGB grafiğindeki kesme noktalarını almak için fonksiyon
void Getabcd() {
a = MinTemp + (MaxTemp - MinTemp) * 0.2121;
b = MinTemp + (MaxTemp - MinTemp) * 0.3182;
c = MinTemp + (MaxTemp - MinTemp) * 0.4242;
d = MinTemp + (MaxTemp - MinTemp) * 0.8182;
}
// bir efsane çizmek için fonksiyon
void DrawLegend() {
// maksimum ve minimum metin ile renk efsanesi
j = 0;
float inc = (MaxTemp - MinTemp ) / 160.0;
for (ii = MinTemp; ii < MaxTemp; ii += inc) {
tft.drawFastHLine(260, 200 - j++, 30, GetColor(ii));
}
tft.setTextSize(2);
tft.setCursor(245, 20);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
sprintf(buf, "%2d/%2d", MaxTemp, (int) (MaxTemp * 1.8) + 32);
tft.print(buf);
tft.setTextSize(2);
tft.setCursor(245, 210);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
sprintf(buf, "%2d/%2d", MinTemp, (int) (MinTemp * 1.8) + 32);
tft.print(buf);
}
// KODUN SONU
