Mattm
Mattm

Reputation: 1

Four MLX90640 thermal cameras on 4 custom buses in Rasberry Pi 5B

I am quite new to Python. With help of GitHub copilot and some basic programming skills I am trying to run 4 thermal cameras at the same time with at least 4Hz frequency (Ideally 16Hz if possible).

I tried running 4 cameras via TCA9548A multiplexer but the max speed I get is only about 0.5Hz. This is not an option.

As alternative I found that I could create custom 4 buses (default I2C bus is taken by temperature sensor).

As an example I attached the config for bus 3 and further along an example of code for 1 camera. I created bus 3 using following config in config.txt in pi:

dtoverlay=i2c-gpio,bus=3,i2c_gpio_sda=16,i2c_gpio_scl=26

Using i2cdetect I can detect IR camera under 0x33 address on this bus.

The challenge is that when I initialize the cameras I don't get any data from them.

How can I proceed?

Code for 1 camera pull below

import time
import smbus2
import adafruit_mlx90640
import ctypes

class SMBusWrapper:
    def __init__(self, bus):
        self.bus = smbus2.SMBus(bus)
        self.locked = False

    def try_lock(self):
        if not self.locked:
            self.locked = True
            return True
        return False

    def unlock(self):
        self.locked = False

    def writeto(self, address, buffer, stop=True):
        if len(buffer) > 1:
            self.bus.write_i2c_block_data(address, buffer[0], list(buffer[1:]))
        elif len(buffer) == 1:
            self.bus.write_byte(address, buffer[0])
        else:
            # Handle empty buffer case gracefully
            self.bus.write_byte(address, 0)

    def readfrom_into(self, address, buffer, stop=True):
        chunk_size = 32  # Maximum block length for SMBus
        for i in range(0, len(buffer), chunk_size):
            chunk = self.bus.read_i2c_block_data(address, 0, min(chunk_size, len(buffer) - i))
            buffer[i:i + len(chunk)] = chunk

    def writeto_then_readfrom(self, address, buffer_out, buffer_in, out_start=0, out_end=None, in_start=0, in_end=None):
        if out_end is None:
            out_end = len(buffer_out)
        if in_end is None:
            in_end = len(buffer_in)
        self.writeto(address, buffer_out[out_start:out_end])
        self.readfrom_into(address, buffer_in[in_start:in_end])

# Initialize I2C bus 3 using SMBusWrapper
i2c_bus = SMBusWrapper(3)

# Function to scan I2C bus and check for devices
def scan_i2c_bus(bus):
    devices = []
    for address in range(128):
        try:
            bus.bus.read_byte(address)
            devices.append(address)
        except OSError:
            pass
    return devices

# Scan the I2C bus and print detected devices
detected_devices = scan_i2c_bus(i2c_bus)
print(f"Detected I2C devices: {[hex(device) for device in detected_devices]}")

# Function to initialize the sensor and handle errors
def initialize_sensor(bus):
    try:
        sensor = adafruit_mlx90640.MLX90640(bus)
        sensor.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_4_HZ
        print("Sensor initialized successfully")
        return sensor
    except ValueError as e:
        print(f"Error initializing sensor: {e}")
        return None

# Initialize the MLX90640 sensor on I2C bus 3
sensor = initialize_sensor(i2c_bus)

if sensor:
    try:
        frame_data = (ctypes.c_uint16 * 834)()  # Initialize frame_data with zeros
        while True:
            print("Getting frame data...")
            result = sensor._GetFrameData(ctypes.byref(frame_data))  # Pass frame_data by reference
            print("Frame data request result:", result)
            if result != 0:
                raise RuntimeError(f"Failed to get frame data: {result}")
            print("Frame data acquired.")
            print(f"Frame data length: {len(frame_data)}")
            print(f"Frame data content: {list(frame_data)[:10]}...")  # Print first 10 elements for brevity
            time.sleep(0.25)  # 4Hz acquisition rate
    except Exception as e:
        print(f"Error acquiring data: {e}")
else:
    print("Failed to initialize the sensor")

I get error below

Detected I2C devices: ['0x33']
Traceback (most recent call last):
  File "/home/mateusz/ThermalPi_data/ThermalPI/thermal_scripts/pull_one_camera.py", line 73, in <module>
    sensor = initialize_sensor(i2c_bus)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mateusz/ThermalPi_data/ThermalPI/thermal_scripts/pull_one_camera.py", line 64, in initialize_sensor
    sensor = adafruit_mlx90640.MLX90640(bus)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/mateusz/ThermalPi_data/ThermalPI/venv/lib/python3.11/site-packages/adafruit_mlx90640.py", line 97, in __init__
    self._ExtractParameters()
  File "/home/mateusz/ThermalPi_data/ThermalPI/venv/lib/python3.11/site-packages/adafruit_mlx90640.py", line 361, in _ExtractParameters
    self._ExtractAlphaParameters()
  File "/home/mateusz/ThermalPi_data/ThermalPI/venv/lib/python3.11/site-packages/adafruit_mlx90640.py", line 547, in _ExtractAlphaParameters
    alphaTemp[p] = SCALEALPHA / alphaTemp[p]
                   ~~~~~~~~~~~^~~~~~~~~~~~~~
ZeroDivisionError: float division by zero
(venv) (base) mateusz@mmpi:~/ThermalPi_data/ThermalPI $ 

Upvotes: 0

Views: 31

Answers (0)

Related Questions