蓝牙接收Arduino JSON payload遇JSONDecodeError问题求助
Arduino蓝牙传输JSON到Python的解析问题及解决方法
问题背景
我正从Arduino微控制器传输JSON payload,并用Python脚本接收,脚本代码如下:
import bluetooth #pybluez import json sensor_address = "18:D9:31:YY:C7:4A" socket = bluetooth.BluetoothSocket(bluetooth.RFCOMM) socket.connect((sensor_address, 1)) buffer = "" print("Listening...") while True: data = socket.recv(1024) buffer += str(data, encoding='ascii') print(buffer) # used to check json payload try: data = json.loads(buffer) print("Received:", data) buffer = "" except json.JSONDecodeError as e: print(e) continue
接收时,try语句执行前的buffer内容为连续拼接的JSON对象:
{"a_x":957.5195,"a_y":-0.488281,"a_z":315.918,"g_x":-0.625954,"g_y":-1.305344}{"a_x":961.914,"a_y":-1.953125,"a_z":297.8516,"g_x":-2.816794,"g_y":2.572519}{"a_x":964.8437,"a_y":3.417969,"a_z":303.2227,"g_x":-1,"g_y":0.374046}
但脚本反复输出Expecting value: line 1 column 1 (char 0)错误,try块内代码始终无法执行。疑问:为何完整payload接收后代码仍不执行?能否用正则表达式从字符串中提取有效payload?
错误原因
- 连续拼接的JSON不是合法格式:
json.loads()只能解析单个JSON值(对象、数组等),而你收到的是多个JSON对象直接拼接(无逗号分隔,也没有外层数组包裹),整个buffer内容属于非法JSON,必然解码失败。 - 流式读取的不确定性:蓝牙串口的
recv()是流式读取,每次收到的可能是部分JSON片段,或者多个完整JSON+部分片段的混合,导致buffer内容始终无法被json.loads()正常解析。
解决方案
方法1:修改Arduino输出格式(最优方案)
直接在Arduino发送JSON时,给每个JSON对象添加分隔符,让Python端可以轻松分割:
- 方案A:每个JSON对象末尾添加换行符
\n,Python端按行分割处理,每次读取一行完整的JSON。 - 方案B:将多个JSON对象包裹成一个JSON数组发送(如
[{"a_x":...}, {"a_x":...}]),但需注意批量发送或实时处理的节奏控制。
方法2:Python端用正则提取完整JSON对象
如果无法修改Arduino代码,可通过正则表达式从buffer中匹配所有完整的JSON对象,处理后移除已解析的部分,保留剩余的不完整片段等待后续拼接。
修改后的Python脚本示例:
import bluetooth # pybluez import json import re sensor_address = "18:D9:31:YY:C7:4A" socket = bluetooth.BluetoothSocket(bluetooth.RFCOMM) socket.connect((sensor_address, 1)) buffer = "" # 匹配无嵌套的完整JSON对象的正则 json_obj_pattern = re.compile(r'\{[^{}]*\}') print("Listening...") while True: data = socket.recv(1024) buffer += str(data, encoding='ascii') # 提取所有完整的JSON对象 matches = json_obj_pattern.findall(buffer) if matches: for match in matches: try: parsed_data = json.loads(match) print("Received:", parsed_data) except json.JSONDecodeError as e: print(f"解析单个JSON失败: {e}") # 移除已处理的完整JSON,保留剩余的不完整片段 buffer = buffer[len(''.join(matches)):]
正则说明
\{[^{}]*\}:匹配以{开头、}结尾,中间不含{}的字符串,适用于无嵌套结构的JSON对象(你的数据刚好符合该场景)。如果涉及嵌套JSON,建议使用专门的流式JSON解析库(如ijson)来处理更复杂的情况。
内容的提问来源于stack exchange,提问作者John Harrington
相关产品推荐
相关产品推荐

