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

Discussão em 'Python' iniciado por Stack, Janeiro 4, 2025.

  1. Stack

    Stack Membro Participativo

    I hope someone can help. 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.

    Can you help me figure this out?

    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:eek:ut_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 $

    Continue reading...

Compartilhe esta Página