-
판넬에서 이미지로 차의 주행 방향을 표시하는 방법analysis 2025. 7. 27. 19:57
시작하기 전에
아래 포스트들에서 판넬 기능으로 출력용 GUI와 입력용 GUI를 작성하는 방법을 설명하였다.
차 그림을 이용하여 차의 주행 방향을 표시할 수 있으면 좋겠다는 요청을 받았다. 내가 구현한 방법을 설명한다.

차의 주행 방향을 이미지로 표시하는 방법을 설명한다. 개요
- 판넬에 차 이미지 출력을 위한 콘트롤 추가하기
- YAW_RATE(CAN 신호)에서 calc.heading_angle(시스템 변수) 구하기
- heading_angle 만큼 차 이미지를 회전하기
- 실행
- 결론
판넬에 차 이미지 출력을 위한 콘트롤 추가하기
- 메인 메뉴/ Simulation/ Panel/ Add Panel로 새 판넬을 추가한다. 혹은 기존 판넬을 선택한다.

메인 메뉴/ Simulation/ Panel에서 새 판넬을 추가하거나 기존 판넬을 선택한다. - 판넬 창의 오른쪽 영역에서 Toolbox 탭을 선택한다. Image 아이콘을 더블 클릭하여, 캔버스에 이미지 콘트롤을 추가한다. 이미지 콘트롤을 드래그하여 위치를 옮긴다. 꼭지점을 클릭한 채로 드래그하여 크기를 변경한다.

Toolbox에서 Image 아이콘을 더블 클릭하여 캔버스에 이미지 콘트롤(위 그림의 Image0)을 추가한다. - 이미지 콘트롤이 추가되면 자동으로 Properties 탭이 선택된다.
- ControlName을 'Image_Car'로 변경한다. 캔버스의 이미지 콘트롤의 이름이 Image0에서 Image_Car로 변경된다. 나는 이미지 콘트롤 위치를 캔버스의 위 왼쪽으로 옮겼다. 크기도 적당하게 만들었다.
- Picture 입력 칸의 ... 버튼을 클릭하면, 이미지를 선택하는 창이 뜬다. Load 버튼을 클릭하여, 드라이브에 있는 차 이미지로 사용할 그림 파일을 선택한다.

ControlName을 변경하고, 그림 파일을 로드한다. - 캔버스의 빈 곳을 클릭하여 판넬을 선택한다. Title을 'Panel_Car'로 변경한다. Height와 Width도 이미지 크기에 맞게 조절한다. 이 크기가 판넬을 실행할 때 윈도의 크기가 된다.

판넬의 이름 (Title)을 변경한다. 필요에 따라 판넬의 크기를 조절한다. YAW_RATE(CAN 신호)에서 calc.heading_angle(시스템 변수) 구하기
- 이 예제를 실험할 CAN 트레이스와 dbc가 필요하다. 나는 내 차 베뉴의 dbc와 베뉴에서 받은 CAN 트레이스를 이용한다.
- dbc를 임포트한다.
- CAN 트레이스 보기 - 바퀴 속도 :: hsl's tsmaster 사용기에서 설명하였다. (포스트 중간의 'dbc 불러오기' 부분을 참조하십시오.)
- ESP12 메시지에 YAW_RATE 신호가 있다.
- 주행 방향을 표시하기 위해서 필요한 것은 YAW_RATE의 적분값인 heading_angle이다.
- ESP12 메시지를 수신할 때마다 (혹은 "송신"할 때마다), 아래 계산을 한다.
- heading_angle = heading_angle_prev + (ts - ts_prev) x (yaw_rate + yaw_rate_prev) / 2
- ts: 현재 메시지 수신 시 타임스탬프
- ts_prev: 지난 메시지 수신 시 타임스탬프
- yaw_rate: 현재 메시지의 YAW_RATE
- yaw_rate_prev: 지난 메시지의 YAW_RATE
- "송신"할 때?
- 나는 온라인 시뮬레이션으로 트레이스를 재생하면서 판넬이 제대로 동작하는지 검증을 해야 한다. 판넬은 온라인 상태에서만 작동하기 때문이다.
- 온라인 트레이스 재생 시에, 트레이스의 "수신" 메시지들이 "송신" 메시지가 된다.
- heading_angle = heading_angle_prev + (ts - ts_prev) x (yaw_rate + yaw_rate_prev) / 2
미니프로그램 코딩 준비
- heading_angle 계산을 위한 미니프로그램이 필요하다. 나는 파이썬으로 코딩할 것이다.
- 메인 메뉴/ Design/ Python Mini Program을 클릭하고 Add Python Code Editor를 선택하여 파이썬 코딩 창을 연다.

파이썬 코딩 창을 연다. - Properties 탭을 클릭한다. Display Name에 'calc_heading_angle' 이라고 입력했다. 코딩 창 이름이 'calc_heading_angle'로 변경된다.
- Program Name에 'calc_heading_angle'이라고 Display Name과 동일한 이름을 입력했다. 코드는 calc_heading_angle.py로 저장된다.
- [중요] 왼쪽 아래 영역의 Database Symbols에서 venue_esc.pdbc를 체크한다. 체크를 해야, dbc에 정의된 메시지들과 신호들을 편리하게 미니프로그램에서 쓸 수 있다.

시스템 변수 calc.heading_angle의 생성과 제거
- 그래픽스 창에 YAW_RATE와 heading_angle을 함께 표시하려고 한다.
- 미니프로그램의 변수 heading_angle을 그래픽스 창에 표시할 수 없다. 시스템 변수가 필요하다.
- calc.heading_angle라는 시스템 변수를 선언한다.
- 이 시스템 변수는 프로그램 실행 중에만 필요하다고 가정한다. On Start 이벤트에서 생성하고, On Stop 이벤트에서 제거하기로 한다.
- Symbols 탭에서, On Start 이벤트를 마우스 우클릭한다. Add On Start를 선택한다. 함수 이름을 정한다. 나는 'create_sys_vars'라고 했다. app.create_system_var() 함수를 이용하여 calc.heading_angle 시스템 변수를 생성한다.

- 같은 방법으로 On Stop 이벤트에 calc.heading_angle 시스템 변수를 제거하는 함수를 추가한다. 각가의 코드는 아래와 같다.
def on_start_create_sys_vars() -> None: if app.create_system_var('calc.heading_angle', TSystemVarType_svtDouble, '0.0', 'system variable yaw_angle') == 0: app.log_text('created', lvlOK) def on_stop_delete_sys_vars() -> None: if app.delete_system_var("calc.heading_angle") == 0: app.log_text("deleted", lvlOK)글로벌 변수 선언
- ESP12 CAN 메시지를 파싱하기 위해서 ESP12_1라는 글로벌 변수를 선언한다. 방법은 다음과 같다.
- Symbols 탭을 클릭한다. Global Definition을 클릭한다. 아래 그림에는 코딩 영역에 코드가 이미 있지만, 처음 하는 경우 이 영역이 비어있다.

- Functions 탭을 클릭한다. TSMaster에서 제공하는 함수들의 목록을 볼 수 있다. '미니프로그램 코딩 준비' 단계에서 dbc를 포함시켰기 때문에 dbc에 정의된 calc_1, ESP12, SAS11, WHL_SPD11 메시지들을 볼 수 있다. 메시지 이름 뒤에 붙은 _1은 dbc를 채널 1에 연결해서 생긴 것이다. 채널 n에 연결했다면 ESP12_n 이렇게 표시되었을 것이다.
- ESP12_1을 마우스 우클릭하여 Insert into script를 선택한다. 앞에서 선택해둔 Global Definition 영역에 코드가 추가된다.
- 코드를 보면 ESP12_1이라는 변수(오브젝트)를 생성하였다.

- 적분 계산을 위해서 지난 메시지의 타임스탬프(ts)와 요-레이트, 지난 번 계산한 주행 방향 (heading_angle)이 필요하다. 이 변수들을 함수 안에서 선언하면, 함수 종료와 함께 사라진다. 그렇게 되지 않도록 나는 글로벌 변수를 사용한다.
- 글로벌 변수라는 의미에서 변수 이름을 'g_'로 시작한다. 지난 번이라는 의미에서 변수 이름에 '_prev'를 붙인다.

heading_angle 계산
- heading_angle을 계산하는 코드는 아래와 같다. 주석으로 설명하였다.
def calc_heading_angle(ACAN: RawCAN) -> None: global g_ts_prev, g_heading_angle, g_yaw_rate_prev # 수신 메시지의 데이터를 ESP12 메시지 구조로 파싱한다. ESP12_1.FRawCAN = ACAN # timestamp: 메시지 수신 시간 ts = ACAN.time_us # CAN 메시지에서 yaw_rate를 가져온다. yaw_rate = ESP12_1.YAW_RATE # 첫 메시지 수신 시에는 타임스탬프가 한 개밖에 없어서 수신 주기를 계산할 수 없다. # 첫 메시지 수신을 표시하기 위해서 g_ts_prev를 -1로 초기화했다. if g_ts_prev < 0: g_ts_prev = ts g_yaw_rate_prev = yaw_rate # 지난 메시지와 이번 메시지 사이의 시간. 단위 usec d_ts = ts - g_ts_prev # g_timestamp_prev를 업데이트한다. g_ts_prev = ts # 메시지가 2개 수신되기 전까지 d_ts는 0이다. if d_ts > 0: # usec를 sec로 변환하여 계산한다. g_heading_angle += (d_ts / 1000000.0) * (yaw_rate + g_yaw_rate_prev) / 2.0 # 그래픽스창 출력에 사용할 시스템 변수를 업데이트 한다. app.set_system_var_double('calc.heading_angle', g_heading_angle) # g_yaw_rate_prev릉 업데이트한다. g_yaw_rate_prev = yaw_rate # 이미지를 회전할 각도를 계산한다. heading_angle_int = int(g_heading_angle) % 360 # 이미지가 너무 자주 회전되지 않도록 한다. # 3도 단위로 회전한다. if heading_angle_int % 3 == 0: if 0 == app.panel_set_rotation_angle("Panel_Car", "Image_Car", heading_angle_int): app.log_text(f'heading angle: {heading_angle_int:}', lvlOK)- 위 코드를 ESP12 메시지를 수신/송신할 때마다 실행해야 한다.
- Symbols 탭에서 On CAN Rx 이벤트를 마우스 우클릭한다. Add On RX - CAN Message를 클릭한다.

- Id에서 ESP12 메시지를 선택한다. Name으로 나는 메시지 이름을 그대로 사용하였다.

- 그러면 이해하기 쉬운 함수 이름이 생성된다. on_can_rx_ESP12

- 코드 영역에 위에서 정의한 calc_heading_angle(ACAN) 함수를 호출하도록 한다.
- 같은 방법으로 On CAN Tx 이벤트에서도 calc_heading_angle(ACAN)을 호출하도록 한다.

heading_angle 만큼 차 이미지를 회전하기
- heading_angle 만큼 차 이미지를 회전하는 방법은 위 코드에 포함되어 있다. 아래 발췌한 부분이다.
- "Panel_Car" 판넬의 "Image_Car" 콘트롤을 heading_angle_int (정수로 변경한 주행 방향 각도) 만큼 회전하는 함수를 사용하면 된다. 간단하다.
# 이미지가 너무 자주 회전되지 않도록 한다. # 3도 단위로 회전한다. if heading_angle_int % 3 == 0: if 0 == app.panel_set_rotation_angle("Panel_Car", "Image_Car", heading_angle_int): app.log_text(f'heading angle: {heading_angle_int:}', lvlOK)- heading_angle과 YAW_RATE를 그래픽스 창에 표시하고자 한다.
- CAN 신호인 YAW_RATE을 그래픽스 창에 표시하는 방법은 아래와 같다.

그래픽스 창에서 '+' 기호 아이콘을 클릭하여, Add CAN signal...을 선택한다. 
CAN Database 창이 뜨면, YAW_RATE를 선택한다. - 그래픽스 창에 시스템 변수 추가하는 것도 위와 같은 방식이다. 차이가 있다면 미니프로그램을 실행하지 않은 상태에서는 시스템 변수 창에 선택할 시스템 변수가 없다는 점이다.

미니프로그램을 실행하지 않은 상태에서는 시스템 변수 창이 비어있다. 
미니프로그램을 실행하면 시스템 변수 창에 calc.heading_angle 시스템 변수가 표시된다. 
그래픽스 창에서 '+' 기호 아이콘을 클릭하여, Add System Variable...을 선택한다. 
Select System Variable 창이 뜨면, calc.heading_angle을 선택한다. - 이왕 화면을 출력 화면을 만드는 김에 Meter를 추가한다. 메인 메뉴/ Analysis/ Gauges에서 Add Meter를 선택한다.

- Meter 창에서 CAN 버튼을 클릭하여 YAW_RATE 신호를 추가한다. 게이지가 추가된다. 게이지를 더블 클릭하면 설정창이 열린다. 게이지 표시 범위, 모양 등을 설정할 수 있다.

- 메인 메뉴/ Analysis/ Bus Replay를 클릭하여 Bus Playback 창을 연다.

- Bus Playback 창에서 Online Replay 탭을 선택한다.
- '+' 기호가 있는 아이콘을 선택하여, 재생할 CAN 트레이스를 선택한다.

- 미니프로그램을 실행하지 않은 상태라면, 실행한다.
- 판넬이 편집 모드에 있다면 연필 모양의 아이콘을 클릭하여 실행 모드로 전환한다.

편집 모드 상태의 판넬 
실행 모드 상태의 판넬 - Bus Playback 창에서 "Play" 버튼을 클릭한다.
실행
- 실행하면 아래 비디오와 같이 된다.
- 오프라인 상태에서 재생하면 판넬은 동작하지 않는다. 그래픽스나 게이지는 동작한다.
결론
- 판넬의 이미지 콘트롤과 간단한 미니프로그램으로 YAW_RATE 신호를 이용하여 차의 주행 방향에 따라 차의 이미지가 방향을 바꾸는 사용자 화면을 만드는 방법을 설명하였다.
- 판넬은 온라인 측정/ 재생 상태에서만 동작한다. 그래픽스나 게이지는 오프라인 재생 상태에서도 동작한다.
- 미니프로그램에서 시스템 변수를 생성하고 제거하는 방법을 설명하였다. 이 경우, 시스템 변수를 그래픽스 창에 추가하기 위해서는 미니프로그램을 먼저 실행해야 한다.
TSMaster Project
display_car_per_yaw_angle_1.zip10.76MBhsl's tsmaster 사용기 :: hsl's tsmaster 사용기
'analysis' 카테고리의 다른 글
blf --> csv --> 리샘플 --> xlsx (1) 2025.09.05 트레이스창에서 메시지 필터 걸기 (0) 2025.08.19 UDS 메시지만 보기 - 메시지 아이디 필터 (0) 2025.07.09 PC간 데이터 전송 - 소켓 통신 (0) 2024.12.31 시스템 변수를 로깅하는 방법 (1) 2024.12.30