基于Raspberry Pi制作DIY热像仪

图片

大家好!

冬天到了,所以我不得不检查我的外地住宅别墅的隔热性能。 事实证明,一个著名的中国市场开始销售廉价的热像仪模块。 因此,我决定将它自己动手做,并建造一个颇有异国情调和有用的东西-房屋的遮阳板。 为什么不呢 尤其是因为无论如何我都有一台Raspberry Pi……结果在下面。

MLX90640。 怎么了


这是一个带有机载微控制器的热像仪矩阵,由一家不知名(对我而言)的公司Melexis生产。 矩阵是32x24像素,虽然不多,但是插值后足以注意到一般趋势。

图片

传感器有两个版本,唯一的区别是外壳和相机的FoV。 接地性更高的模型以水平110度和垂直75度观察世界。 B模型分别具有55度和37.5度。 该机箱具有四个输出-两个用于供电,两个用于通过I2C与控制器设备通信。 数据表可以在这里找到。

那是什么GY-MCU90640?


我们的中国研究员还为MLX90640芯片提供了板载另一个微控制器(STM32F103),这可能是为了简化矩阵控制。 整个装置称为GY-MCU90640,它在2018年12月花费了我5,000卢布(约合80美元)。它看起来像:

图片

如我们所见,该模型还有两个版本,带有不同的传感器

哪一个效果最好? 不幸的是,我只是在订购,运输和接收模块后才问自己这个问题。 选择时我没有考虑过。

广角版本最适合自动驾驶机器人或闭路电视系统(因为它的视野更好)。 数据表表明,它的噪音也较小,但准确性更高。

图片

但是出于一种重要的原因,出于可视化考虑,我建议使用更“鹰眼”的B模型。 可以将其转到适当位置(手动或通过驱动器),以使组合图像比其32x24分辨率更精细。 但是我没有,所以稍后我将讨论广角A模型。

连接到Raspberry Pi


我们可以通过两种方式控制热像仪:

  • 短接板上的“ SET”引脚,并使用I2C协议直接控制MLX90640微控制器
  • 保持引脚不变,并通过RS-232或类似接口使用STM32F103控制器。

如果您使用C ++进行编码,最好忽略额外的控制器,缩短引脚并使用制造商的API(位于此处)

谦虚的Python专家也可以使用第一个选项。 似乎有两个Python库( 在这里在这里 ),但对我来说都没有现成的方法。

理论上,高级Python专家可以编写自己的控制器驱动程序。 数据表解释了如何从中提取帧。 但是您必须手动描述所有校准过程,我觉得这太难了。 因此,我使用了选项2。结果看起来有些复杂,但是仍然可以管理。

由于中国人的独创(或运气),开发板上的输出配置非常方便:

图片

我需要做的就是将开发板插入Raspberry的端口。 该开发板内置有5V-3V转换器,因此Pi的精致Rx和Tx输出没有任何危险。

我还要补充一点,您可以在使用选项1时进行类似的连接,但是您必须非常小心并且精通焊接。 该板必须安装在Pi的另一侧(示例在标题照片中)。

软体类


中国著名的市场提供用于访问GY-MCU90640的这款宏伟的软件:

图片

显然,还必须对用于访问微控制器的通信协议进行一些描述,在与卖方短暂交谈(对他表示敬意)之后,我已经说过了该协议。 PDF格式,以及纯净的中文摘要。

多亏了Google翻译和健康的复制粘贴功能,大约90分钟后,该协议才被解码。 我上载了 图片 Github 原来,该板理解6条基本命令,其中一条用于通过COM端口请求当前帧。

矩阵的每个像素本质上都是物体温度的读数。 温度值以摄氏度乘以100(2字节数字)为单位。 当开发板每秒自动发送帧四次到Pi时,甚至有一种特殊的模式。

接收热图像的完整脚本:
"""MIT License Copyright (c) 2019 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.""" import serial, time import datetime as dt import numpy as np import cv2 # function to get Emissivity from MCU def get_emissivity(): ser.write(serial.to_bytes([0xA5,0x55,0x01,0xFB])) read = ser.read(4) return read[2]/100 # function to get temperatures from MCU (Celsius degrees x 100) def get_temp_array(d): # getting ambient temperature T_a = (int(d[1540]) + int(d[1541])*256)/100 # getting raw array of pixels temperature raw_data = d[4:1540] T_array = np.frombuffer(raw_data, dtype=np.int16) return T_a, T_array # function to convert temperatures to pixels on image def td_to_image(f): norm = np.uint8((f/100 - Tmin)*255/(Tmax-Tmin)) norm.shape = (24,32) return norm ########################### Main cycle ################################# # Color map range Tmax = 40 Tmin = 20 print ('Configuring Serial port') ser = serial.Serial ('/dev/serial0') ser.baudrate = 115200 # set frequency of module to 4 Hz ser.write(serial.to_bytes([0xA5,0x25,0x01,0xCB])) time.sleep(0.1) # Starting automatic data colection ser.write(serial.to_bytes([0xA5,0x35,0x02,0xDC])) t0 = time.time() try: while True: # waiting for data frame data = ser.read(1544) # The data is ready, let's handle it! Ta, temp_array = get_temp_array(data) ta_img = td_to_image(temp_array) # Image processing img = cv2.applyColorMap(ta_img, cv2.COLORMAP_JET) img = cv2.resize(img, (320,240), interpolation = cv2.INTER_CUBIC) img = cv2.flip(img, 1) text = 'Tmin = {:+.1f} Tmax = {:+.1f} FPS = {:.2f}'.format(temp_array.min()/100, temp_array.max()/100, 1/(time.time() - t0)) cv2.putText(img, text, (5, 15), cv2.FONT_HERSHEY_SIMPLEX, 0.45, (0, 0, 0), 1) cv2.imshow('Output', img) # if 's' is pressed - saving of picture key = cv2.waitKey(1) & 0xFF if key == ord("s"): fname = 'pic_' + dt.datetime.now().strftime('%Y-%m-%d_%H-%M-%S') + '.jpg' cv2.imwrite(fname, img) print('Saving image ', fname) t0 = time.time() except KeyboardInterrupt: # to terminate the cycle ser.write(serial.to_bytes([0xA5,0x35,0x01,0xDB])) ser.close() cv2.destroyAllWindows() print(' Stopped') # just in case ser.close() cv2.destroyAllWindows() 


结果


该脚本以每秒4次的速度轮询热矩阵并将帧输出到所连接的监视器的控制台,这足以避免过多的不适感。 为了进行可视化,它使用OpenCV软件包。 当您按S时,来自摄像机的“热图”将作为JPG上传到脚本的文件夹中。

图片

为了获得更好的可见性,我还使应用程序在框架内显示最低和最高温度。 因此,通过查看热图,我们可以估计最冷和最热物体的温度(在一定范围内,通常在较高的一侧),范围在20至40度之间。 Ctrl + C退出脚本。

图片

该脚本在Raspberry Pi Zero W和Pi 3 B +上的工作原理相同。 我在智能手机上安装了VNC服务器,因此,通过使用具有VNC功能的智能手机将Pi连接到移动电源,我们可以得到一个袖珍型热像仪,以保存图像。 可能不太方便,但是可以完成工作。

第一次启动后,它可能会错误地显示最高温度,在这种情况下,只需重新启动脚本即可完成工作。

今天就这样。 实验可以认为是成功的。 您绝对可以使用此设备对房屋进行热扫描。 如果有人可以提出其他用途,请在评论中写下。

祝您一周工作愉快,很快再见!

UPD:我在评论中被要求从外面拍摄房子的照片。 来了 由于温度的对比度较低,这些图片最终没有提供足够的信息。 上面的两张照片从两个角度来看是整个房子。 下方的两张照片是不同的窗口。

图片

我对代码所做的唯一更改是温度范围:从+20 ... + 40到-10 ... + 5。

Source: https://habr.com/ru/post/zh-CN441050/


All Articles