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


    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
    
    • 1
    • 2

    另外,要分析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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述
    以上代码中,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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

    比如这里的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)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述
    这里需要用到的就是>>移位运算以及&按位与运算,可以精准的取到某个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)返回的是),字典的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
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 相关阅读:
    CDA Level1——4.统计学
    管理区解耦架构见过吗?能帮客户搞定大难题的
    linux http代理设置
    面向对象设计模式
    【SwiftUI模块】0003、SwiftUI搭建瀑布流-交错网格
    R语言ggplot2可视化:基于aes函数中的fill参数和shape参数自定义绘制分组折线图并添加数据点(散点)、设置可视化图像的主题为theme_bw
    vue中的provide/inject你知道吗(vue2、vue3)?
    【数据结构】链表中二级指针的应用
    Visual Studio ERROR : LNK2001 和LNK2019
    openssl漏洞检查修复
  • 原文地址:https://blog.csdn.net/All_In_gzx_cc/article/details/133341332