The MLX90640 comes with STEMMA QT/QWIIC connectors which makes it super simple to plug into projects with no soldering needed. Adafruit sells a STEMMA to STEMMA QT cable that allows you to plug this breakout into the STEMMA connector found on a number of Adafruit microcontroller boards, including PyBadge and PyGamer. The following example uses the PyBadge or PyGamer and the MLX90640 to create a super easy-to-assemble thermal camera with a display!
CircuitPython Microcontroller Wiring
First wire up a MLX90640 to your PyBadge or PyGamer exactly as shown below. Here's an example of wiring a PyBadge to the sensor with I2C using the STEMMA to STEMMA QT cable:
- Plug the larger end (STEMMA/Grove) of the cable into the PyBadge/PyGamer.
- Plug the smaller end (STEMMA QT) of the cable into the MLX90640.
CircuitPython Installation of Additional Libraries
On the previous page, you installed the Adafruit CircuitPython MLX90640 library on your CircuitPython board.
First make sure you are running the latest version of Adafruit CircuitPython for your board.
Next you'll need to install the necessary libraries to use this example -- carefully follow the steps to find and install these libraries from Adafruit's CircuitPython library bundle. Our CircuitPython starter guide has a great page on how to install the library bundle.
You'll need to manually install two additional libraries from the bundle:
- adafruit_display_text
- simpleio.mpy
Before continuing, make sure your board's lib folder has the adafruit_mlx90640.mpy, adafruit_bus_device, adafruit_display_text and simpleio.mpy files and folders copied over.
CircuitPython PyBadge/PyGamer Thermal Camera
Save the following code to your PyBadge or PyGamer as code.py.
# SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries # SPDX-License-Identifier: MIT import time import board import busio import displayio import terminalio from adafruit_display_text.label import Label from simpleio import map_range import adafruit_mlx90640 number_of_colors = 64 # Number of color in the gradian last_color = number_of_colors - 1 # Last color in palette palette = displayio.Palette(number_of_colors) # Palette with all our colors ## Heatmap code inspired from: http://www.andrewnoske.com/wiki/Code_-_heatmaps_and_color_gradients color_A = [ [0, 0, 0], [0, 0, 255], [0, 255, 255], [0, 255, 0], [255, 255, 0], [255, 0, 0], [255, 255, 255], ] color_B = [[0, 0, 255], [0, 255, 255], [0, 255, 0], [255, 255, 0], [255, 0, 0]] color_C = [[0, 0, 0], [255, 255, 255]] color_D = [[0, 0, 255], [255, 0, 0]] color = color_B NUM_COLORS = len(color) def MakeHeatMapColor(): for c in range(number_of_colors): value = c * (NUM_COLORS - 1) / last_color idx1 = int(value) # Our desired color will be after this index. if idx1 == value: # This is the corner case red = color[idx1][0] green = color[idx1][1] blue = color[idx1][2] else: idx2 = idx1 + 1 # ... and before this index (inclusive). fractBetween = value - idx1 # Distance between the two indexes (0-1). red = int( round((color[idx2][0] - color[idx1][0]) * fractBetween + color[idx1][0]) ) green = int( round((color[idx2][1] - color[idx1][1]) * fractBetween + color[idx1][1]) ) blue = int( round((color[idx2][2] - color[idx1][2]) * fractBetween + color[idx1][2]) ) palette[c] = (0x010000 * red) + (0x000100 * green) + (0x000001 * blue) MakeHeatMapColor() # Bitmap for colour coded thermal value image_bitmap = displayio.Bitmap(32, 24, number_of_colors) # Create a TileGrid using the Bitmap and Palette image_tile = displayio.TileGrid(image_bitmap, pixel_shader=palette) # Create a Group that scale 32*24 to 128*96 image_group = displayio.Group(scale=4) image_group.append(image_tile) scale_bitmap = displayio.Bitmap(number_of_colors, 1, number_of_colors) # Create a Group Scale must be 128 divided by number_of_colors scale_group = displayio.Group(scale=2) scale_tile = displayio.TileGrid(scale_bitmap, pixel_shader=palette, x=0, y=60) scale_group.append(scale_tile) for i in range(number_of_colors): scale_bitmap[i, 0] = i # Fill the scale with the palette gradian # Create the super Group group = displayio.Group() min_label = Label(terminalio.FONT, color=palette[0], x=0, y=110) max_label = Label(terminalio.FONT, color=palette[last_color], x=80, y=110) # Add all the sub-group to the SuperGroup group.append(image_group) group.append(scale_group) group.append(min_label) group.append(max_label) # Add the SuperGroup to the Display board.DISPLAY.root_group = group min_t = 20 # Initial minimum temperature range, before auto scale max_t = 37 # Initial maximum temperature range, before auto scale i2c = busio.I2C(board.SCL, board.SDA, frequency=800000) # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller mlx = adafruit_mlx90640.MLX90640(i2c) print("MLX addr detected on I2C") print([hex(i) for i in mlx.serial_number]) # mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_2_HZ mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_4_HZ frame = [0] * 768 while True: stamp = time.monotonic() try: mlx.getFrame(frame) except ValueError: # these happen, no biggie - retry continue # print("Time for data aquisition: %0.2f s" % (time.monotonic()-stamp)) mini = frame[0] # Define a min temperature of current image maxi = frame[0] # Define a max temperature of current image for h in range(24): for w in range(32): t = frame[h * 32 + w] if t > maxi: maxi = t if t < mini: mini = t image_bitmap[w, (23 - h)] = int(map_range(t, min_t, max_t, 0, last_color)) min_label.text = "%0.2f" % (min_t) max_string = "%0.2f" % (max_t) max_label.x = 120 - (5 * len(max_string)) # Tricky calculation to left align max_label.text = max_string min_t = mini # Automatically change the color scale max_t = maxi # print((mini, maxi)) # Use this line to display min and max graph in Mu # print("Total time for aquisition and display %0.2f s" % (time.monotonic()-stamp))
Now point the thermal camera at various objects to see a heat map displayed on your board!
Page last edited January 22, 2025
Text editor powered by tinymce.