|
o22uecqekb164032178342.gif
( U' }8 V$ H' L. W. B, P- v点击上方蓝色字体,关注我们8 V( ? E* c: \' c% k1 |' r7 D/ O
* w, ^/ ~/ H) p* V) ^尤其是当系统需求变更或多个供应商协作开发时,对比 DBC 文件以找出差异和潜在问题是至关重要的。
x# I' m4 x6 F3 t# F* v
5 P# R `: Q% @" Y" q本文将深入探讨如何通过 Python 的 cantools 库,实现高效、准确地对比多个相似的 CAN DBC 数据。
! u) _- B8 q2 X1 f' z# _& g6 F' A& v9 G6 l( r- D# W( O
cantools 是 Python 领域中一个强大的 CAN 协议处理库,广泛用于汽车和嵌入式系统中,用于解析、编码和解码 CAN 报文。
2 \! J, _8 Z9 q Q12 b; V! s9 {3 q9 D; z% W9 S9 S4 L# _3 i6 m
安装 cantools 模块' W! U! N( u3 t O& V3 O; e, j
确保安装 cantools 库:& G! ]% U' L, |, v- |; y$ W
- `* |, |) j4 U! g3 A
pip install cantools假设有多个 DBC 文件:
]# j' T3 S d3 h: I. P
+ S& ?2 p8 x% G5 udbc_file1.dbcdbc_file2.dbcdbc_file3.dbc对比 DBC 文件时,我们一般会关注以下几个方面:
# S0 t4 D% C7 W2 f/ }1 N2 g3 `% s3 V( F. E9 `# M5 e
消息(Message)差异# C, u: B# a4 d' x, t# C: Z
消息 ID 是否一致消息名称是否一致消息长度(DLC)是否一致
, J) D! r8 B" I8 l* e$ @信号(Signal)差异
- M5 C; m! `5 Z+ g, T+ [信号数量是否一致信号名称、起始位、长度、字节序和编码格式的差异信号物理值缩放和偏移的变化
' R/ X0 e7 r4 Q# p6 g
( E- x/ o' X0 @# f# H
6 G! {( e2 H$ S6 D节点(Node)差异7 r- A7 V7 I* Q- N) u2 M5 P7 W
节点名称、发送和接收的消息是否一致. V+ e g) R0 x
" W: D* ]4 H) @2 c
2
9 ~$ Z4 I: F6 a8 b代码实现
# k+ R2 x+ {8 J9 Y" Y: D设计一个对比代码,思路如下:
( R" }0 `4 [! r加载 DBC 文件:加载并解析文件,提取消息和信号数据。多文件对比:使用嵌套循环对多个 DBC 进行两两对比,记录差异。
, W' C" z% U% p& T/ \, ]4 F, w结果展示:以结构化的形式展示差异,方便分析。
! ?/ y/ C q- G2 ?0 F代码实现如下:8 K1 F1 q$ w) Y7 ~$ Z @' R
! s/ Y) D) `7 \, ?import cantoolsimport osfrom collections import defaultdictdef load_dbc(file_path): """加载DBC文件并返回CAN数据库对象""" try: return cantools.database.load_file(file_path) except Exception as e: print(f"加载失败: {file_path} - {e}") return Nonedef extract_message_data(db): """提取DBC文件中的消息及信号信息""" data = {} for message in db.messages: signals = {signal.name: { "start": signal.start, "length": signal.length, "scale": signal.scale, "offset": signal.offset, "byte_order": signal.byte_order, "is_signed": signal.is_signed } for signal in message.signals} data[message.name] = { "frame_id": message.frame_id, "length": message.length, "signals": signals } return data5 I3 I- Q6 e' M2 m! T# i
def compare_signals(signal1, signal2, signal_name): """比较信号的属性差异""" diff = {} for attr in ["start", "length", "scale", "offset", "byte_order", "is_signed"]: if signal1[attr] != signal2[attr]: diff[attr] = (signal1[attr], signal2[attr]) return diff if diff else None& Q" L' _3 _5 f J
def compare_messages(msg_data1, msg_data2): """比较两组消息数据""" diff_results = defaultdict(lambda: defaultdict(dict))+ f2 K4 Y( C; U8 z( J2 E; R
all_msg_names = set(msg_data1.keys()).union(set(msg_data2.keys())) ]1 l, k% }( M" b
for msg_name in all_msg_names: if msg_name not in msg_data1: diff_results[msg_name]["存在于"] = "仅在 DBC2" continue if msg_name not in msg_data2: diff_results[msg_name]["存在于"] = "仅在 DBC1" continue/ _: J! t* H5 i; e3 \% Q
# 对比 Frame ID 和 Length if msg_data1[msg_name]["frame_id"] != msg_data2[msg_name]["frame_id"]: diff_results[msg_name]["frame_id"] = (msg_data1[msg_name]["frame_id"], msg_data2[msg_name]["frame_id"]) if msg_data1[msg_name]["length"] != msg_data2[msg_name]["length"]: diff_results[msg_name]["length"] = (msg_data1[msg_name]["length"], msg_data2[msg_name]["length"])0 m5 u0 ^+ l0 k* k; ]7 x8 k8 `) ]
# 对比信号 signals1 = msg_data1[msg_name]["signals"] signals2 = msg_data2[msg_name]["signals"] all_signals = set(signals1.keys()).union(set(signals2.keys())). B% E2 i- H! U$ F; r" b
for sig in all_signals: if sig not in signals1: diff_results[msg_name]["signals"][sig] = "仅在 DBC2" elif sig not in signals2: diff_results[msg_name]["signals"][sig] = "仅在 DBC1" else: sig_diff = compare_signals(signals1[sig], signals2[sig], sig) if sig_diff: diff_results[msg_name]["signals"][sig] = sig_diff
' J' b8 I8 h8 k% ?) I' g, h t; f return diff_results
1 l2 b" q2 {" K. t, X: N, @( _def compare_multiple_dbc(dbc_files): """对比多个 DBC 文件""" dbcs = {file: load_dbc(file) for file in dbc_files} dbc_data = {file: extract_message_data(db) for file, db in dbcs.items() if db}: H4 K, L- H! n8 m7 q& |" @+ R# N* X
for i in range(len(dbc_files)): for j in range(i + 1, len(dbc_files)): file1, file2 = dbc_files, dbc_files[j] print(f"
8 W5 }8 m3 Q1 J=== 对比 {file1} 和 {file2} ===") diff = compare_messages(dbc_data[file1], dbc_data[file2]) if not diff: print("无差异") else: for msg, details in diff.items(): print(f"消息: {msg}") for key, value in details.items(): print(f" - {key}: {value}")
- ~) p) \+ [: W8 u* f3 J% P# 示例调用dbc_files = ["dbc_file1.dbc", "dbc_file2.dbc", "dbc_file3.dbc"]compare_multiple_dbc(dbc_files)
7 o' I$ S5 T) \# i0 o7 d# m7 J
jdraxptx2kv64032178442.jpg
( J0 ~+ p3 Z) z* g: r2 s6 C
ifxio1vwzvg64032178542.gif
$ S W% f+ U$ q点击阅读原文,更精彩~ |
|