Build a mini thermal camera – Part 3

Welcome to the third part of our mini thermal camera project! So far, we’ve set up the hardware and configured LVGL for our ESP32-S3 microcontroller. If you missed any steps, be sure to check out Part 1 and Part 2.

In this segment, I’ll detail the creation and configuration of the graphical elements needed for the thermal camera. Following this, we’ll integrate the thermal sensor readings and display them using our graphical interface. By the end of this tutorial, you’ll have a functional thermal camera capable of capturing and displaying real-time thermal images. Let’s get started!

Creating Essential UI Elements for the Thermal Camera

In this part, we are going to create and configure essential graphical elements for the user interface. First, we’ll create labels for ambient temperature, maximum temperature, and minimum temperature using the lv_label_create function. These labels will be positioned at the bottom of the screen with the lv_obj_align function.

Next, we’ll create a battery indicator using a bar element with lv_bar_create. This bar will be styled to change color based on the battery level, displaying green when battery is full and red when low, in particular I want the color gradient to start when the charge goes below 65%.

We will also create a graphical object for thermal image visualization using the lv_img_create function. The source of the image, set by the lv_img_set_src function, is a buffer containing the image data. This buffer will be detailed later when we discuss the IR array sensor. The thermal image will be centered on the screen and zoomed in, as the infrared array is small compared to the screen size.

Integrating the MLX90640 Sensor: Firmware and Implementation

In this section, we’ll dive into the integration of the MLX90640 sensor, focusing on the firmware required to interface with the sensor. While the sensor’s specifications were covered in the first part of the tutorial, here we’ll explore how to set up the firmware to read data from the sensor and process it for our thermal camera application. This includes configuring communication protocols, handling sensor data, and preparing the thermal image buffer for display on the screen.

I started with the libraries provided by Melexis, which are available on their dedicated GitHub page. These libraries needed adaptation for the ESP32-S3 microcontroller. Specifically, I integrated the driver with the I2C-specific code and made minor adjustments to the API, including adding some defines. The complete code for the thermal camera project is available on my GitHub repository, Link at the end of this post.

To use the device, you need to:

  1. Define data sets and buffers for data storage.
  2. Call MLX90640_I2CInit().
  3. Set the data rate.
  4. Read the EEPROM.
  5. Extract parameters.
  6. Start getting the data frame.

The API also includes functions to convert raw data to temperature and store everything in a buffer.

At this point, you need to extract information from the temperature buffer, such as minimum and maximum values, and convert temperatures to colors. I used the “jet” color map for visualizing the temperature. The “jet” color map transitions from blue (for low values) through cyan, green, yellow, and red (for high values), providing a clear gradient for temperature representation. Below is the implementation of the conversion function. It first normalizes the temperature value to a range between 0 and 1 based on the provided minimum and maximum temperatures. This ensures that the temperature value is scaled appropriately for color mapping. The final color is then mapped based on predefined thresholds. The minimum and maximum temperatures also determine the dynamic range of the image; they dictate the range of temperatures that can be visualized. In my example, min_temp and max_temp are set statically in the code, but they can also be adjusted dynamically based on actual measurements.

Because the screen size is much larger than the infrared array sensor size, I decided not only to zoom the image using LVGL functions but also to enlarge the thermal array to four times the actual size of the sensor. I defined SENS_H as 2*24 and SENS_V as 2*32, so when copying the thermal image into the buffer, a single IR pixel is copied into four image pixels. I did this because excessive zooming with LVGL functions introduced too many artifacts, and this method provides better visualization.

Conclusion

In this part of the tutorial, we successfully created essential UI elements for our thermal camera and integrated the MLX90640 sensor, focusing on the firmware and implementation. By enhancing the user interface and properly scaling the thermal image, we ensured a decent visualization on our display.

To access to the full code, visit my GitHub repository. This repository contains all the resources and code needed to build and refine your own mini thermal camera. You will notice that the operations for UI updates and thermal image buffer writing are managed by a semaphore to prevent the overlap of writing and reading operations. This ensures that data integrity is maintained by allowing only one process to access the shared resources at a time, thus avoiding potential conflicts and ensuring smooth and efficient operation of the thermal camera system. Happy coding!

Thank you for reading and supporting my blog! If you enjoyed this content and would like to help me continue creating more, please consider leaving a donation. Your generosity will help me cover the costs of materials and tools for future projects. Any amount is greatly appreciated! And remember to follow me on Instagram for more updates and behind-the-scenes content.