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
相关产品推荐
相关产品推荐

