CAN DBC解析
CAN dbc文件是什么
CAN DBC 指的是CAN 报文的格式定义。简单地说,通过CAN 总线通信的数据类型可以用DBC文件来读取和理解。一般采用can editor进行编辑和查看。can editor是vector提供的编辑工具。
DBC 是处理8字节十六进制CAN 报文和原始CAN 数据的识别和转换的最常用方法。一个CAN 帧中的数据可以分成8个单byte的值、64个单bit值、一个64-bit 值或这些值的任何组合。数据字段最多可以包含8个字节的数据。一个CAN 帧可以包含0到64个单独的信号(对于64个通道,它们都将是二进制的)。
DBC报文一帧可以称作message,而message中的每一个信号称作signal。其中message包含:
- id,CAN message id,一般以16进制显示;
- name, CAN message name;
- CAN 报文的类型(CAN 标准帧/扩展帧或CAN FD 标准帧/扩展帧)
- 数据长度代码(DLC)–CAN 报文中数据的长度
singal中包含:
- 信号名称:signal name, 消息中存在的信号的名称
- 单位:信号中存在的物理数据的单位
- 起始位:信号的起始位
- 位计数:信号的位计数
- 类型:数据类型
- Factor(系数):信号的转换系数
- Offset(偏移):信号的转换偏移
- 最小和最大的信号值
- comment, 信号说明
好,废话不多说,直接进入正题,dbc解析~
DBC解析
dbc文件解析采用python,原因是Python有dbc文件解析的库,可以直接使用,比较方便。dbc解析采用的是cantools这个库文件,只需要安装这个库即可。
安装方法:
pip3 install cantools
使用时,直接import cantools即可。
下面为常用接口的介绍说明:
dbc_file = "******"
dbc_info = cantools.db.load_file(dbc_file) #创建一个dbc数据库对象
直接使用时,下述附代码,可直接复制使用。
# -*- coding: utf-8 -*-
#####
"""
# author:vehicle_ma, 2023/2/10
"""
######
import cantools
class DbcInfo:
"""
用于读取dbc文件,返回dbc信息
"""
def __init__(self, input_file):
"""
init
"""
self.dbc_file = input_file
self.dbc_info = cantools.db.load_file(self.dbc_file)
def get_message(self, frame_id):
"""
return message,特别强调,frame_id输入10进制即可,同时必须是int型数据,不能是字符串
"""
return self.dbc_info.get_message_by_frame_id(frame_id) #直接返回message的所有信息
def get_message_name(self, frame_id):
"""
return message name
"""
return self.dbc_info.get_message_by_frame_id(frame_id).name
def get_message_name_by_message_id(self, frame_name):
"""
return message id by message name
"""
return self.dbc_info.get_message_by_name(frame_name).frame_id
def get_signals_list(self, frame_id):
"""
return signals list
"""
return self.dbc_info.get_message_by_frame_id(frame_id).signal_tree #这里返回的是message中signal的list,包含一个message中所有的signal
def get_signal(self, frame_id, signal_name):
"""
return signal, 输入message id和signal name
"""
return self.dbc_info.get_message_by_frame_id(frame_id).get_signal_by_name(signal_name)
def get_signal_config_maximum(self, frame_id, signal_name):
"""
return signal maximum
"""
return self.dbc_info.get_message_by_frame_id(frame_id).get_signal_by_name(signal_name).maximum
def get_signal_config_minimum(self, frame_id, signal_name):
"""
return signal minimum
"""
return self.dbc_info.get_message_by_frame_id(frame_id).get_signal_by_name(signal_name).minimum
def get_signal_config_scale(self, frame_id, signal_name):
"""
return signal scale,这里指的是signal定义中其取值范围的间隔,
比如从1到10,每个2取一个值,scale就是2
"""
return self.dbc_info.get_message_by_frame_id(frame_id).get_signal_by_name(signal_name).scale
def get_signal_config_comment(self, frame_id, signal_name):
"""
return signal comment,signal说明
"""
return self.dbc_info.get_message_by_frame_id(frame_id).get_signal_by_name(signal_name).comment
def signal_config_value_description_to_num(self, frame_id, signal_name, value_str):
"""
return signal value description
这里需要特别说明下,有些signal取值不是正常的数值,而是文字描述,
这个在定义中是个表,比如1:open, 2:close, 4:ignore,
本函数的意思是当你取到这个字符串,比如close时,能够返回这个字符串在对应中的数字2,
这在解析和保存以及后续发送中是很有用的。
"""
return self.dbc_info.get_message_by_frame_id(frame_id).get_signal_by_name(signal_name).\
choice_string_to_number(value_str)
if __name__ == '__main__':
dbc_info = DbcInfo('D:test.dbc')
#test,根据自己需求使用上述函数即可
#frame_id输入10进制即可,同时必须是int型数据,不能是字符串
print(dbc_info.get_message_name(520))
如果想进行can报文修改,需要注意的是,直接给的数据不一定符合要求,需要保证修改数值在signla的最大最小范围内,同时保证该值符合定义中的取值间隔,可采用下述函数进行check,保证输入数值符合要求。
def check_value_meet_norms(self, frame_id, signal_name, value):
"""
check value meet norms and return closest value based on scale factor
检查输入是否符合规范,同时输出符合规范的最接近输入value值的value
如果你要用脚本修改can报文,但是修改的值如果不符合要求,给入会报错,
该函数保证修改值符合规范且接近用户期望值
"""
max_value = self.get_signal_config_maximum(frame_id, signal_name)
min_value = self.get_signal_config_minimum(frame_id, signal_name)
scale_value = self.get_signal_config_scale(frame_id, signal_name)
if value > max_value:
if isinstance(scale_value, int):
return int(max_value)
return max_value
elif value < min_value:
if isinstance(scale_value, int):
return int(max_value)
return min_value
else:
num = round(value / scale_value)
if isinstance(scale_value, int):
return int(num * scale_value)
return num * scale_value
cantools官方包链接: https://www.cnpython.com/pypi/cantools.