You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用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

火山引擎 最新活动