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

pySerialTransfer双向通信异常:Python无法正确读取Arduino返回值

Python与Arduino双向串口通信不稳定问题排查

我编写了一个极简的Python与Arduino双向串口通信脚本:Python向Arduino发送整数,Arduino将该整数自增后通过串口返回。但运行时Python无法稳定读取自增后的正确值,仅能每隔多次尝试才读取到一次正确结果。以下是相关代码及控制台日志:

代码与日志

comm.py

from time import sleep
from pySerialTransfer import pySerialTransfer as txfer


class struct:
    control = 0

class receivestruct:
    status = 0


if __name__ == '__main__':
    try:
        testStruct = struct
        rstruct =receivestruct 
        link = txfer.SerialTransfer('COM7')
        
        link.open()
        sleep(2)
        
        counter = 0
    
        while True:
            sendSize = 0
            
            testStruct.control = counter
            
            sendSize = link.tx_obj(testStruct.control, start_pos=sendSize)
            
            link.send(sendSize)

            print('sent')
            #sleep(0.5)

            read_correctly = False
            while (read_correctly == False):
                try:
                    if not (link.available()):
                        pass

                    recSize = 0
                    # this section returns errors with can't read str as int 
                    rstruct.status = link.rx_obj(obj_type='i', start_pos=recSize)
                    counter = rstruct.status
                    recSize += txfer.STRUCT_FORMAT_LENGTHS['i']

                    print(rstruct.status)
                    read_correctly = True
                except:
                    pass

        
    except KeyboardInterrupt:
        link.close()

arduino.ino

#include "SerialTransfer.h"


SerialTransfer myTransfer;

uint32_t rcontrol;

uint32_t control;

void setup()
{
  Serial.begin(115200);
  myTransfer.begin(Serial);
}

void loop()
{
  if(myTransfer.available())
  {
    // use this variable to keep track of how many
    // bytes we've processed from the receive buffer
    uint16_t recSize = 0;

    recSize = myTransfer.rxObj(rcontrol, recSize);


    control = rcontrol + 1;
    uint16_t sendSize = 0;


    sendSize = myTransfer.txObj(control, sendSize);

    myTransfer.sendData(sendSize);
    
  }
}

控制台日志

115
sent
115
sent
116
sent
116
sent
116
sent
116
sent
116
sent
116
sent
116
sent
116
sent
116
sent
117
sent
117
sent
117
sent
117
sent
117
sent
117
sent
117
sent
117
sent
117
sent
118
sent
118
sent
118
sent
118
sent
118
sent
118
sent
118
sent
118
sent
118
sent
119
sent
119
sent
119
sent
119
sent
119
sent
119
sent
119
sent
119
sent

问题原因分析

  1. 数据类型不匹配:Python端使用obj_type='i'(对应有符号32位int),但Arduino端定义的是uint32_t(无符号32位整数),类型不匹配会导致数据解析错误,出现无法读取或读取值异常的情况。
  2. 无等待强制读取:Python发送数据后未等待Arduino处理并返回,立刻进入读取循环。串口通信存在延迟,此时缓存中可能没有新数据或残留旧数据,直接读取会触发异常,而宽泛的except: pass会跳过错误,导致重复读取旧缓存值。
  3. 异常处理过于宽泛:捕获所有异常且不做任何处理,掩盖了数据解析失败、串口读取异常等真实问题,无法及时排查错误根源。
  4. 未清空错误缓存:当读取出现异常时,未清空串口接收缓存,残留的错误数据会被后续循环重复读取,导致多次返回旧值。

修正方案

修正后的comm.py

from time import sleep
from pySerialTransfer import pySerialTransfer as txfer


if __name__ == '__main__':
    try:
        link = txfer.SerialTransfer('COM7')
        link.open()
        sleep(2)
        
        counter = 0
    
        while True:
            # 发送无符号32位整数,与Arduino端类型匹配
            send_size = link.tx_obj(counter, obj_type='I')
            link.send(send_size)
            print(f'sent: {counter}')
            
            # 等待Arduino返回数据,避免读空或旧缓存
            while not link.available():
                sleep(0.01)
            
            # 读取数据并处理可能的异常
            try:
                rec_size = 0
                received_val = link.rx_obj(obj_type='I', start_pos=rec_size)
                counter = received_val
                print(f'received: {received_val}')
            except Exception as e:
                print(f'读取错误: {e}')
                link.clear()  # 清空缓存,避免残留错误数据

    except KeyboardInterrupt:
        link.close()

修正后的arduino.ino

#include "SerialTransfer.h"

SerialTransfer myTransfer;
uint32_t rcontrol;
uint32_t control;

void setup()
{
  Serial.begin(115200);
  myTransfer.begin(Serial);
}

void loop()
{
  if(myTransfer.available())
  {
    uint16_t recSize = 0;
    recSize = myTransfer.rxObj(rcontrol, recSize);
    
    control = rcontrol + 1;
    uint16_t sendSize = 0;
    sendSize = myTransfer.txObj(control, sendSize);
    
    myTransfer.sendData(sendSize);
    // 等待数据发送完成,避免截断
    while(myTransfer.bytesSent() < sendSize) {}
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 00:07:20