
Olá pessoal!
Chegou o inverno e, com ele, a tarefa é verificar as propriedades de isolamento térmico dos
edifícios da residência rural da dacha. E então, no conhecido site chinês, apareceram módulos de imagem térmica bastante acessíveis. É possível montar algo exótico e, possivelmente, até útil - um termovisor caseiro? Por que não, como Raspberry estava em algum lugar ... O que aconteceu - eu vou te dizer por baixo.
MLX90640. O que é isso
E isso, de fato, é uma matriz de imagem térmica com um microcontrolador a bordo. Produção da empresa anteriormente desconhecida Melexis. A matriz de imagem térmica tem uma dimensão de 32 por 24 pixels. Isso não é muito, mas ao interpolar a imagem, parece ser o suficiente para pelo menos entender alguma coisa.

O sensor está disponível em duas versões, cujos casos diferem no ângulo de visão da matriz. Uma estrutura mais agachada A tem vista para o mundo exterior em um ângulo de 110 (horizontal) a 75 (vertical) graus. B - abaixo de 55 por 37,5 graus, respectivamente. O gabinete do dispositivo possui apenas quatro saídas - duas para alimentação, duas para comunicação com o dispositivo de controle via interface I2C. As planilhas de dados interessadas podem ser baixadas
aqui .
E então, o que é o GY-MCU90640?
Camaradas chineses colocam o MLX90640 a bordo com outro microcontrolador a bordo (STM32F103). Aparentemente, para facilitar o gerenciamento de matrizes. Toda essa fazenda é chamada GY-MCU90640. E custa no momento da aquisição (final de dezembro de 2018) na região de 5 mil rublos. É assim:

Como você pode ver, existem dois tipos de placas, com uma versão estreita ou grande angular do sensor a bordo.
Qual versão é melhor para você? Uma boa pergunta, infelizmente, eu a tive somente depois que o módulo já foi encomendado e recebido. Por alguma razão, no momento do pedido, não prestei atenção a essas nuances. Mas em vão.
Uma versão mais ampla será boa em robôs autopropulsores ou em sistemas de segurança (o campo de visão será maior). De acordo com a folha de dados, também possui menos ruído e maior precisão de medição.

Mas para tarefas de visualização, eu preferiria recomendar uma versão mais "de longo alcance" de B. Por um motivo muito significativo. No futuro, ao fotografar, ele poderá ser implantado (manualmente ou em uma plataforma com uma unidade) e tirar "fotos" compostas, aumentando assim a resolução mais do que modesta de 32 por 24 pixels. Colete imagens térmicas de 64 por 96 pixels, por exemplo ... Bem, tudo bem, no futuro as fotos serão da versão grande angular A.
Conectar-se ao Raspberry PI
Existem duas maneiras de controlar o módulo de imagem térmica:
- Encurte o jumper “SET” na placa e use I2C para entrar em contato diretamente com o microcontrolador MLX90640 interno.
- Deixe o jumper sozinho e comunique-se com o módulo através de uma interface semelhante instalada na placa STM32F103 via RS-232.
Se você escreve em C ++, provavelmente será mais conveniente ignorar o microcontrolador extra, causar um curto-circuito no jumper e usar a API do fabricante, que fica
aqui .
Pitonistas humildes também podem seguir o primeiro caminho. Parece que existem algumas bibliotecas Python (
aqui e
aqui ). Mas, infelizmente, nenhum deles funcionou para mim.
Pythonists avançados podem basicamente escrever um driver de controle de módulo em Python. O procedimento para obter um quadro é descrito em detalhes na folha de dados. Mas então você terá que prescrever todos os procedimentos de calibração, o que parece um pouco oneroso. Portanto, eu tive que seguir o segundo caminho. Acabou sendo moderadamente espinhoso, mas bastante aceitável.
Graças à percepção dos engenheiros chineses ou apenas uma feliz coincidência, o xale revelou uma localização muito boa das conclusões:

Resta apenas colocar o bloco e inserir o cachecol no conector de framboesa. Um conversor de 5 a 3 Volts está instalado na placa, então parece que nada ameaça as delicadas saídas Rx e Tx do Raspberry.
Deve-se acrescentar que a conexão de acordo com a primeira opção também é possível, mas requer mais trabalho e habilidade de solda. A placa deve ser instalada no outro lado do conector Raspberry (mostrado na foto do título desta postagem).
De software
Em um site chinês conhecido, é oferecido um milagre para acessar o GY-MCU90640:

Aparentemente, deve haver alguma descrição do protocolo de interação com o microcontrolador instalado na placa, de acordo com o qual este produto de software funciona! Após uma breve conversa com o vendedor de lenços (respeito a esses respeitados cavalheiros), esse protocolo foi enviado a mim. Apareceu em pdf e em chinês puro.
Graças ao tradutor do Google e à cópia e pasta ativa, o protocolo foi descriptografado em cerca de uma hora e meia, e todos podem lê-lo no
Github . Descobriu-se que o cachecol compreende seis comandos básicos, entre os quais há uma solicitação de quadro na porta COM.
Cada pixel da matriz é, de fato, o valor da temperatura do objeto que esse pixel está olhando. Temperatura em graus Celsius vezes 100 (número de byte duplo). Na verdade, existe até um modo especial em que o cachecol envia quadros da matriz para o Raspberry 4 vezes por segundo.
O script para obter imagens térmicas aqui:"""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()
, Raspberry PI, 4 . , . OpenCV. «s» « » jpg.

. , . — . 20 40 . Ctrl + C.

Raspberry Pi Zero W Pi 3 B+. VNC . , , powerbank' VNC . , , .
. .
, , . . , . - , .
!
UPD: . . - , , . . — .

. +20...+40 -10...+5.