使用cantools.decode_message()解码CAN消息时结果与手动/第三方软件解码不一致的问题求助
cantools.decode_message()解码CAN消息时结果与手动/第三方软件解码不一致的问题求助
我现在遇到一个棘手的问题:我通过UDP接收CAN消息,格式为(data_length, frame_id, data),想要将其转换为JSON格式。我使用cantools.database.load_file()加载DBC文件,再通过decode_message()解码消息——解码过程没有抛出任何错误,但得到的数值结果和手动解码、第三方软件解码的结果完全不符。
举个具体的例子:
原始数据为 00 00 03 d0 01 40 00 ad,正确的解码结果应该是:
{'Engine_Speed': 0, 'Inlet_Manifold_Pressure': 97.6, 'Inlet_Air_Temperature': 32, 'Throttle_Position': 17.3}
但我通过cantools得到的结果却是:
{'Engine_Speed': 12336, 'Inlet_Manifold_Pressure': 1233.6000000000001, 'Inlet_Air_Temperature': 1233.9, 'Throttle_Position': 2564.8}
(补充:这是对应帧ID的DBC在kvsar CAN DBC中的截图)
我已经尝试了三种不同的字节反转方式来调整数据:
- 将原始数据
12 34 56 78转换为87 65 43 21 - 转换为
78 56 34 12 - 转换为
21 43 65 87
但这些调整都没有得到正确的数值。我还有一段代码可以将数据格式化为类似b'\\x10\\x00\\x00\\x10\\x10\\x00\\x00\\x30'的字节串,这个方法对部分变量有效,但无法解决所有变量的问题。
我已经检查过DBC文件没有设置偏移量,缩放比例配置正确,变量对应的字节分配也没问题,但依然无法解决这个数值偏差的问题。
以下是我的完整代码:
import cantools import json import time def start(receive_socket, socket): print('Starting CAN Translator') global send_socket send_socket = socket setup() main(receive_socket) def setup(): global sel global db global CANSocket global serverIP global receivePort global bufferSize global nonLiterals global json_file_name bufferSize = 1024 nonLiterals = set() json_file_name = 'json_data.json' # Add the DBC file to the CAN reader db = cantools.database.load_file('DBCS/DBC3.dbc', database_format='dbc', encoding='cp1252', frame_id_mask=None, prune_choices=False, strict=True, cache_dir=None) # Reset the json file json_file = open(json_file_name, 'w') json_file.write('{}') def find_nth(haystack, needle, n): start = haystack.find(needle) while start >= 0 and n > 1: start = haystack.find(needle, start + len(needle)) n -= 1 return start # Translate each string from the decoded CAN message into a dictionary and then output that dictionary to the json file def to_json(message): print(message) with open(json_file_name, 'r+') as json_file: json_dict = json.load(json_file) # print(json_dict) json_dict.update(message) # Add a value to hold the current time json_dict.update({'Timestamp': time.time()}) json_file.close() open(json_file_name, 'w').close() json_file = open(json_file_name, 'r+') json.dump(json_dict, json_file) send_json(json_dict) def reformatter(data_string): # print(data_string) start_pos = 0 current_space = 0 next_space = 0 i = 0 data_reformatted = '' while next_space >= 0: # print(data_string) next_space = find_nth(data_string, ' ', i + 1) # print(next_space) # print(next_space-current_space) if next_space - current_space == 1: data_reformatted += ('\\x0' + data_string[start_pos:next_space]) elif next_space - current_space == 2: data_reformatted += ('\\x' + data_string[start_pos:next_space]) else: data_reformatted += ('\\x' + data_string[start_pos:]) # print('looking for more spaces') i += 1 current_space = next_space + 1 start_pos = current_space # print(data_reformatted) return data_reformatted def data_handler(data): # Extract the message from the socket message = data.decode().strip() # Separate CAN message into id and data # Except non hexadecimal values try: frame_id = int(message[find_nth(message, ',', 1) + 1:find_nth(message, ',', 2)], 16) except ValueError as error: # print('Non hexadecimal frame_id: %s' % error) nonLiterals.add(str(error)) frame_id = 'ERROR' print(message) print(f'Frame ID: {frame_id} data: {data}') data_string = message[find_nth(message, ',', 2) + 1:] data = bytes(data_string, 'utf-8') data_reformatted = reformatter(data_string) fixed_data = bytes(data_reformatted, 'utf-8') # print(fixed_data) reversed_reformatted = bytes(reverse(data_reformatted), 'utf-8') regular_reversed = data_string[::-1] regular_reversed_reformatted = bytes(reformatter(regular_reversed), 'utf-8') weird_reversed = bytes(reverse(reformatter(regular_reversed)), 'utf-8') to_send = fixed_data print(to_send) try: # Decode each incoming message to_json(db.decode_message(frame_id_or_name=frame_id, data=to_send, decode_choices=False, scaling=True, decode_containers=False, allow_truncated=False)) except KeyError as error: print('Key error: %s' % error) except ValueError as error: print(error) except Exception as error: print(error) def send_json(json_string): json_result = json.dumps(json_string) try: send_socket.send(json_result.encode()) except ConnectionResetError as error: print(error) # print(json_result, 'was sent!') # time.sleep(1) def reverse(data_string): # print(data_string) length = len(data_string) i = int(length/4) reverse_string = '' while i > 0: startpos = find_nth(data_string, '\\', i) reverse_string += data_string[startpos:startpos+4] i -= 1 # print(reverse_string) return reverse_string def main(receive_socket): while True: data_handler(receive_socket.recv())
备注:内容来源于stack exchange,提问作者jack




