【CAN信号解析】使用python-can/cantools解析CAN数据

本文介绍了如何使用python-can和cantools库解析CAN消息。内容包括python-can库的使用,如BLFReader读取CAN数据,以及cantools解析DBC文件获取信号的物理值。还提到解析ASC数据并保存为CSV格式,以及根据DBC解析CAN信号和雷达MF4数据。
摘要由CSDN通过智能技术生成

1. 如何解析CAN消息

关于CAN的基础知识,可阅读如下链接:

  1. CAN协议详解
  2. CAN消息解析

此部分参考自:https://zhuanlan.zhihu.com/p/635594421

1.1 简介

用python分析asc,blf等格式数据,python-can这个包是必备的cantools这个包虽然理论上非必须,但用它处理起来更方便。另外cantools这个包本身依赖python-can,所以直接装个cantools就能直接上手干了。

pip install python-can
pip install cantools

另外,要分析asc, blf格式的数据,还得需要相应的数据库文件,也就是.dbc.arxml文件。DBC(Database Container)是一种CAN数据定义文件,用于描述车辆网络系统中的消息、信号和节点之间的关系和通信规则。在Python中,我们可以使用第三方库cantools来读取和解析DBC文件,以便在开发过程中使用。

下面是以blf格式数据为例展示解析方法,asc格式数据类似。

1.2 python-can库使用

官网的说法,python-can这个工具非常强大,不仅能离线的分析CAN数据,还能通过在线的方式与Vector工具箱、SocketCAN、PCAN等主流工具直接联动,把在线数据灌入python里进行在线运算与分析,只要写一下配置文件就行

如果是离线分析CAN数据的话,这个工具也是简单到离谱:python-can直接提供一个.BLFReader函数(或.ASCReader(asc_path)),输入blf/asc文件名,直接输出结构化的CAN数据,简单粗暴。

import can

blf_data = can.BLFReader("log1.blf")
#asc_data = can.ASCReader("xxx.asc")

for msg in blf_data:
    print(msg)

在这里插入图片描述
以上代码中,blf_data = can.BLFReader(...)实际上是建立一个can.BLFReader类,本身是不怎么耗时的。
下面的for循环实际上是调用的BLFReader类的__iter__方法,得到的msg是一个can.message类。由于can.message类重写了__str__方法,因此我们在调用print(msg)时,就会自动把message里的内容格式化输出。格式化输出的格式和Vector工具箱中的Trace几乎完全一样,因此即使用惯了Vector工具箱的人看起来也毫无压力。

更细化的,我们可以翻到can.message类__str__方法的实现代码,具体看一下我们print(msg)时,print出的究竟是什么东西。

我们在print(msg)时,输出格式里从左到右分别是

  • 这条msg的时间戳
  • 这条msg的can_id
  • 这条msg的属性(比如是否是canfd帧、是否是错误帧、是rx还是tx帧等等)
  • 这条msg的长度(也就是dlc)
  • 以16进制格式输出的raw data
  • 这条msg的can channel

由于我们没有用dbc或arxml文件去解析msg里的数据,因此也只能打印出raw data,打印不出来具体的信号值

另外,由于msg本身就是一个can.message类,因此我们也可以手动取到它的各种属性,比如:
在这里插入图片描述

比较常用的有:

  • msg.channel —— channel,取决于录制blf时的channel mapping
  • msg.timestamp —— 录制blf时记录的本条数据时间戳
  • msg.arbitration_id —— can id,或者叫frame id
  • msg.data —— bytearray格式的raw data

raw data如果直接打印的话,默认是按bytearray格式打印的。比如,我们可以筛选出channel=2,id=0x51的数据帧,打印出它们的raw data:

import can

blf_data = can.BLFReader("log1.blf")

for msg in blf_data:
    if msg.channel == 2 and msg.arbitration_id == 0x51:
        print(msg.data)

在这里插入图片描述
更进一步的,如果我们知道相应的数据帧中的每一位的定义,也可以自己筛出我们需要的信号的物理值

比如这里的channel=2,id=0x51的数据帧,我们通过其他工具(比如Vector Autosar Explorer)翻到其内部定义,可以看到它第2个byte中的后4个bit,以及第3个byte中的第4-6个bit都是某个有物理意义的值
在这里插入图片描述
然后我们就可以按需把这个物理值取出来:

import can

blf_data = can.BLFReader("log1.blf")

for msg in blf_data:
    if msg.channel == 2 and msg.arbitration_id == 0x51:
        print(msg.timestamp, "\t", msg.data[1] & 0b1111, "\t", (msg.data[3] >> 2) & 0b111)

在这里插入图片描述
这里需要用到的就是>>移位运算以及&按位与运算,可以精准的取到某个byte中的某几个bit的值

实际上,第2个byte中的后4个bit是这条信号的Rolling Counter第3个byte中的第4-6个bit某个功能当前的状态,打印出来的值都符合预期。

实际我们没必要这样自己通过位运算去取各种物理值,可以通过cantools库读取 .dbc或.arxml报文格式定义文件,自动解析出我们想要的信号值!具体看下面介绍。

2. python-can库介绍

仅仅使用python-can工具的话,我们其实就可以精准的在blf中取到任何一个signal去分析了,但是需要我们知道每个signal位于哪个数据帧中哪个byte里的哪个bit,还得自己写移位和按位与,非常麻烦。为了避免这种麻烦,可以用cantools工具。

2.1 完整解析流程

  1. 通过本地的example.arxmlxxx.dbc文件,构建一个database(是一个can.Database类)。这里的本地文件支持dbc、arxml、kcd、cdd等多种格式

  2. 通过上一节所述的python-can工具包,读取blf或asc数据文件,并筛选出channel=2,id=0x51的数据帧(或for循环遍历blf_data或asc_data 读取所有帧信号值);

  3. 把筛选出的数据帧的raw data扔给数据库,使其“解包”出有意义的物理值。

2.2 简单示例

decode_message()这个函数接收两个必要的入参:

  • 数据帧的can id
  • 以及bytes类型的raw data

另外还有一些可选参数(比如我这里指定的decode_choices指的是使用信号的symbol还是num),可选参数可以参考cantools的官方说明文档,不过它这个说明文档写的比较乱。

这样得到的signal_values其实是一个字典(type(signal_values)返回的是<class ‘dict’>),字典的key是信号名称,字典的value是信号的物理值

因此,我们就可以直接取到特定名称的信号,而不需要手动写移位和按位与从raw data里取值:

import can, cantools

database = cantools.db.load_file("example.arxml")
blf_data = can.BLFReader("log1.blf")

for msg in blf_data:
    if msg.channel == 2 and msg.arbitration_id == 0x51:
        signal_values = database.decode_message(0x51, msg.data, decode_choices=False)
        print(msg.timestamp, signal_values["xxxRC"])

在这里插入图片描述
这里的“xxxRC”就是第一节中信号的Rolling Counter(当然真实信号名不叫这玩意,规避一下保密风险)。可以看到通过字典+[key]的形式就能直接取到信号物理值。不过cantools工具只会无脑把信号物理值转成float型变量(即使它本身是int),把信号拎出来做比较或做进一步分析的时候要注意一下。

3. 总结与坑

用python解析blf的好处就是解出来的信号可以无缝衔接诸

### 回答1: Python 是一种高级编程语言,可用于许多不同的应用程序开发。在汽车制造业中,控制通讯网络(CAN)是汽车电子系统中的一种基本通信方式,而 Python 支持使用 Pcan-USB 设备通过 CAN 通信协议进行数据传输。peak 是一种基于 CAN 的通信协议,可以在汽车电子系统中使用。因此,Python 可以使用 peak 来收发 CAN 报文使用 Python 发送 CAN 报文需先安装 Pcan 模块。 Pcan 模块是一个 python 库,依赖于 PCAN-USB 接口设备。使用 Pcan 模块,能够实现对 CAN 总线的控制和数据传输。 在 Python使用 Pcan 模块,具体步骤如下: 1.引入 Pcan 模块库 import can from can.bus import BusState 2.创建 Pcan 对象并指定 Pcan 设备位置 can_bus = can.interface.Bus(bustype=BUSTYPE, channel=CHANNEL, bitrate=BITRATE) 3.创建 CAN 报文对象并定义要发送的数据和消息 ID can_msg = can.Message(arbitration_id=MSG_ID, is_extended_id=False,data=[0x01, 0x02, 0x03], is_fd=False) 4.发送 CAN 报文 can_bus.send(can_msg) 在 Python 中接收 CAN 报文的方法与发送类似。只需要定义一个接收函数并调用接收函数即可。具体如下: 1. 定义 CAN 报文接收函数 def receive_can_msg(can_bus): msg = can_bus.recv(timeout=1) if msg is None: return else: print("Received message: ", msg) 2. 调用 CAN 报文接收函数 receive_can_msg(can_bus) 总的来说,Python 是一种非常灵活的编程语言,可以很方便地处理 CAN 总线通讯数据使用 Pcan 模块,将能够在 Python 程序中轻松读取和发送 CAN 报文,进而实现与汽车电子控制系统的连接和信息交换。 ### 回答2: Python是一种高级编程语言,具有易学、易用和灵活的特点,被广泛应用于数据科学、Web 开发、机器学习等领域。同时,Python也可以用于汽车电子领域的CAN通信。peak CAN是一种基于CAN控制器的CAN总线技术,可以实现双向数据传输。在Python中,可以使用peak库来进行CAN报文的收发。 首先需要安装peak库,然后通过Python中的socketCAN驱动来实现CAN通信。在Python中,可以通过Peak CAN接口类来建立与CAN总线的连接,在建立连接后,就可以通过发送和接收CAN报文来实现数据的传输。可以通过调用Peak CAN接口类的方法来设置CAN报文的ID、数据长度和数据内容,并将CAN报文通过接口发送到总线上。同时,可以使用Peak CAN接口类的方法来接收CAN报文,并解析其中的数据内容。 在使用Python进行CAN通信时,需要注意的是,CAN报文的发送和接收需要遵守一定的规则,包括CAN报文的ID、数据长度和数据内容等。同时,需要考虑CAN总线的带宽和节点的处理能力等因素,以保证数据的传输效率和可靠性。 总之,Python通过peak库提供了一种方便、简单和灵活的方式,来实现汽车电子领域的CAN通信。对于开发人员来说,能够熟练掌握Python和peak库,将有助于提高CAN通信的效率和可靠性,从而实现更加高效和可靠的汽车电子控制系统。 ### 回答3: Python中可以使用pycan或cantools等第三方库来实现对CAN总线的控制、发送和接收CAN报文。而在这些库中,可以使用peak作为CAN总线的高层通信协议。 peak是一种CAN总线通信协议,可以通过卡的形式与计算机通信,从而实现在PC端使用Python控制CAN总线。在Python代码中,可以通过引入peak库的方式来使用其相关函数和类。 使用peak库,首先需要创建一个can总线的实例,然后通过该实例来控制CAN总线的连接以及发送和接受CAN报文。在发送CAN报文时,可以使用can总线实例中的send函数,将要发送的数据打包进一个can.Frame对象中,然后使用send函数将该对象发送到CAN总线上。 在接收CAN报文时,可以使用can总线实例中的recv函数来接收来自CAN总线的数据。recv函数会返回一个can.Frame对象,其中包含了接收到的CAN报文的相关信息,如报文的ID和数据。 通过使用Python中的peak库,可以方便地控制CAN总线,并实现CAN报文的发送和接收,从而用于各种汽车电子控制、嵌入式系统开发和测试等领域。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值