This the FLIR Thermal camera breakout module can easily integrate to your SBC Single Board computer kit / BSP boards or Microcontroller evaluation boards that driven by ARM, STM, TI, NXP, ATMEL, etc. This device can be used in thermal imaging, motion detection, night vision, heat mapping, and gesture recognitions. The FLIR lepton is most compact long-wave infrared (LWIR) sensor, packs with excellent pixel resolution with a breakthrough lens fabricated in wafer form, together with a micro bolometer focal plane array (FPA) and thermal imaging processing. There are two model which you can start on this module one is the FLIR Lepton IO Module Version 1.2 without micro USB and the FLIR Lepton IO v1.3 has on-board micro USB that runs automatically on PC even without a central controller/microcontroller but requires TTL UART USB. For more technical details please refer to the datasheet.
Requiredments
- Raspberry Pi, NanoPi, Beaglebone, Thinker Board, Snapdragon Board, Lemon Pi, LattePanda, Banana Pi, Orange Pi. (please refer to each SBC’s respective pin-outs)
- Microcontroller –Arduino DUE, ESP32, LinkItOne (Note: Some Arduino hardware does not have enough memory to buffer the thermal image at 80602/9600 bytes)
- FLIR Lepton IO Module v1.2 / FLIR Lepton Module v1.3 Pro
- 3.3V TTL UART to USB Serial Cable – Attach to end of JTAG adapter above and enable debug UART switch in the firmware to utilize
- JTAG (required for firmware upgrades)
- FLIR Lepton Official Product Link
Wiring Guide
For installation on Raspberry Pi, NanoPi, Beaglebone, Thinker Board, Snapdragon Board, Lemon Pi, LattePanda, Banana Pi, Orange Pi. Just follow the steps below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
Step 1: $ sudo su root Step 2: $ apt-get upgrade Step 3: $ apt-get update Step 4: $ apt-get dist-upgrade Step 5: alter /etc/apt/sources.list to stretch instead of jessie Step 6: $ apt-get update Step 7: $ apt-get upgrade Step 8: $ reboot Enable OpneGL Kernel Driver Step 9: $ sudo raspi-config Select "Advance Options" Select "GL Driver" Select "GL (Full KMS) OpenGL desktop driver with full KMS" Select "ok" Select "FINISH" Step 10: sudo reboot Install Required Development Packages Step 11: $ sudo apt-get install qt5-default qtmultimedia5-dev qtdeclarative5-dev \ qml-module-qtquick-controls2 qml-module-qtmultimedia \ qml-module-qtquick-layouts qml-module-qtquick-window2 \ qml-module-qtquick-templates2 qml-module-qtgraphicaleffects \ libusb-1.0-0-dev cmake git Clone and Build GetThermal Step 12: git clone https://github.com/groupgets/GetThermal.git cd GetThermal git submodule update --init Step 13: Build libuvc cd libuvc mkdir build cd build cmake .. make cd ../.. Step 14: Build gethermal mkdir build cd build qmake .. make Output bin can be found in release/GetThermal Step 15: Allowing normal user PT1 to access to the thermal camera sudo sh -c "echo 'SUBSYSTEMS==\"usb\", ATTRS{idVendor}==\"1e4e\", ATTRS{idProduct}==\"0100\", SYMLINK+=\"pt1\", GROUP=\"usb\", MODE=\"666\"' > /etc/udev/rules.d/99-pt1.rules" Step 16: GetThermal -platform eglfs Running with Python Requires > CV2 and Numpy Module Step 1: $ sudo apt-get install python-opencv python-numpy Step 2: $ sudo python setup.py install Step 3: $ sudo apt-get install python-picamera Step 4: $ pylepton_overlay -a 255 Step 5: pylepton_capture testCaptureImage.png |
Test Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
#!/usr/bin/env python import numpy as np import ctypes import struct import time # relative imports in Python3 must be explicit from .ioctl_numbers import _IOR, _IOW from fcntl import ioctl SPI_IOC_MAGIC = ord("k") SPI_IOC_RD_MODE = _IOR(SPI_IOC_MAGIC, 1, "=B") SPI_IOC_WR_MODE = _IOW(SPI_IOC_MAGIC, 1, "=B") SPI_IOC_RD_LSB_FIRST = _IOR(SPI_IOC_MAGIC, 2, "=B") SPI_IOC_WR_LSB_FIRST = _IOW(SPI_IOC_MAGIC, 2, "=B") SPI_IOC_RD_BITS_PER_WORD = _IOR(SPI_IOC_MAGIC, 3, "=B") SPI_IOC_WR_BITS_PER_WORD = _IOW(SPI_IOC_MAGIC, 3, "=B") SPI_IOC_RD_MAX_SPEED_HZ = _IOR(SPI_IOC_MAGIC, 4, "=I") SPI_IOC_WR_MAX_SPEED_HZ = _IOW(SPI_IOC_MAGIC, 4, "=I") SPI_CPHA = 0x01 # /* clock phase */ SPI_CPOL = 0x02 # /* clock polarity */ SPI_MODE_0 = (0|0) # /* (original MicroWire) */ SPI_MODE_1 = (0|SPI_CPHA) SPI_MODE_2 = (SPI_CPOL|0) SPI_MODE_3 = (SPI_CPOL|SPI_CPHA) class Lepton(object): """Communication class for FLIR Lepton module on SPI Args: spi_dev (str): Location of SPI device node. Default '/dev/spidev0.0'. """ ROWS = 60 COLS = 80 VOSPI_FRAME_SIZE = COLS + 2 VOSPI_FRAME_SIZE_BYTES = VOSPI_FRAME_SIZE * 2 MODE = SPI_MODE_3 BITS = 8 SPEED = 18000000 SPIDEV_MESSAGE_LIMIT = 24 def __init__(self, spi_dev = "/dev/spidev0.0"): self.__spi_dev = spi_dev self.__txbuf = np.zeros(Lepton.VOSPI_FRAME_SIZE, dtype=np.uint16) # struct spi_ioc_transfer { # __u64 tx_buf; # __u64 rx_buf; # __u32 len; # __u32 speed_hz; # __u16 delay_usecs; # __u8 bits_per_word; # __u8 cs_change; # __u32 pad; # }; self.__xmit_struct = struct.Struct("=QQIIHBBI") self.__msg_size = self.__xmit_struct.size self.__xmit_buf = np.zeros((self.__msg_size * Lepton.ROWS), dtype=np.uint8) self.__msg = _IOW(SPI_IOC_MAGIC, 0, self.__xmit_struct.format) self.__capture_buf = np.zeros((Lepton.ROWS, Lepton.VOSPI_FRAME_SIZE, 1), dtype=np.uint16) for i in range(Lepton.ROWS): self.__xmit_struct.pack_into(self.__xmit_buf, i * self.__msg_size, self.__txbuf.ctypes.data, # __u64 tx_buf; self.__capture_buf.ctypes.data + Lepton.VOSPI_FRAME_SIZE_BYTES * i, # __u64 rx_buf; Lepton.VOSPI_FRAME_SIZE_BYTES, # __u32 len; Lepton.SPEED, # __u32 speed_hz; 0, # __u16 delay_usecs; Lepton.BITS, # __u8 bits_per_word; 1, # __u8 cs_change; 0) # __u32 pad; def __enter__(self): # "In Python 3 the only way to open /dev/tty under Linux appears to be 1) in binary mode and 2) with buffering disabled." self.__handle = open(self.__spi_dev, "wb+", buffering=0) ioctl(self.__handle, SPI_IOC_RD_MODE, struct.pack("=B", Lepton.MODE)) ioctl(self.__handle, SPI_IOC_WR_MODE, struct.pack("=B", Lepton.MODE)) ioctl(self.__handle, SPI_IOC_RD_BITS_PER_WORD, struct.pack("=B", Lepton.BITS)) ioctl(self.__handle, SPI_IOC_WR_BITS_PER_WORD, struct.pack("=B", Lepton.BITS)) ioctl(self.__handle, SPI_IOC_RD_MAX_SPEED_HZ, struct.pack("=I", Lepton.SPEED)) ioctl(self.__handle, SPI_IOC_WR_MAX_SPEED_HZ, struct.pack("=I", Lepton.SPEED)) return self def __exit__(self, type, value, tb): self.__handle.close() @staticmethod def capture_segment(handle, xs_buf, xs_size, capture_buf): messages = Lepton.ROWS iow = _IOW(SPI_IOC_MAGIC, 0, xs_size) ioctl(handle, iow, xs_buf, True) while (capture_buf[0] & 0x000f) == 0x000f: # byteswapped 0x0f00 ioctl(handle, iow, xs_buf, True) messages -= 1 # NB: the default spidev bufsiz is 4096 bytes so that's where the 24 message limit comes from: 4096 / Lepton.VOSPI_FRAME_SIZE_BYTES = 24.97... # This 24 message limit works OK, but if you really need to optimize the read speed here, this hack is for you: # The limit can be changed when spidev is loaded, but since it is compiled statically into newer raspbian kernels, that means # modifying the kernel boot args to pass this option. This works too: # $ sudo chmod 666 /sys/module/spidev/parameters/bufsiz # $ echo 65536 > /sys/module/spidev/parameters/bufsiz # Then Lepton.SPIDEV_MESSAGE_LIMIT of 24 can be raised to 59 while messages > 0: if messages > Lepton.SPIDEV_MESSAGE_LIMIT: count = Lepton.SPIDEV_MESSAGE_LIMIT else: count = messages iow = _IOW(SPI_IOC_MAGIC, 0, xs_size * count) ret = ioctl(handle, iow, xs_buf[xs_size * (60 - messages):], True) if ret < 1: raise IOError("can't send {0} spi messages ({1})".format(60, ret)) messages -= count def capture(self, data_buffer = None, log_time = False, debug_print = False, retry_reset = True): """Capture a frame of data. Captures 80x60 uint16 array of non-normalized (raw 12-bit) data. Returns that frame and a frame_id (which is currently just the sum of all pixels). The Lepton will return multiple, identical frames at a rate of up to ~27 Hz, with unique frames at only ~9 Hz, so the frame_id can help you from doing additional work processing duplicate frames. Args: data_buffer (numpy.ndarray): Optional. If specified, should be ``(60,80,1)`` with `dtype`=``numpy.uint16``. Returns: tuple consisting of (data_buffer, frame_id) """ start = time.time() if data_buffer is None: data_buffer = np.ndarray((Lepton.ROWS, Lepton.COLS, 1), dtype=np.uint16) elif data_buffer.ndim < 2 or data_buffer.shape[0] < Lepton.ROWS or data_buffer.shape[1] < Lepton.COLS or data_buffer.itemsize < 2: raise Exception("Provided input array not large enough") while True: Lepton.capture_segment(self.__handle, self.__xmit_buf, self.__msg_size, self.__capture_buf[0]) if retry_reset and (self.__capture_buf[20, 0] & 0xFF0F) != 0x1400: # make sure that this is a well-formed frame, should find line 20 here # Leave chip select deasserted for at least 185 ms to reset if debug_print: print("Garbage frame number reset waiting...") time.sleep(0.185) else: break self.__capture_buf.byteswap(True) data_buffer[:,:] = self.__capture_buf[:,2:] end = time.time() if debug_print: print("---") for i in range(Lepton.ROWS): fid = self.__capture_buf[i, 0, 0] crc = self.__capture_buf[i, 1, 0] fnum = fid & 0xFFF print("0x{0:04x} 0x{1:04x} : Row {2:2} : crc={1}".format(fid, crc, fnum)) print("---") if log_time: print("frame processed int {0}s, {1}hz".format(end-start, 1.0/(end-start))) # TODO: turn on telemetry to get real frame id, sum on this array is fast enough though (< 500us) return data_buffer, data_buffer.sum() |
Downloads
- Eclipse IDE and JTAG debugging setup | Link
- FlIR Lepton PureThermal with Python
- Android Development Source Code with APP | Link
- Pure Thermal 1 UVC Capture Examples
- PureThermal Version 1.2 Schematics / User Manual | PDF
- FLIR Lepton Interface Design Manual | PDF
- PureThermal 1 User Manual | PDF
- PureThermal 1 Schematics | PDF
- FLIR Lepton Installation Guide for Raspberry Pi Can be Found Here | Link
- FLIR Lepton Code Library for for Beaglebone Black | Link
- FLIR Lepton Code Library for STM Discovery | Link
- FLIR Lepton Code for STM32 Nucleo | Link
- FLIR Lepton Code Library for for AVR Arduino DUE | Link
- FLIR Lepton Code Library for Arduino | Link