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

使用python-can读取PCAN总线数据始终返回相同值的问题

解决PCAN总线Python读取数据不更新的问题

看起来你遇到的核心问题是总线接收缓存里的旧消息没有被清空,导致代码一直在重复读取首次获取的数据,而不是最新的总线消息。PCAN-View能看到数据变化,说明硬件和总线通信是正常的,问题出在代码的消息读取逻辑上。

问题原因分析

你当前使用bus.recv(None)时,None参数表示无限等待直到收到一条消息。但python-can的PCAN接口默认会缓存总线收到的消息——如果设备在启动时发送了初始数据(比如[00 03]),这条消息会被存在缓存里,后续即使总线有新的更新数据,只要缓存里还有未读取的旧消息,recv()就会先返回旧的,而不是等待新消息。这就是数据始终不更新的根本原因。

解决方案

下面提供两种可靠的解决方法,你可以根据需求选择:

方法1:主动清空缓存,只保留最新消息

在每次循环中,先快速读取缓存里所有的旧消息并丢弃,只保留最后一条最新的消息进行处理:

import can
from time import sleep

def main():
    bus = can.interface.Bus(bustype='pcan', channel='PCAN_USBBUS1', bitrate=500000)
    try:
        while True:
            latest_msg = None
            # 循环读取所有缓存中的消息,直到没有新消息(设置10ms超时)
            while True:
                msg = bus.recv(0.01)
                if msg is None:
                    break
                latest_msg = msg
            
            # 处理最新消息
            if latest_msg:
                arb_id = latest_msg.arbitration_id
                if arb_id in [0x1B2, 0x1B3, 0x1B4, 0x1B5]:
                    print(latest_msg)
            else:
                print("Nothing received this time")
            
            sleep(0.2)
    except KeyboardInterrupt:
        print("Program Exited")
    except can.CanError:
        print("Message NOT sent")
    finally:
        bus.shutdown()

if __name__ == '__main__':
    main()

方法2:使用AsyncBufferedReader监听最新消息

python-can提供了AsyncBufferedReader监听器,它会异步接收总线消息,确保你每次拿到的都是最新的消息,无需手动处理缓存:

import can
from can import AsyncBufferedReader
from time import sleep

def main():
    bus = can.interface.Bus(bustype='pcan', channel='PCAN_USBBUS1', bitrate=500000)
    # 创建异步读取器
    reader = AsyncBufferedReader()
    # 将读取器绑定到总线,自动接收消息
    notifier = can.Notifier(bus, [reader])
    
    try:
        while True:
            # 等待0.2秒获取最新消息(和你的原sleep时间一致)
            msg = reader.get_message(0.2)
            if msg:
                arb_id = msg.arbitration_id
                if arb_id in [0x1B2, 0x1B3, 0x1B4, 0x1B5]:
                    print(msg)
            else:
                print("Nothing received this time")
    except KeyboardInterrupt:
        print("Program Exited")
    finally:
        # 停止监听器和总线
        notifier.stop()
        bus.shutdown()

if __name__ == '__main__':
    main()

为什么原代码无效?

你尝试过发送消息、调用can.Listener().stop(),但这些操作都没有触及核心问题:缓存里的旧消息没有被清理。原代码每次recv()都会优先读取缓存中最早的未处理消息,而不是等待新的总线数据,所以即使PCAN-View显示新数据,你的代码还是在重复读旧数据。

这两种方法都能确保你获取到总线的最新消息,测试一下应该就能解决你的问题了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:28:52