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

Python while True循环运行久后变慢、方位角差值恒为0问题排查

问题根本诱因

两个故障现象对应独立的根因,和你描述的“初始运行正常、数分钟后异常”特征完全匹配:

  • 程序逐渐变慢、单步耗时达数秒:核心原因是串口写缓冲区溢出阻塞。pyserial默认采用阻塞写模式,且未配置写超时阈值,如果Arduino端串口读取速度跟不上Python端发送速度,数据会在发送缓冲区持续堆积,数分钟后缓冲区被完全填满。后续每次执行port.write()时,程序会强制暂停,等待缓冲区释放足够空闲空间才能写入新数据,阻塞时长从数秒到数十秒不等。程序刚启动时缓冲区为空,因此不会触发阻塞。
  • 方位角差值恒为0:由两个逻辑bug共同导致:
    • 精度过早截断:你在拿到方位角原始浮点值后第一时间用int()强转,直接舍弃了小数部分。近地卫星1秒内的方位角变化量经常小于1度,两次浮点值差小于1度时,强转整数后数值完全相等,差值自然为0。
    • 未处理循环边界:方位角是0~360度的循环值,当目标从359度移动到1度时,直接做差会得到-358的错误结果,即使精度足够,跨边界场景下计算值也完全不符合实际运动逻辑。
修复方案

按以下步骤调整代码即可解决全部问题:

  1. 串口初始化时增加写超时配置,启动前清空残留缓冲区,从根源避免无限阻塞:
import serial
# 串口初始化,根据实际硬件参数修改端口、波特率
port = serial.Serial(
    port='COMx',
    baudrate=9600,
    write_timeout=1 # 写操作最长阻塞1秒,防止程序卡死
)
# 启动时清空缓冲区残留的无效数据
port.reset_input_buffer()
port.reset_output_buffer()
  1. 调整计算逻辑:采样阶段全程保留浮点精度,差值计算时补全360度边界处理,所有数值计算完成后再转成需要的整数格式,避免提前截断精度。
  2. 调整循环时序:校准采样间隔,抵消代码执行、串口发送带来的时间漂移,保证两次位置采样的间隔稳定为1秒。

修正后的完整循环代码如下:

import time
import math
from datetime import datetime

degrees_per_radian = 180.0 / math.pi
# 以下home、iss对象初始化逻辑和你原有代码保持一致即可
# home = ephem.Observer()
# iss = ephem.readtle(...)

while True:
    loop_start_ts = time.time()
    # 第一次位置采样
    home.date = datetime.utcnow()
    iss.compute(home)
    el_prev = iss.alt * degrees_per_radian
    az_prev = iss.az * degrees_per_radian
    print(f"prev az: {az_prev:.2f}, prev el: {el_prev:.2f}")

    # 保证两次采样间隔为1秒
    time.sleep(1)

    # 第二次位置采样
    home.date = datetime.utcnow()
    iss.compute(home)
    el_curr = iss.alt * degrees_per_radian
    az_curr = iss.az * degrees_per_radian

    # 正确计算方位角差值,处理0/360度循环边界
    az_diff = az_curr - az_prev
    if az_diff > 180:
        az_diff -= 360
    elif az_diff < -180:
        az_diff += 360

    # 所有计算完成后再转整数,避免精度损失
    az_send = int(az_diff)
    el_send = int(el_curr)
    print(f"curr az: {az_curr:.2f}, 1s az change: {az_diff:.2f}")

    # 串口发送增加超时处理,避免缓冲区堆积
    str_pos = f"{az_send};{el_send}\n"
    try:
        port.write(str_pos.encode())
        port.flush()
        print("data transmitted!")
    except serial.SerialTimeoutException:
        port.reset_output_buffer()
        print("serial write timeout, buffer reset")
    print("__________________")

    # 校准循环总时长,保证采样间隔稳定
    loop_cost = time.time() - loop_start_ts
    if loop_cost < 1:
        time.sleep(1 - loop_cost)
额外优化点
  • 确认Arduino端串口读取逻辑的波特率、数据解析格式和Python端完全匹配,解析错误会导致读取速度下降,反向拖慢串口发送链路。
  • 长期运行时可以删除冗余的print调试语句,控制台大量持续输出也会带来额外的性能开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 06:06:26