ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • dbc에서 m_id들을 찾기
    application 2025. 1. 26. 00:16

    dbc에서 m_id들을 찾기

    • 목적: 차량 형상 관리 관점에서 설계 사양 (dbc)과 실차의 형상(m_id_info)을 비교한다.
    • dbc 파일에서 m_id_info의 m_id들을 찾는다.
    • 찾아야할 m_id들은 ~mid_info.xlsx에 저장되어 있다.
    • cantools라는 Python 모듈을 이용하여 dbc의 내용을 읽는다.
    • 찾기와 비교를 쉽게 하기 위해서 pandas라는 Python 모듈을 이용한다.
    • xlsx의 내용을 df_car라는 dataframe(df)으로 만든다.
    • dbc의 내용을 df_dbc라는 df로 만든다.
    • 두 df를 합친다.
      • 양쪽 df 모두에 포함되어 있고, dlc(data length code)가 동일하면 ok
      • 양쪽 df 모두에 포함되어 있는데, dlc가 다르면 nok
      • df_dbc에는 있는데 df_car에 없으면 missing
      • df_car에 있는데 df_dbc에 없으면 unidentified
    • 로 분류한다.

    CAN 통신에서 메시지 아이디(m_id)들을 찾고 그 아이디들을 dbc에서 찾는 것은 차량 형상 점검의 기본이자 시작점이다.

    from pathlib import Path
    import cantools
    import pandas as pd
    ldf is not supported
    xls is not supported
    xlsx is not supported

    찾아야 할 m_id

    xlsx_m_info = Path(r'C:/data/tosun/projects/uds_vehicle_config/Logging/Bus/uds_vehicle_config_2025_01_19_10_34_14_m_info.xlsx')
    df_car = pd.read_excel(xlsx_m_info, sheet_name='Sheet1')
    df_car[['m_id', 'm_id_int', 'dlc', 'd_ts']].sample(3)
      m_id m_id_int dlc d_ts
    29 394 916 8 0.02
    44 52A 1322 8 0.20
    36 4E6 1254 8 0.10

    m_id를 찾을 dbc

    # dbc 파일
    dbc = Path(r'C:\data\tosun\reference\dbc\20240809_venue\venue_esc.dbc')
    db = cantools.database.load_file(dbc, strict=False)
    db.messages
    
    [message('calc', 0x222, False, 8, {None: '[P] Periodic'}),
     message('ESP12', 0x220, False, 8, {None: '[P] Periodic'}),
     message('SAS11', 0x2b0, False, 5, {None: '[P] Periodic'}),
     message('WHL_SPD11', 0x386, False, 8, {None: '[P] Periodic'})]

    df_dbc를 만든다.

    messages = [(message.name, hex(message.frame_id), message.frame_id, message.length) for message in db.messages]
    df_dbc = pd.DataFrame(messages, columns=['name', 'm_id', 'm_id_int', 'dlc'])
    df_dbc
      name m_id m_id_int dlc
    0 calc 0x222 546 8
    1 ESP12 0x220 544 8
    2 SAS11 0x2b0 688 5
    3 WHL_SPD11 0x386 902 8

    df_dbc와 df_m_id_info를 합친다.

    df = pd.merge(df_dbc, df_car[['m_id_int', 'dlc', 'd_ts']], on='m_id_int', how='outer', suffixes=['_dbc', '_car'], indicator=True)
    df['m_id'] = df['m_id_int'].apply(lambda x: f'0x{x:03X}')
    df['dlc_check'] = df['dlc_dbc'] == df['dlc_car']
    df.sample(3)
      name m_id m_id_int dlc_dbc dlc_car d_ts _merge dlc_check
    58 NaN 0x5CF 1487 NaN 8.0 0.10 right_only False
    20 NaN 0x329 809 NaN 8.0 0.01 right_only False
    10 NaN 0x164 356 NaN 4.0 0.01 right_only False
    # columns of interest
    coi = ['m_id', 'name', 'dlc_dbc', 'dlc_car', 'dlc_check']
    
    # df_dbc와 df_car에 모두 있고 dlc가 같은 것
    df_ok = df.loc[(df['_merge'] == 'both') & (df['dlc_check'] == True), coi]
    
    # 메시지를 송신하는 제어기를 찾는다.
    df_ok['ecu_tx'] = df_ok['m_id'].apply(lambda x: db.get_message_by_frame_id(int(x, 16)).senders)
    
    # 메시지를 수신하는 제어기를 찾는다.
    df_ok['ecu_rx'] = df_ok['m_id'].apply(lambda x: db.get_message_by_frame_id(int(x, 16)).receivers)
    
    # df_dbc와 df_car에 모두 있는데 dlc가 다른 것
    df_nok = df.loc[(df['_merge'] == 'both') & (df['dlc_check'] == False), coi]
    df_nok['ecu_tx'] = df_nok['m_id'].apply(lambda x: db.get_message_by_frame_id(int(x, 16)).senders)
    df_nok['ecu_rx'] = df_nok['m_id'].apply(lambda x: db.get_message_by_frame_id(int(x, 16)).receivers)
    
    # df_dbc에 있는데 df_car에 없는 것
    df_missing = df.loc[df['_merge'] == 'left_only', coi]
    df_missing['ecu_tx'] = df_missing['m_id'].apply(lambda x: db.get_message_by_frame_id(int(x, 16)).senders)
    df_missing['ecu_rx'] = df_missing['m_id'].apply(lambda x: db.get_message_by_frame_id(int(x, 16)).receivers)
    
    # df_car에 있는데 df_dbc에 없는 것
    df_unidentified = df.loc[df['_merge'] == 'right_only', coi]
    print(f'{len(df_ok)} messages are found in both dbc and m_info with the same dlc')
    df_ok
    2 messages are found in both dbc and m_info with the same dlc
      m_id name dlc_dbc dlc_car dlc_check ecu_tx ecu_rx
    13 0x220 ESP12 8.0 8.0 True [ESC] {GST, EMS, SAS}
    27 0x386 WHL_SPD11 8.0 8.0 True [ESC] {GST, EMS, SAS}
    print(f'{len(df_nok)} messages are found in both dbc and m_info with different dlc')
    df_nok
    1 messages are found in both dbc and m_info with different dlc
      m_id name dlc_dbc dlc_car dlc_check ecu_tx ecu_rx
    18 0x2B0 SAS11 5.0 6.0 False [SAS] {ESC}
    print(f'{len(df_missing)} messages are found in car but not in dbc')
    df_missing
    1 messages are found in car but not in dbc
      m_id name dlc_dbc dlc_car dlc_check ecu_tx ecu_rx
    14 0x222 calc 8.0 NaN False [ESC] {GST, EMS, SAS}
    print(f'{len(df_unidentified)} messages are found in car but not in dbc')
    df_unidentified.sample(3)    # 많아서 3개만 출력한다. 
    56 messages are found in car but not in dbc
      m_id name dlc_dbc dlc_car dlc_check
    41 0x502 NaN NaN 4.0 False
    51 0x553 NaN NaN 8.0 False
    46 0x53E NaN NaN 6.0 False

    결론

    • "blf 파일에서 m_id, dlc, d_ts 추출하기"에서 CAN 버스에 있는 메시지들을 찾았다.
    • 이 메시지들이 dbc 파일에 있는 지 확인하였다.
    • dbc에도 있고 차에도 있고 사양(예제에서는 dlc만 확인하였다.)도 같은 경우, 문제 없다. (case OK)
    • dbc에도 있고 차에도 있는데 사양이 다른 경우, 문제이다. 점검이 필요하다. (case NOK)
    • dbc에는 있는데 차에는 없는 경우, 문제이다. 용도가 있어서 dbc에 포함하였거나, dbc에 오류가 있거나, 제어기에 오류가 있다. (case Missing)
    • dbc에는 없는데 차에는 있는 경우, 문제이다. dbc에 오류가 있거나, 제어기에 오류가 있다. (case Unidentified)
    • dbc와 제어기를 점검하고 필요에 따라 수정하고 이 스크립트를 실행하여 결과를 확인하는 절차를 반복하는 방식으로 설계 형상과 실제 형상을 맞춰나갈 수 있다.
    • dbc를 최신 상태로 유지하는 것은 차량 형상 관리를 위해서 중요하다.
    • 툴 없이 차량 형상 관리를 한다는 것은 무모한 일이라고 생각한다.