ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

基于树莓派与AMG8833的复古热成像仪DIY全攻略

2026/8/19 10:13:53 拓冰建站 浏览量
基于树莓派与AMG8833的复古热成像仪DIY全攻略 1. 项目概述用树莓派复刻一台1979年的热成像仪最近在整理老物件时翻到了一张1979年《大众电子》杂志的广告页上面展示了一款名为“Apollo”的热成像相机原型机。那粗犷的工业设计、显像管式的显示界面瞬间把我拉回了那个充满探索精神的年代。作为一个硬件爱好者我立刻萌生了一个想法能不能用今天唾手可得的开源硬件比如树莓派来复刻一台属于我们这个时代的“Apollo”热成像仪这不仅仅是一个怀旧项目更是一次对传感器技术平民化历程的致敬。今天我们就用一块树莓派、一个热成像传感器模块加上Python和一点复古的UI设计亲手打造一台功能完整的便携式热成像相机。无论你是想学习传感器应用、Python图形界面开发还是单纯想做一个酷炫的极客玩具这个项目都能让你满载而归。2. 核心硬件选型与电路设计思路2.1 传感器模块MLX90640与AMG8833的抉择热成像的核心是红外传感器。市面上常见的、易于与树莓派集成的传感器主要有两种MLX90640和AMG8833又称Grid-EYE。MLX90640是一款32x24像素的红外阵列传感器能提供768个独立的温度测量点。它的分辨率更高成像细节更丰富适合需要观察温度分布细节的场景比如检查电路板发热点或建筑隔热缺陷。但其数据量较大对树莓派的处理能力有一定要求且价格相对较高。AMG8833则是一个8x8像素的红外阵列提供64个温度点。它的优势在于价格亲民、接口简单I2C、数据处理压力小。虽然成像的“颗粒感”会强一些像早期的电子游戏画面但这反而与我们要复刻的1979年“复古低分辨率”风格不谋而合。考虑到项目的复古主题、成本以及对树莓派Zero或3B等型号的兼容性我最终选择了AMG8833。注意AMG8833的视场角FOV通常为60°x60°。这意味着它“看到”的是一个正方形区域。如果你需要更宽的视野可能需要寻找FOV更大的型号或者通过机械扫描的方式来实现。2.2 主控与显示树莓派与ST7789屏幕的搭配树莓派自然是本项目的大脑。从Zero 2 W到最新的Pi 5都能胜任但考虑到便携性树莓派Zero 2 W是一个绝佳的选择它性能足够且体积小巧。你需要为其准备一张至少8GB的MicroSD卡并安装好Raspberry Pi OS精简版即可。显示部分为了追求复古的CRT阴极射线管单色或伪彩色效果一块小巧的SPI接口LCD屏非常合适。Adafruit的1.3英寸或1.54英寸ST7789驱动IPS屏是我的首选。它分辨率适中240x240或240x135色彩表现好并且有成熟的Python库Adafruit_CircuitPython_ST7789支持可以轻松绘制出我们想要的扫描线、像素块等复古图形效果。2.3 电路连接与供电方案连接非常简单主要利用树莓派的GPIO和I2C、SPI接口。AMG8833连接AMG8833使用I2C通信。VCC - 树莓派 3.3V (Pin 1)GND - 树莓派 GND (Pin 6)SDA - 树莓派 GPIO 2 (SDA, Pin 3)SCL - 树莓派 GPIO 3 (SCL, Pin 5)ST7789屏幕连接屏幕使用SPI通信还需要一根引脚控制复位RESET和另一根控制数据/命令选择DC。VCC - 3.3VGND - GNDSCLK - GPIO 11 (SPI0 SCLK)MOSI - GPIO 10 (SPI0 MOSI)CS - GPIO 8 (SPI0 CE0) 或直接接地如果只有一个SPI设备DC - GPIO 24 (任意GPIO用于区分发送的是数据还是命令)RST - GPIO 25 (任意GPIO用于硬件复位)供电整个系统可以通过树莓派的Micro USB口供电。如果使用移动电源建议选择输出5V/2.5A以上的型号以保证树莓派Zero 2 W和屏幕稳定运行。如果屏幕背光电流较大可以考虑单独从5V引脚取电但通常3.3V足够。实操心得在焊接排针或连接杜邦线时务必先断开电源。I2C总线上通常需要上拉电阻但很多传感器模块包括常见的AMG8833模块已经板载了上拉电阻所以直接连接即可。如果不确定可以用万用表测量一下SDA/SCL线对3.3V的电阻如果阻值在几K欧姆说明已有上拉。3. 软件环境搭建与核心库配置3.1 操作系统与基础环境首先在SD卡上刷写最新的Raspberry Pi OS Lite无桌面环境更节省资源。通过SSH连接到你的树莓派。第一件事是更新系统并启用必要的接口sudo apt update sudo apt upgrade -y sudo raspi-config在raspi-config中找到Interface Options依次开启I2C和SPI。这是传感器和屏幕通信的基础。接下来安装Python3和必要的工具。Raspberry Pi OS通常预装了Python3但我们还需要包管理工具pipsudo apt install python3-pip python3-venv -y我强烈建议为这个项目创建一个独立的Python虚拟环境避免库版本冲突python3 -m venv thermal_cam_env source thermal_cam_env/bin/activate看到命令行提示符前面出现(thermal_cam_env)即表示激活成功。3.2 核心Python库安装本项目依赖几个关键的Python库Adafruit-Blinka这是Adafruit CircuitPython库在树莓派或其他Linux单板机上的兼容层它让我们可以用CircuitPython风格的API来操作GPIO、I2C、SPI。pip3 install adafruit-blinkaAMG8833传感器库Adafruit提供了专门的CircuitPython库。pip3 install adafruit-circuitpython-amg88xxST7789屏幕库用于驱动屏幕。pip3 install adafruit-circuitpython-st7789Pillow (PIL)一个强大的图像处理库我们将用它来将温度数据数组转换为图像并进行缩放、调色等操作。pip3 install pillowPyGame虽然我们的主显示用ST7789库但PyGame在开发阶段非常有用。我们可以先在电脑显示器上用PyGame模拟出复古UI效果调试好后再移植到小屏幕上。它也能用于处理输入比如按钮。pip3 install pygame### 3.3 硬件初始化测试 在编写主程序前先写个简单的测试脚本确保硬件都能正常工作。 **测试AMG8833** python # test_sensor.py import time import board import busio import adafruit_amg88xx # 初始化I2C i2c busio.I2C(board.SCL, board.SDA) # 初始化传感器默认I2C地址是0x69 sensor adafruit_amg88xx.AMG88XX(i2c) # 等待传感器启动 time.sleep(0.1) while True: # 读取所有64个像素的温度值单位摄氏度 pixels sensor.pixels print(“温度阵列”) for row in pixels: print([“{0:.1f}”.format(temp) for temp in row]) print(“\n”) time.sleep(1)运行这个脚本你应该能看到一个8x8的二维数组不断打印出来数值接近环境温度。如果报错检查I2C是否启用接线是否正确可以用sudo i2cdetect -y 1命令查看0x69地址是否存在。测试ST7789屏幕# test_screen.py import board import digitalio import adafruit_st7789 from PIL import Image, ImageDraw # 配置屏幕引脚 spi board.SPI() tft_cs board.CE0 tft_dc digitalio.DigitalInOut(board.D24) tft_rst digitalio.DigitalInOut(board.D25) # 初始化屏幕这里以240x240为例 display adafruit_st7789.ST7789(spi, cstft_cs, dctft_dc, rsttft_rst, width240, height240, rotation180) # 创建一个纯色图像并显示 image Image.new(“RGB”, (240, 240), color(255, 0, 0)) # 红色 display.image(image)运行后屏幕应该会变成红色。如果屏幕是白色或没反应检查SPI启用状态、引脚定义和旋转角度rotation参数可能是0, 90, 180, 270。4. 核心算法从温度数据到复古热成像4.1 温度数据获取与校准AMG8833返回的原始数据是64个浮点数代表摄氏温度。但有几个点需要注意噪声传感器本身有噪声相邻像素在均匀温度场下也可能有0.5°C左右的差异。为了得到更平滑的图像我们可以对连续几帧的数据进行移动平均滤波。漂移长时间工作或有环境温度变化时读数可能有轻微漂移。对于非高精度测量可以定期记录一个“背景帧”比如对准一个已知室温的均匀墙面然后将后续读数减去这个背景帧的偏移量进行简易校准。范围映射我们需要将温度值映射到颜色或灰度。首先确定一个你关心的温度范围比如T_min 20°C,T_max 40°C。任何低于T_min的温度都视为T_min高于T_max的视为T_max。4.2 伪彩色与灰度图像生成1979年的热像仪显示色彩有限我们模拟两种经典风格铁虹Ironbow伪彩色这是最经典的热成像配色从黑冷到蓝、绿、黄、红、白热。我们可以利用PIL的Image模块来创建调色板。将归一化后的温度值0.0到1.0映射到一个预定义的色彩查找表LUT。一个简单的实现方法是将温度值乘以255得到一个索引从一个包含256种颜色的列表从冷色到暖色中选取颜色。灰度黑白更复古像老式CRT显示器。直接将归一化温度值乘以255作为灰度值0黑255白。代码示例温度归一化与图像生成import numpy as np from PIL import Image def normalize_temperature(pixels_array, temp_min, temp_max): “”“将温度数组归一化到0-1之间”“” # 将温度限制在范围内 clipped np.clip(pixels_array, temp_min, temp_max) # 归一化 normalized (clipped - temp_min) / (temp_max - temp_min) return normalized def create_ironbow_image(normalized_data): “”“生成铁虹伪彩色图像”“” height, width 8, 8 # 将8x8数据上采样到240x240使用最近邻插值保持“像素块”感 upscaled_data np.kron(normalized_data, np.ones((30, 30))) # 8*30240 # 创建一个240x240的RGB图像 image Image.new(“RGB”, (width*30, height*30)) pixels image.load() # 简单的铁虹LUT这里用线性插值模拟实际可用更精细的列表 for y in range(image.height): for x in range(image.width): val upscaled_data[y, x] if val 0.25: # 黑到蓝 r, g, b 0, 0, int(val * 4 * 255) elif val 0.5: # 蓝到青 r, g, b 0, int((val-0.25)*4*255), 255 elif val 0.75: # 青到黄 r, g, b int((val-0.5)*4*255), 255, int((0.75-val)*4*255) else: # 黄到红到白 r, g, b 255, int((1.0-val)*4*255), 0 pixels[x, y] (r, g, b) return image def create_grayscale_image(normalized_data): “”“生成灰度图像”“” height, width 8, 8 upscaled_data np.kron(normalized_data, np.ones((30, 30))) # 将0-1值转换为0-255的整数 gray_array (upscaled_data * 255).astype(np.uint8) image Image.fromarray(gray_array, mode‘L’).convert(‘RGB’) # 转换为RGB模式供屏幕显示 return image4.3 复古UI元素叠加为了还原1979年的感觉我们可以在热图之上叠加一些UI元素扫描线效果在图像上叠加几条水平移动的亮线或暗线模拟CRT扫描。网格绘制8x8的网格明确标出每个温度像素的边界。模拟仪表/刻度在屏幕边缘绘制一个从蓝到红的温度刻度条。字体使用一种等宽、像素感强的字体来显示最高温、最低温、平均温等数字信息。这些都可以用PIL的ImageDraw模块来实现。5. 系统集成与性能优化5.1 主程序循环架构主程序需要高效地完成几个任务读取传感器、处理数据、生成图像、更新显示、并可能响应按键输入。一个典型的循环结构如下import time import board import busio import digitalio import adafruit_amg88xx import adafruit_st7789 from PIL import Image, ImageDraw, ImageFont import numpy as np # 初始化硬件 i2c busio.I2C(board.SCL, board.SDA) sensor adafruit_amg88xx.AMG88XX(i2c) spi board.SPI() tft_cs board.CE0 tft_dc digitalio.DigitalInOut(board.D24) tft_rst digitalio.DigitalInOut(board.D25) display adafruit_st7789.ST7789(spi, cstft_cs, dctft_dc, rsttft_rst, width240, height240, rotation180) # 状态变量 mode “ironbow” # 显示模式”ironbow”, “grayscale” temp_min 20.0 temp_max 40.0 scanline_pos 0 font_small ImageFont.load_default() # 使用默认字体或加载一个像素字体 # 主循环 while True: start_time time.monotonic() # 1. 读取数据 pixels np.array(sensor.pixels) # 转换为numpy数组便于计算 # 2. 数据处理滤波、校准 # 这里可以加入移动平均滤波 # processed_pixels some_filter(pixels) # 3. 归一化 normalized normalize_temperature(pixels, temp_min, temp_max) # 4. 生成基础热图 if mode “ironbow”: image create_ironbow_image(normalized) else: image create_grayscale_image(normalized) # 5. 叠加UI元素 draw ImageDraw.Draw(image) # 绘制网格 for i in range(9): line_pos i * 30 draw.line([(line_pos, 0), (line_pos, 240)], fill(128, 128, 128), width1) draw.line([(0, line_pos), (240, line_pos)], fill(128, 128, 128), width1) # 绘制扫描线示例一条半透明的移动白线 scanline_height 4 scanline Image.new(‘RGBA’, (240, scanline_height), (255, 255, 255, 64)) image.paste(scanline, (0, scanline_pos), scanline) scanline_pos (scanline_pos 2) % 240 # 绘制温度刻度条 for i in range(240): val i / 240 r, g, b get_color_from_lut(val) # 根据你的LUT获取颜色 draw.line([(245, i), (250, i)], fill(int(r), int(g), int(b)), width1) # 显示温度文本 max_temp np.max(pixels) min_temp np.min(pixels) avg_temp np.mean(pixels) draw.text((5, 5), f“Max:{max_temp:.1f}C”, fontfont_small, fill(255,255,0)) draw.text((5, 20), f“Min:{min_temp:.1f}C”, fontfont_small, fill(0,255,255)) draw.text((5, 35), f“Avg:{avg_temp:.1f}C”, fontfont_small, fill(255,255,255)) # 6. 更新显示 display.image(image) # 控制帧率例如5FPS loop_time time.monotonic() - start_time time.sleep(max(0, 0.2 - loop_time))5.2 性能瓶颈与优化技巧在树莓派Zero 2 W上运行主要的性能瓶颈在于图像生成与缩放np.kron和逐像素计算颜色在Python中较慢。PIL绘图操作频繁绘制文本、网格是耗时的。优化策略预计算铁虹LUT的颜色可以预先计算成一个256x3的数组避免循环中的复杂判断。减少缩放计算可以生成一个8x8的小图像然后用PIL的Image.resize()方法放大到240x240并指定resampleImage.NEAREST来保持像素感。这比在Python循环中操作快得多。缓存静态元素网格、刻度条等不常变化的UI元素可以生成一张静态的背景图每帧只需将热图与背景图合成而不是重新绘制所有线条。降低帧率对于热成像2-5 FPS已经足够观察温度变化无需追求高帧率。5.3 外壳设计与便携化要给这个项目一个完整的“产品”感觉一个3D打印的外壳必不可少。设计时需要考虑传感器开窗确保AMG8833的红外感应窗口前没有遮挡普通塑料会阻挡远红外线最好使用专用的锗玻璃窗口或者至少开一个裸露的孔。屏幕固定将ST7789屏幕牢固地固定在前面板。按键开口预留几个按钮孔用于切换模式、调整温度范围等。散热树莓派运行时会发热外壳需要设计通风孔。电池仓如果想完全便携可以设计一个空间容纳18650电池和充放电管理模块。你可以在Thingiverse或Printables等网站搜索“Raspberry Pi Zero Case”和“Thermal Camera”寻找灵感或者使用Fusion 360等软件自己设计。6. 功能扩展与实战应用6.1 添加物理控制与交互除了在屏幕上显示我们可以通过GPIO连接几个按钮来增加交互性模式切换按钮在伪彩色和灰度模式间切换。温度范围调整按钮两个按钮分别提高或降低T_max和T_min用于聚焦到特定的温度区间。拍照/录像按钮按下后将当前帧的温度数据或图像保存到SD卡。可以保存为CSV文件温度数据或PNG图片。使用adafruit_debouncer库可以很好地处理按键抖动。将按钮一端接GPIO引脚另一端接地并在代码中设置为上拉输入模式。6.2 数据记录与分析将热成像仪用于实际问题排查时记录数据至关重要。我们可以扩展程序功能定时拍照每隔一段时间自动保存一张热图。温度报警当检测到某个区域温度超过设定阈值时在屏幕上高亮显示并记录日志。生成温度变化曲线针对某一个固定的像素点比如设备上的某个关键元件记录其温度随时间的变化并绘制成曲线图。保存的CSV文件可以导入到Excel、PythonPandas, Matplotlib或专业软件中进行更深入的分析。6.3 实战应用场景这台自制热像仪虽然分辨率不高但在很多场景下非常有用电子维修快速定位电路板上的短路发热元件。哪个芯片或MOSFET异常发烫一目了然。家庭能源审计检查门窗、墙壁的隔热漏洞。冷空气渗入或热空气溢出的地方在热像图上会显示明显的温差。3D打印监控观察打印件在打印过程中的温度分布是否均匀特别是对于大型件或使用封闭式打印机的情况。宠物/野生动物观察在夜晚热成像可以让你看到温血动物的活动注意AMG8833的探测距离有限大约几米到十米。科学教育非常直观地展示热传导、热辐射、隔热材料效果等物理概念。注意事项AMG8833测量的是表面温度且易受环境反射影响。测量光亮金属表面时读数会不准确。玻璃对远红外线基本不透明所以无法透过窗户测量室外温度。7. 常见问题排查与调试心得在项目搭建过程中你可能会遇到以下问题7.1 传感器读数异常现象所有像素温度相同或为0、-273绝对零度。排查首先运行sudo i2cdetect -y 1确认I2C总线上是否存在地址0x69或0x68取决于模块跳线。如果看不到检查接线、电源并确认I2C已启用。检查电源电压。AMG8833需要稳定的3.3V树莓派GPIO的3.3V引脚输出能力有限如果连接了多个设备可能导致电压跌落。尝试单独供电。检查代码中的I2C初始化是否正确特别是board.SCL和board.SDA的引脚定义是否与你的树莓派型号匹配。7.2 屏幕无显示或花屏现象屏幕背光亮但无内容或显示乱码。排查检查SPI运行ls /dev/spi*应该能看到/dev/spidev0.0和/dev/spidev0.1。如果没有在raspi-config中重新启用SPI并重启。检查引脚和接线确认DC和RST引脚号在代码中定义正确并且接线牢固。松动的杜邦线是万恶之源。检查屏幕初始化参数width,height,rotation这三个参数必须与你的屏幕物理分辨率和安装方向一致。可以尝试不同的rotation值0, 90, 180, 270。降低SPI速率有时屏幕驱动IC在高SPI速率下不稳定。在初始化ST7789时可以尝试传入baudrate24000000或更低的参数。7.3 程序运行卡顿或帧率极低现象图像更新缓慢树莓派CPU占用率高。排查与优化使用htop命令查看是哪个进程占用了CPU。如果是Python进程说明我们的代码效率是瓶颈。应用性能优化技巧如前所述使用预计算LUT、PIL的resize代替手动放大、缓存UI元素。关闭不必要的服务如果运行的是完整版桌面系统关闭图形界面可以释放大量资源。使用sudo systemctl set-default multi-user.target并重启以命令行模式运行。检查虚拟内存如果内存不足会导致频繁交换swap极大拖慢速度。使用free -h查看。可以考虑减少图像缓冲区或增加swap空间。7.4 温度测量不准确现象读数与环境温度计差异大。排查传感器预热AMG8833需要几分钟的预热时间才能达到稳定状态。刚上电的读数不准是正常的。避免空气流动风扇、空调风或人的呼吸都会干扰测量。尽量在静止空气中测量。考虑发射率不同材料的发射率不同。AMG8833默认校准是针对发射率约0.95的物体如皮肤、木材、油漆。测量光亮金属低发射率或玻璃透明时读数会严重偏低。这不是传感器故障而是所有红外测温设备的物理限制。进行两点校准如果你有高精度的接触式测温仪可以测量一个低温物体如冷水和一个高温物体如温水记录下AMG8833的读数然后计算出一个简单的线性偏移和增益修正公式应用到代码中。这个项目从构思到实现最耗时的部分往往不是编码而是硬件调试和性能调优。当屏幕上第一次出现那个带着扫描线、略显粗糙但真实反映温度分布的热图时那种成就感是无与伦比的。它不仅仅是一个工具更是连接过去与现在、想法与现实的一座桥梁。你可以根据自己的想法轻松地修改配色方案、添加新功能比如蓝牙数据传输到手机甚至尝试更高分辨率的传感器。希望这个详细的指南能帮你顺利点亮属于你自己的“1979 Apollo Pi Thermal Camera”。