CAN通讯进阶-基于Python使用dbc文件解析CAN数据(dbc文件的创建、使用方法)

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

CAN通讯进阶-基于Python使⽤dbc⽂件解析CAN数据(dbc⽂件的创建、使⽤⽅
法)
CAN通讯进阶-基于Python使⽤DBC⽂件解析CAN数据
配置环境
使⽤环境:python3.6
平台:Windows10
IDE:PyCharm
1.环境配置
1.1安装CAN通讯需要的包
pip install canlib
1.2 安装kvaser_drivers以及Kvaser CanKing
下载下来之后的⽂件是这样的,三个⽂件依次双击安装就⾏了
安装完后,在开始栏可以查看到已经安装好了
2.使⽤DBC⽂件解析CAN帧2.1DBC⽂件
DBC是Database Can的缩写,其代表的是CAN的数据库⽂件,在这个⽂件中把CAN通讯的信息定义的⾮常完整清楚,在Windows下其存在的格式便是dbc,如图所⽰:
有了DBC⽂件便可以对接收到的CAN帧进⾏解析,分析⼀系列CAN帧代表的真实物理含义。

正因为如此,每⼀个DBC⽂件都对应着⼀种CAN帧的规则,使⽤CAN作为通讯⼿段的设备(如汽车中发动机、车灯、车载空调等等)都有对应的DBC⽂件。

2.2本博客布局
本博客将从DBC⽂件的创建、使⽤DBC⽂件发送指定格式的CAN数据、使⽤DBC⽂件解析接收到的CAN数据来展开。

3.DBC⽂件的创建
3.1创建DBC⽂件代码
# author:Hurricane
# date: 2021/4/16
# File : CAN_Create_Database.py
# E-mail:hurri_cane@
import argparse
from collections import namedtuple
from canlib import kvadblib
Message = namedtuple('Message','name id dlc signals')
Signal = namedtuple('Signal','name size scaling limits unit')
EnumSignal = namedtuple('EnumSignal','name size scaling limits unit enums')
_messages =[
Message(
name='EngineData',
id=100,
dlc=8,
signals=[
Signal(
name='PetrolLevel',
size=(24,8),
scaling=(1,0),
limits=(0,255),
unit="l",
),
Signal(
name='EngPower',
size=(48,16),
scaling=(0.01,0),
limits=(0,150),
unit="kW",
),
Signal(
name='EngForce',
size=(32,16),
scaling=(1,0),
limits=(0,0),
unit="N",
),
EnumSignal(
name='IdleRunning',
size=(23,1),
unit="",
enums={'Running':0,'Idle':1},
),
Signal(
name='EngTemp',
size=(16,7),
scaling=(2,-50),
limits=(-50,150),
unit="degC",
),
Signal(
name='EngSpeed',
size=(0,16),
scaling=(1,0),
limits=(0,8000),
unit="rpm",
),
]),
Message(
name='GearBoxInfo',
id=1020,
dlc=1,
signals=[
Signal(
name='EcoMode',
size=(6,2),
scaling=(1,0),
limits=(0,1),
unit="",
),
EnumSignal(
name='ShiftRequest',
size=(3,1),
scaling=(1,0),
limits=(0,0),
unit="",
enums={'Shift_Request_On':1,'Shift_Request_Off':0}, ),
EnumSignal(
name='Gear',
size=(0,3),
scaling=(1,0),
limits=(0,5),
unit="",
enums={
'Idle':0,
'Gear_1':1,
'Gear_2':2,
'Gear_3':3,
'Gear_4':4,
'Gear_5':5,
},
),
]),
]
def create_database(name, filename):
db = kvadblib.Dbc(name=name)
for _msg in _messages:
message = db.new_message(
name=_,
)
for _sig in _msg.signals:
if isinstance(_sig, EnumSignal):
_type = kvadblib.SignalType.ENUM_UNSIGNED
_enums = _sig.enums
else:
_type = kvadblib.SignalType.UNSIGNED
_enums ={}
message.new_signal(
name=_,
type=_type,
byte_order=kvadblib.SignalByteOrder.INTEL,
mode=kvadblib.SignalMultiplexMode.MUX_INDEPENDENT,
size=kvadblib.ValueSize(*_sig.size),
scaling=kvadblib.ValueScaling(*_sig.scaling),
limits=kvadblib.ValueLimits(*_sig.limits),
unit=_sig.unit,
enums=_enums,
)
db.write_file(filename)
db.close()
if __name__ =='__main__':
parser = argparse.ArgumentParser(
description="Create a database from scratch.")
parser.add_argument('--filename', default=r'..\engine_example.dbc',help=(
"The filename to save the database to."))
parser.add_argument('-n','--name', default='Engine example',help=(
"The name of the database (not the filename, the internal name."))
args = parser.parse_args()
create_database(, args.filename)
3.2使⽤⽅法
代码中if __name__ == '__main__':下:
parser.add_argument('--filename', default=r'..\engine_example.dbc',help=(
"The filename to save the database to."))
指定的filename为创建的DBC⽂件的路径以及⽂件名,本代码中便是将DBC⽂件存在代码所在⽬录的上层⽬录中,以engine_example.dbc⽂件名保存
代码中_messages列表
便是定义CAN帧解析的规则,可以定义:CAN帧的id
CAN帧的数据长度
CAN帧的解析single规则
等等…
创建⽅式如下:
4.DBC⽂件发送指定格式的CAN数据4.1DBC⽂件发送指定格式的CAN数据代码# author:Hurricane
# date: 2021/4/12
# File : CAN_Random_Send.py
# E-mail:hurri_cane@
import argparse
import time
import random
from canlib import canlib, kvadblib
bitrates ={
'1M': canlib.canBITRATE_1M,
'500K': canlib.canBITRATE_500K,
'250K': canlib.canBITRATE_250K,
'125K': canlib.canBITRATE_125K,
'100K': canlib.canBITRATE_100K,
'62K': canlib.canBITRATE_62K,
'50K': canlib.canBITRATE_50K,
'83K': canlib.canBITRATE_83K,
'10K': canlib.canBITRATE_10K,
}
# 随机在dbc结构中抽取⼀个结构
def set_random_framebox_signal(db, framebox, signals):
sig = random.choice(signals)
value = get_random_value(db, sig)
framebox.signal().phys = value
# 随机在抽取到的结构帧的数值范围中产⽣⼀个值
def get_random_value(db, sig):
limits = sig.limits
value = random.uniform(limits.min, limits.max)
# round value depending on type...
if(
sig.type is kvadblib.SignalType.UNSIGNED or
sig.type is kvadblib.SignalType.SIGNED
):
# ...remove decimals if the signal was of type unsigned
value =int(round(value))
else:
# ...otherwise, round to get only one decimal
value =round(value,1)
return value
def ping_loop(channel_number, db_name, num_messages, quantity, interval, bitrate, seed=0): db = kvadblib.Dbc(filename=db_name)
ch = canlib.openChannel(channel_number, canlib.canOPEN_ACCEPT_VIRTUAL)
ch.setBusOutputControl(canlib.canDRIVER_NORMAL)
ch.setBusParams(bitrate)
ch.busOn()
random.seed(seed)
if num_messages ==-1:
# used_messages为dbc⽂件定义的所有帧结构
used_messages =list(db)
else:
used_messages = random.sample(list(db), num_messages)
print()
print("Randomly selecting signals from the following messages:")
print(used_messages)
print("Seed used was "+repr(seed))
print()
while True:
# Create an empty framebox each time, ignoring previously set signal
# values.
framebox = kvadblib.FrameBox(db)
# Add all messages to the framebox, as we may use send any signal from
# any of them.
for msg in db:
framebox.add_message()
# Make a list of all signals (which framebox has found in all messages
# we gave it), so that set_random_framebox_signal() can pick a random
# one.
signals =[bsig.signal for bsig in framebox.signals()]
# Set some random signals to random values
for i in range(quantity):
set_random_framebox_signal(db, framebox, signals)
# Send all messages/frames
for frame in framebox.frames():
print('Sending frame', frame)
ch.writeWait(frame, timeout=5000)
time.sleep(interval)
if __name__ =='__main__':
description="Send random CAN message based on a database.")
parser.add_argument('channel',type=int, default=0, nargs='?',help=(
"The channel to send messages on."))
parser.add_argument('--bitrate','-b', default='500k',help=(
"Bitrate, one of "+', '.join(bitrates.keys())))
parser.add_argument('--db', default="../Mobileye.dbc",help=(
"The database file to base messages on."))
parser.add_argument('-Q','--quantity',type=int, default=5,help=(
"The number of signals to send each tick."))
parser.add_argument('-I','--interval',type=float, default=0.2,help=(
"The time, in seconds, between ticks."))
parser.add_argument('-n','--num-messages',type=int, default=-1,help=(
"The number of message from the database to use, or -1 to use all."))
parser.add_argument('-s','--seed', nargs='?', default='0',help=(
"The seed used for choosing messages. If possible, will be converted to an int. If no argument is given, a random seed will be used."))
args = parser.parse_args()
if args.seed is None:
seed =None
else:
try:
seed =int(args.seed)
except ValueError:
seed = args.seed
ping_loop(
channel_number=args.channel,
db_name=args.db,
num_messages=args.num_messages,
quantity=args.quantity,
interval=args.interval,
bitrate=bitrates[args.bitrate.upper()],
seed=args.seed,
)
4.2使⽤⽅法
这份代码的功能为:
以DBC⽂件规定的数据格式,随机发送⼀些数据帧出去
代码中if __name__ == '__main__':下:
parser.add_argument('--db', default="../Mobileye.dbc",help=(
"The database file to base messages on."))
指定的filename为读取的DBC⽂件的路径,本代码中读取的DBC⽂件存在代码所在⽬录的上层⽬录中,以Mobileye.dbc⽂件名存在PS:这⾥⾯的DBC⽂件也可以改为3.1创建DBC⽂件代码中⽣成的engine_example.dbc⽂件
此处附上两个DBC⽂件的云盘链接
运⾏4.1代码:
可以看到Kvaser Can King接收到各式各样的数据,但是其中的具含义我们并不清楚,这边涉及到第5节,使⽤DBC⽂件解析接收到的CAN 帧。

5.使⽤DBC⽂件解析接收到的CAN数据
5.1使⽤DBC⽂件解析接收到的CAN数据代码
# author:Hurricane
# date: 2021/4/16
# File : CAN_Using_Database.py
# E-mail:hurri_cane@
import argparse
from canlib import canlib, kvadblib
bitrates ={
'1M': canlib.canBITRATE_1M,
'500K': canlib.canBITRATE_500K,
'250K': canlib.canBITRATE_250K,
'125K': canlib.canBITRATE_125K,
'100K': canlib.canBITRATE_100K,
'62K': canlib.canBITRATE_62K,
'50K': canlib.canBITRATE_50K,
'83K': canlib.canBITRATE_83K,
'10K': canlib.canBITRATE_10K,
}
def printframe(db, frame):
try:
bmsg = db.interpret(frame)
except kvadblib.KvdNoMessage:
print("<<< No message found for frame with id %s >>>"% frame.id)
return
# form = '═^' + str(width)
# print(format(" %s " % , form))
print('┏', )
if ment:
print('┃','"%s"'% ment)
for bsig in bmsg:
print('┃', +':', bsig.value, bsig.unit)
print('┗')
def monitor_channel(channel_number, db_name, bitrate, ticktime):
db = kvadblib.Dbc(filename=db_name)
ch = canlib.openChannel(channel_number, canlib.canOPEN_ACCEPT_VIRTUAL)
ch.setBusOutputControl(canlib.canDRIVER_NORMAL)
ch.setBusParams(bitrate)
ch.busOn()
timeout =0.5
tick_countup =0
if ticktime <=0:
ticktime =None
elif ticktime < timeout:
timeout = ticktime
print("Listening...")
while True:
try:
frame = ch.read(timeout=int(timeout *1000))
printframe(db, frame)
except canlib.CanNoMsg:
if ticktime is not None:
tick_countup += timeout
while tick_countup > ticktime:
print("tick")
tick_countup -= ticktime
except KeyboardInterrupt:
print("Stop.")
break
if __name__ =='__main__':
parser = argparse.ArgumentParser(
description="Listen on a CAN channel and print all signals received, as specified by a database.") parser.add_argument('channel',type=int, default=1, nargs='?',help=(
"The channel to listen on."))
parser.add_argument('--db', default="../Mobileye.dbc",help=(
"The database file to look up messages and signals in."))
parser.add_argument('--bitrate','-b', default='500k',help=(
"Bitrate, one of "+', '.join(bitrates.keys())))
parser.add_argument('--ticktime','-t',type=float, default=0,help=(
"If greater than zero, display 'tick' every this many seconds"))
args = parser.parse_args()
monitor_channel(args.channel, args.db, bitrates[args.bitrate.upper()], args.ticktime)
5.2使⽤⽅法
代码中if __name__ == '__main__':下:
parser.add_argument('--db', default="../Mobileye.dbc",help=(
"The database file to look up messages and signals in."))
指定的filename为读取的DBC⽂件的路径,本代码中读取的DBC⽂件存在代码所在⽬录的上层⽬录中,以Mobileye.dbc⽂件名存在PS:这⾥⾯的DBC⽂件也可以改为3.1创建DBC⽂件代码中⽣成的engine_example.dbc⽂件
为了测试解析数据是否有效,采⽤此博客中4.DBC⽂件发送指定格式的CAN数据节下的随机发送数据的代码发送数据。

运⾏4.1节代码后,再运⾏5.1节代码来解析数据:
可以看到相较于Kvaser Can King接收到各式各样的数据,使⽤DBC⽂件解析后的数据都已准换为了真实的物理含义:
6.参考⽂献
Python Canlib Documentation
file:///D:/Program%20Files%20(x86)/kvaserCAN/canlib/python/pycanlib/docs/index.html 7.结束语
如果本⽂对你有帮助的话还请点赞、收藏⼀键带⾛哦,你的⽀持是我最⼤的动⼒!(づ。◕ᴗᴗ◕。)づ。

相关文档
最新文档