|
o22uecqekb164032178342.gif
, b& c- Z9 `2 j# C6 o3 b! K. t" n- k点击上方蓝色字体,关注我们. V& d( G8 j9 j r3 ]+ k
* p- ^# ]8 u7 L q7 S7 i g) t尤其是当系统需求变更或多个供应商协作开发时,对比 DBC 文件以找出差异和潜在问题是至关重要的。
! I% V1 R" D! K& G8 t* r( P
5 g3 V# l! j3 x本文将深入探讨如何通过 Python 的 cantools 库,实现高效、准确地对比多个相似的 CAN DBC 数据。
, Y; f7 p' ]7 G3 I0 J2 r8 a3 v! q8 v0 x: i: `9 T) _9 ?" b- G$ [
cantools 是 Python 领域中一个强大的 CAN 协议处理库,广泛用于汽车和嵌入式系统中,用于解析、编码和解码 CAN 报文。* X6 l/ I: q; f" l$ e& P
1* F G: ^4 O* j, l/ U- z( f
安装 cantools 模块8 j8 J; Q8 d7 q( z
确保安装 cantools 库:
+ ~+ Z/ W, D. O" n; g; ~0 L- C% z# G, j7 D7 ~
pip install cantools假设有多个 DBC 文件:. G0 T' K- F) P" k5 t8 r* x, a1 u' u
. P: Q4 c/ ]" p4 Z5 V% |7 Y5 V
dbc_file1.dbcdbc_file2.dbcdbc_file3.dbc对比 DBC 文件时,我们一般会关注以下几个方面:
W" o! N& y5 G0 i/ g7 ^& ^5 O* w, y# ?% g m D: l
消息(Message)差异
7 ~# B# u# m, n8 U消息 ID 是否一致消息名称是否一致消息长度(DLC)是否一致
: K" @7 T. B: A' g# n' o信号(Signal)差异
. O6 U- E( ~2 i- }信号数量是否一致信号名称、起始位、长度、字节序和编码格式的差异信号物理值缩放和偏移的变化
) ^! a& M# z7 z5 N" O8 s- q: E; i% I
7 x7 Y! g- F& r1 u# J9 n
节点(Node)差异! `" y9 {! Q- D n% K- A, a
节点名称、发送和接收的消息是否一致
* l; D% c3 V/ F# S5 [- u1 f9 b: g3 S6 Z" |+ g( l* S
2
9 o* {; k/ R* ~- H代码实现
4 m! Q z9 v, O# d2 ^设计一个对比代码,思路如下:
/ s% {7 i7 }( u" |2 Y加载 DBC 文件:加载并解析文件,提取消息和信号数据。多文件对比:使用嵌套循环对多个 DBC 进行两两对比,记录差异。
9 u2 m; P! f% z5 u* e4 ~结果展示:以结构化的形式展示差异,方便分析。* X, ?6 F9 P$ I5 r, V/ ^0 v
代码实现如下:2 ]/ N) w/ ?, a. T( Q! k2 B
- f( n8 W1 N6 H g" x+ _5 kimport 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 data( J- H+ D# P) X# v
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
; J8 S) O* ]/ U& Ndef compare_messages(msg_data1, msg_data2): """比较两组消息数据""" diff_results = defaultdict(lambda: defaultdict(dict))
$ ]- `' \; ?. f( x- b+ m all_msg_names = set(msg_data1.keys()).union(set(msg_data2.keys()))1 d+ m7 u3 u0 p. ~( _, e
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
( \" |- @- n4 @: n' G/ [ x5 u # 对比 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"])
, S/ x' y5 E4 u' ] i1 S # 对比信号 signals1 = msg_data1[msg_name]["signals"] signals2 = msg_data2[msg_name]["signals"] all_signals = set(signals1.keys()).union(set(signals2.keys()))" L( s; t$ G S9 w
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_diff5 B) S% t8 r5 E0 ?7 c
return diff_results
) i8 ]$ Z* ^4 u- {, ndef 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}( q) d+ z, n" M% 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"
& e! o/ \1 ^8 i8 u `5 A$ h=== 对比 {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}")
% x" ~+ F2 ` j5 M) {3 U% O# 示例调用dbc_files = ["dbc_file1.dbc", "dbc_file2.dbc", "dbc_file3.dbc"]compare_multiple_dbc(dbc_files)8 S- R5 s4 ^0 B7 }
jdraxptx2kv64032178442.jpg
0 a( X& ?& Z2 t9 W8 p8 i, l; d
ifxio1vwzvg64032178542.gif
6 d/ q) o w' Q6 S/ r; v9 k, O% U _点击阅读原文,更精彩~ |
|