
مرحبا بالجميع!
جاء فصل الشتاء ، ومعه مهمة التحقق من خصائص العزل الحراري
للمباني في منزل ريفي لإقامة الصيف. وبعد ذلك اتضح أن على موقع صيني معروف ظهرت وحدات التصوير الحراري بأسعار معقولة جدا. هل من الممكن تجميع شيء غريب ، وربما مفيد ، وهو تصوير حراري محلي الصنع؟ لماذا لا ، مثل توت العليق كان مستلقيا في مكان ما ... ما الذي جاء منه - سأخبرك تحت القص.
MLX90640. ما هذا
وهذا ، في الواقع ، هو مصفوفة التصوير الحراري مع متحكم على متن الطائرة. إنتاج شركة غير معروفة سابقا Melexis. تبلغ مصفوفة التصوير الحراري 32 × 24 بكسل. هذا ليس كثيرًا ، ولكن عند الاستيفاء من الصورة ، يبدو كافيًا لإنتاج شيء ما على الأقل.

يتوفر المستشعر في نسختين ، تختلف حالاتهما في زاوية عرض المصفوفة. هيكل القرفصاء A يطل على العالم الخارجي بزاوية 110 (أفقية) عند 75 (رأسية) درجة. ب - أقل من 55 بنسبة 37.5 درجة على التوالي. تحتوي علبة الجهاز على أربعة مخرجات فقط - اثنان للطاقة ، واثنان للتواصل مع جهاز التحكم عبر واجهة I2C. يمكن تنزيل أوراق البيانات المهتمة من
هنا .
ثم ما هو GY-MCU90640؟
وضع الرفاق الصينيون MLX90640 على متن الطائرة مع متحكم آخر (STM32F103). على ما يبدو ، لإدارة أسهل المصفوفة. تسمى هذه المزرعة بأكملها GY-MCU90640. ويكلف وقت الاستحواذ (نهاية ديسمبر 2018) في منطقة 5 آلاف روبل. يبدو مثل هذا:

كما ترون ، هناك نوعان من اللوحات ، مع نسخة ضيقة أو واسعة الزاوية من أجهزة الاستشعار على متن الطائرة.
ما هو الإصدار الأفضل لك؟ سؤال جيد ، لسوء الحظ ، لم يكن لدي إلا بعد أن تم طلب الوحدة وتلقيها بالفعل. لسبب ما ، في وقت الأمر ، لم ألاحظ هذه الفروق الدقيقة. لكن دون جدوى.
سيكون الإصدار الأوسع جيدًا على الروبوتات ذاتية الدفع أو في أنظمة الأمان (سيكون مجال الرؤية أكبر). حسب ورقة البيانات ، فإنه يحتوي أيضًا على ضوضاء أقل ودقة قياس أكبر.

لكن بالنسبة لمهام التصور ، أفضل أن أوصي بإصدار أكثر "بعيد المدى" من B. لسبب مهم للغاية. في المستقبل ، عند التصوير ، يمكن نشره (يدويًا أو على نظام أساسي باستخدام محرك أقراص) والتقاط "صور" مركبة ، مما يزيد من الدقة المتواضعة التي تصل إلى 32 × 24 بكسل. اجمع الصور الحرارية 64 × 96 بكسل ، على سبيل المثال ... حسنًا ، حسنًا ، ستكون الصور في المستقبل من الإصدار ذي الزاوية الواسعة A.
الاتصال التوت بي
هناك طريقتان للتحكم في وحدة التصوير الحراري:
- تقصير العبور "SET" على اللوحة واستخدام I2C للاتصال مباشرة متحكم MLX90640 الداخلي.
- اترك الوصلة منفردة والتواصل مع الوحدة من خلال واجهة مماثلة مثبتة على لوحة STM32F103 من خلال RS-232.
إذا كتبت بـ C ++ ، فربما يكون من الأنسب تجاهل المتحكم الإضافي ودائرة العبور القصيرة واستخدام واجهة برمجة التطبيقات (API) من الشركة المصنعة التي تقع
هنا .
يمكن للثعبان المتواضع أن يسلك الطريق الأول. يبدو أن هناك بعض مكتبات Python (
هنا وهنا ). لكن لسوء الحظ ، لم يعمل لي أحد.
يمكن للبيثون المتقدمين أن يكتبوا في الأساس برنامج تشغيل وحدة التحكم في بيثون. يتم وصف الإجراء للحصول على إطار بالتفصيل في ورقة البيانات. ولكن بعد ذلك سيتعين عليك وصف جميع إجراءات المعايرة ، والتي تبدو مرهقة بعض الشيء. لذلك ، اضطررت للذهاب في الطريق الثاني. اتضح أن تكون معتدلة الشائكة ، ولكن مقبول جدا.
بفضل رؤية المهندسين الصينيين أو مجرد صدفة سعيدة ، تبين أن الشال يتمتع بموقع جيد للغاية من الاستنتاجات:

يبقى فقط لوضع الكتلة وإدخال وشاح في موصل التوت. يتم تثبيت محول من 5 إلى 3 فولت على السبورة ، لذا يبدو أن لا شيء يهدد مخرجات Rx و Tx الحساسة لـ Raspberry.
يجب إضافة أن الاتصال وفقًا للخيار الأول ممكن أيضًا ، لكنه يتطلب مزيدًا من مهارة العمل والجندى. يجب تثبيت اللوحة على الجانب الآخر من موصل التوت (كما هو موضح في صورة عنوان هذا المنشور).
البرمجيات
في موقع صيني مشهور ، يتم تقديم مثل هذه المعجزة للوصول إلى GY-MCU90640:

على ما يبدو ، يجب أن يكون هناك بعض وصف بروتوكول التفاعل مع متحكم مثبت على اللوحة ، والذي يعمل وفقًا لهذا المنتج البرنامجي! بعد محادثة قصيرة مع بائع الأوشحة (فيما يتعلق بالسادة المحترمين) ، تم إرسال هذا البروتوكول إلي. ظهرت في قوات الدفاع الشعبي والصينية البحتة.
بفضل مترجم Google ولصق النسخ النشط ، تم فك تشفير البروتوكول في غضون ساعة ونصف ، ويمكن للجميع قراءته على
Github . اتضح أن الوشاح يفهم ستة أوامر أساسية ، من بينها طلب إطار على منفذ COM.
كل بكسل في المصفوفة هو ، في الواقع ، قيمة درجة حرارة الكائن الذي يبحث عنه هذا البكسل. درجة الحرارة في درجة مئوية مرات 100 (عدد مزدوج البايت). في الواقع ، هناك حتى وضع خاص سترسل فيه الوشاح إطارات من المصفوفة إلى Raspberry 4 مرات في الثانية.
البرنامج النصي للحصول على الصور الحرارية هنا:"""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.