Skip to content
樹莓派:紅外線熱像儀
📆2020-04-19 | 📂Embedded

看到火車站架設熱像儀監控旅客們的體溫,然而並非每個車站都能設置如此昂貴的儀器,出於好奇也想做個低成本的來看看,雖然解析度與精確度都比不上昂貴的精密儀器,但在近距離下能做到快速、自動偵測體溫的話,比起讓站務人員逐一量測後進站,這應該堪用且有效率多了。


AMG8833 Intro

於是我買來了Adafruit AMG8833模組,這模組上頭裝著Panasonic所生產的紅外線陣列感測器。 Datasheet:Panasonic IR Array Sensor Grid-EYE

參考Adafruit官網的技術參數說明:

  1. 感測器為8x8紅外線陣列
  2. 溫度感測區間為攝氏0度~攝氏80度(精度為正負2.5度)
  3. 人體最大感測距離為7米
  4. 透過I2C協定進行數據傳輸

Setting & Installing

接下來將於運行Raspbian作業系統的樹莓派上進行環境設置,我習慣使用VNC Server與樹莓派進行遠端連線操作

系統更新

shell
$ sudo apt-get update
$ sudo apt-get upgrade

啟用I2C & SPI介面

shell
$ sudo raspi-config

在選項5的介面設定中啟用它們,然後測試是否成功啟用

shell
$ ls /dev/i2c* /dev/spi*

Package Installing

直接安裝Adafruit的AMG88XX Package,pip會處理其他依賴的函式庫(e.g. Adafruit-Blinka)。

shell
$ sudo pip3 install adafruit-circuitpython-amg88xx

Blinka Test

使用Adafruit的測試範例來確認環境設定是否完成。

python
import board
import digitalio
import busio

print("Hello blinka!")

# Try to great a Digital input
pin = digitalio.DigitalInOut(board.D4)
print("Digital IO ok!")

# Try to create an I2C device
i2c = busio.I2C(board.SCL, board.SDA)
print("I2C ok!")

# Try to create an SPI device
spi = busio.SPI(board.SCLK, board.MOSI, board.MISO)
print("SPI ok!")

print("done!")

I2C Test

依照樹莓派GPIO與AMG8833進行連接:

  1. 3V Power連接到Vin
  2. GND連接到GND
  3. 連接SDA & SCL

試著透過I2C讀取感測器數據並印出來

python
import time
import busio
import board
import adafruit_amg88xx

i2c = busio.I2C(board.SCL, board.SDA)
amg = adafruit_amg88xx.AMG88XX(i2c)

while True:
    for row in amg.pixels:
        # Pad to 1 decimal place
        print(["{0:.1f}".format(temp) for temp in row])
        print("")
    print("\n")
    time.sleep(1)

Build Thermal Camera

安裝溫度數據視覺化所需的函式庫

shell
$ sudo apt-get install -y python3-scipy python3-pygame
$ sudo pip3 install colour

Adafruit官方範例程式:

python
"""This example is for Raspberry Pi (Linux) only!
   It will not work on microcontrollers running CircuitPython!"""
import os
import math
import time

import busio
import board

import numpy as np
import pygame
from scipy.interpolate import griddata

from colour import Color

import adafruit_amg88xx

i2c_bus = busio.I2C(board.SCL, board.SDA)

#low range of the sensor (this will be blue on the screen)
MINTEMP = 26.

#high range of the sensor (this will be red on the screen)
MAXTEMP = 32.

#how many color values we can have
COLORDEPTH = 1024

os.putenv('SDL_FBDEV', '/dev/fb1')
pygame.init()

#initialize the sensor
sensor = adafruit_amg88xx.AMG88XX(i2c_bus)

# pylint: disable=invalid-slice-index
points = [(math.floor(ix / 8), (ix % 8)) for ix in range(0, 64)]
grid_x, grid_y = np.mgrid[0:7:32j, 0:7:32j]
# pylint: enable=invalid-slice-index

#sensor is an 8x8 grid so lets do a square
height = 240
width = 240

#the list of colors we can choose from
blue = Color("indigo")
colors = list(blue.range_to(Color("red"), COLORDEPTH))

#create the array of colors
colors = [(int(c.red * 255), int(c.green * 255), int(c.blue * 255)) for c in colors]

displayPixelWidth = width / 30
displayPixelHeight = height / 30

lcd = pygame.display.set_mode((width, height))

lcd.fill((255, 0, 0))

pygame.display.update()
pygame.mouse.set_visible(False)

lcd.fill((0, 0, 0))
pygame.display.update()

#some utility functions
def constrain(val, min_val, max_val):
    return min(max_val, max(min_val, val))

def map_value(x, in_min, in_max, out_min, out_max):
    return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min

#let the sensor initialize
time.sleep(.1)

while True:

    #read the pixels
    pixels = []
    for row in sensor.pixels:
        pixels = pixels + row
    pixels = [map_value(p, MINTEMP, MAXTEMP, 0, COLORDEPTH - 1) for p in pixels]

    #perform interpolation
    bicubic = griddata(points, pixels, (grid_x, grid_y), method='cubic')

    #draw everything
    for ix, row in enumerate(bicubic):
        for jx, pixel in enumerate(row):
            pygame.draw.rect(lcd, colors[constrain(int(pixel), 0, COLORDEPTH- 1)],
                             (displayPixelHeight * ix, displayPixelWidth * jx,
                              displayPixelHeight, displayPixelWidth))

    pygame.display.update()

迷你紅外線熱像儀就這麼運作起來囉~🙆‍♂️ 可依照自己的測試環境,嘗試調整感測溫度上下限讓影像清晰一些。

Ref.

  1. I2C-協定用法原理簡介-晶片溝通的橋樑
  2. Installing CircuitPython Libraries on Raspberry Pi
  3. Adafruit AMG8833 8x8 Thermal Camera Sensor
  4. Raspberry Pi Thermal Camera

Last updated: