You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Raspberry Pi Pico串口缓冲区过小及类型错误问题求助

Raspberry Pi Pico + ADXL345 + MR24HPB1 项目报错排查

问题背景

使用Raspberry Pi Pico搭配ADXL345加速度计与MR24HPB1雷达传感器开发项目,核心逻辑为检测到人体移动且特定物体静止时执行操作。目前出现报错,怀疑与UART缓冲区大小有关,但无法确定原因,已尝试增大UART的txbuf和rxbuf参数,问题依旧。

报错信息

MPY: soft reboot
buffer too small
Traceback (most recent call last):
File "<stdin>", line 63, in <module>
TypeError: unsupported types for le: 'int', 'NoneType'

报错触发于代码行:condition2 = 31 <= data_as_float <= 100

完整代码

from machine import UART, Pin, I2C
from struct import unpack
from neopixel import NeoPixel


def low_pass_filter(prev_value, new_value, alpha):
    """This function applies a low pass filter """
    return alpha * prev_value + (1 - alpha) * new_value

def get_data_as_float(data_as_hex):
    """This function takes a hexadecimal string and returns it as a float"""

    try:
        byte_array = bytes.fromhex(data_as_hex)
        float_value = unpack('f', byte_array)[0]
        return float_value

    except Exception as e:
        print(e)


# Constants
ADXL345_ADDRESS = 0x53
ADXL345_POWER_CTL = 0x2D
ADXL345_DATA_FORMAT = 0x31
ADXL345_DATAX0 = 0x32

# Instantiate sensors
uart = UART(1, 9600, bits=8, parity=None, stop=1, tx=Pin(4), rx=Pin(5))
i2c = I2C(0, sda=Pin(8), scl=Pin(9), freq=400000)
i2c.writeto_mem(ADXL345_ADDRESS, ADXL345_POWER_CTL, bytearray([0x08]))
i2c.writeto_mem(ADXL345_ADDRESS, ADXL345_DATA_FORMAT, bytearray([0x0B]))
led = NeoPixel(Pin("GP0"), 8)

# Variables for low pass
start_value = 0
alpha = 0.99

# Thresholds for accelerometer
x_thresh, y_thresh, z_thresh = 0.05, 0.5, 2.5

while True:
    # Get and process message
    message = uart.read()
    if message is not None:
        message = message.hex()
        function_code = message[6:8]
        address1 = message[8:10]
        address2 = message[10:12]
        data = message[12:-4]
        data_as_float = get_data_as_float(data)
        
        # Get and process xyz
        xyz = i2c.readfrom_mem(ADXL345_ADDRESS, ADXL345_DATAX0, 6)
        x, y, z = unpack('<3h', xyz)
        x, y, z = abs(x), abs(y), abs(z)
        filtered_x = low_pass_filter(start_value, x, alpha)
        filtered_y = low_pass_filter(start_value, y, alpha)
        filtered_z = low_pass_filter(start_value, z, alpha)
        
        # Conditions
        condition1 = function_code == "04" and address1 == "03" and address2 == "06"
        condition2 = 31 <= data_as_float <= 100
        condition3 = x < x_thresh and y < y_thresh and z < z_thresh
        
        if condition1 and condition2 and condition3:
            print("Yay")

排查与解决思路

1. 核心报错原因定位

TypeError: unsupported types for le: 'int', 'NoneType' 说明data_as_float的值为None,导致无法和整数31/100进行比较。而data_as_float为None的直接原因是get_data_as_float函数在捕获异常时仅打印错误,未返回有效数值,Python默认返回None。

2. 异常触发的深层原因

  • UART数据截断:buffer too small提示UART接收缓冲区不足,uart.read()获取到的雷达响应帧不完整,截取的data字段长度不符合float类型的4字节要求(对应8位十六进制字符串),导致转换时抛出异常。
  • 数据格式不匹配:MR24HPB1返回的Modbus数据帧不符合预期解析逻辑,截取的data字段不是有效的float十六进制格式。

3. 具体修复步骤

(1)修复get_data_as_float函数异常处理

给函数添加默认返回值,避免None参与后续逻辑判断,同时增加数据长度校验:

def get_data_as_float(data_as_hex):
    """This function takes a hexadecimal string and returns it as a float"""
    try:
        # float类型需要4字节,对应8位十六进制字符串,先校验长度
        if len(data_as_hex) != 8:
            print(f"Invalid data length: {len(data_as_hex)}")
            return -1
        byte_array = bytes.fromhex(data_as_hex)
        float_value = unpack('f', byte_array)[0]
        return float_value
    except Exception as e:
        print(f"Data conversion error: {e}")
        return -1

(2)优化UART数据接收逻辑

  • 固定帧长读取:查MR24HPB1手册确认Modbus响应帧的固定长度,用uart.read(固定长度)代替uart.read(),确保获取完整帧。
  • 增大缓冲区并设置超时:初始化UART时明确设置更大的缓冲区和读取超时,减少数据截断概率:
uart = UART(1, 9600, bits=8, parity=None, stop=1, tx=Pin(4), rx=Pin(5), rxbuf=256, txbuf=256, timeout=100)
  • 添加帧头校验:处理消息前先校验Modbus帧的起始地址(比如MR24HPB1默认地址为0x01,对应十六进制"01"),过滤无效帧:
if message is not None:
    message_hex = message.hex()
    if not message_hex.startswith("01"):
        print("Invalid frame header")
        continue
    # 后续解析逻辑...

(3)修正加速度计数据处理逻辑

ADXL345输出的是16位原始整数,需要转换为实际加速度值(单位g),当前代码直接用原始整数和阈值(0.05等)比较逻辑错误:

# ADXL345设置为±16g量程时,灵敏度为3.9mg/LSB,即1单位=0.0039g
sensitivity = 0.0039
xyz = i2c.readfrom_mem(ADXL345_ADDRESS, ADXL345_DATAX0, 6)
x, y, z = unpack('<3h', xyz)
# 转换为实际加速度值(g)
x_g = abs(x * sensitivity)
y_g = abs(y * sensitivity)
z_g = abs(z * sensitivity)
# 滤波使用转换后的值
filtered_x = low_pass_filter(start_value, x_g, alpha)
filtered_y = low_pass_filter(start_value, y_g, alpha)
filtered_z = low_pass_filter(start_value, z_g, alpha)
# 条件判断用转换后的g值
condition3 = x_g < x_thresh and y_g < y_thresh and z_g < z_thresh

(4)添加调试日志

在关键步骤打印数据,方便定位问题:

print(f"Received frame: {message_hex}")
print(f"Data field: {data}, length: {len(data)}")
print(f"Converted float: {data_as_float}")
print(f"Accel values (g): x={x_g}, y={y_g}, z={z_g}")

总结

当前报错的直接原因是data_as_float为None,根源是UART数据不完整或解析错误,同时加速度计数据处理存在逻辑漏洞。按上述步骤修复后,可解决当前报错并提升项目稳定性。

内容的提问来源于stack exchange,提问作者Christian Persson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 07:55:35