通过串口从Python向Arduino传输浮点数时数据异常的高效解决办法
问题描述
向Arduino传输1440个浮点数时出现部分数值错误,考虑过添加延迟解决,但希望找到更高效的传输方案。
Python代码片段
arduino = serial.Serial(port=args.port, baudrate=115200, timeout=5000) print(feature[0:50]) # Send each float in a feature for num in feature: arduino.write(bytes(str("%f" % num), "ascii") + bytes("\n", "ascii")) # Receive the input back recv_features = [] for _ in range(len(feature)): recv = arduino.read_until() recv_features.append(float(recv.decode(encoding="ascii"))) print(recv_features[0:50])
Arduino代码片段
#define INPUT_LEN 10 char X_test_byteArr[INPUT_LEN]; float data[1440]; void setup() { Serial.begin(115200); Serial.setTimeout(5000); } void loop() { size_t num_read; // Receive every input as string, convert to float while (Serial.available()==0) {} for (int i = 0; i < 1440; i++) { // Wait for input data while (Serial.available()==0) {} // Read input string num_read = Serial.readBytesUntil('\n', X_test_byteArr, INPUT_LEN); X_test_byteArr[num_read] = '\0'; // Convert input string to float data[i] = float(atof(X_test_byteArr)); } for (int i = 0; i < 1440; ++i) { Serial.println(data[i]); } }
数据对比
发送的前50个数据
[-1.12, 0.32, -0.48, -0.84, 3.01, 0.03, -0.80, 0.23, -0.69, 1.02, 0.55, 0.24, -0.13, -0.55, -1.42, 4.20, 0.05, 0.04, 0.29, -0.45, -0.12, 0.21, -0.81, -0.07, 1.03, -0.09, -0.01, 0.38, -0.99, 1.59, 0.21, -0.18, 0.03, 0.39, 1.38, 0.76, -0.15, -0.25, 0.23, -0.02, 0.00, -0.48, -0.27, 0.19, -0.09, -1.77, 0.24, -0.52, -0.08, 0.43]
接收的前50个数据
[-1.12, 0.32, -0.48, -0.84, 3.01, 0.03, -0.80, 0.23, -0.69, 1.02, 0.55, 0.24, -0.13, -0.55, -1.42, 4.20, 0.05, 0.04, 0.29, -0.45, -0.12, 0.21, -0.81, -0.07, 1.03, -0.09, -0.01, 37987, 0.00, -0.99, 59294, 0.21, -0.18, 0.03, 0.39, 1.38, 0.76, 0.00, -0.15, -0.25, 22918, 0.00, -0.02, 0.00, -0.48, -0.27, 19308, -0.09, -1.77, 0.24]
问题分析与解决方案
错误原因
- 缓冲区溢出:Arduino端
INPUT_LEN=10的缓冲区过小,当浮点数的ASCII字符串长度超过10时,readBytesUntil会截断数据,残留的旧缓冲区内容被atof解析成错误的大整数。 - 同步问题:Python连续发送数据时,Arduino的
while(Serial.available()==0)可能在数据未完全接收时就开始读取,导致字符串不完整。
高效替代方案
1. 二进制传输(最快最可靠)
跳过ASCII转换,直接传输浮点数的二进制字节,速度比ASCII快3-5倍,且无解析错误:
- Python端
import struct # 将float列表打包为小端模式的二进制字节流(每个float占4字节) byte_data = b''.join([struct.pack('<f', num) for num in feature]) arduino.write(byte_data) # 接收时解包二进制数据 recv_bytes = arduino.read(len(feature)*4) recv_features = [struct.unpack('<f', recv_bytes[i:i+4])[0] for i in range(0, len(recv_bytes), 4)]
- Arduino端
float data[1440]; void setup() { Serial.begin(115200); Serial.setTimeout(5000); Serial.setBufferSize(8192); // 增大串口缓冲区避免溢出 } void loop() { // 等待所有数据到达(1440个float共5760字节) if (Serial.available() >= 1440*4) { Serial.readBytes((char*)data, 1440*4); // 回传二进制数据 Serial.write((char*)data, 1440*4); } }
2. 优化ASCII传输(保留文本格式)
如果必须用ASCII传输,解决核心问题:
- 增大缓冲区:将
INPUT_LEN改为15,足够容纳带符号的长浮点数ASCII字符串(如-123.456789) - 加入校验机制:每个数据包开头加
START标记,结尾加END标记,确保数据完整接收 - 批量传输:Python一次性发送所有数据(用分隔符分隔),Arduino一次性读取后拆分解析,减少往返次数
3. 硬件与配置优化
- 确保Python和Arduino的波特率完全一致
- 用
Serial.setBufferSize()增大Arduino的串口缓冲区,避免数据溢出 - 减少回传次数:比如只回传校验值(如所有浮点数的总和),而不是全部数据,节省传输时间
内容的提问来源于stack exchange,提问作者PriceWang
相关产品推荐
相关产品推荐

