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 = 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 |
coi = ['m_id', 'name', 'dlc_dbc', 'dlc_car', 'dlc_check']
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_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_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_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)
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를 최신 상태로 유지하는 것은 차량 형상 관리를 위해서 중요하다.
- 툴 없이 차량 형상 관리를 한다는 것은 무모한 일이라고 생각한다.