UAM 올림피아드 프로젝트 후기 #1
개요
올해 7월 끝자락에서 시작된 위대한 여정이 드디어 하나의 장을 마감했습니다. 팀장은 대회의 찬란한 무대를 향한 꿈을 가슴에 품고, 다양한 재능과 가능성을 간직한 팀원들을 한데 모았죠. 프로젝트가 진행되면서 이들은 각자의 부족함을 인정하고, 서로의 강점을 존중하며 하나의 목표를 항해 매진했습니다. 팀장의 기대를 한 몸에 받으며, 팀원들은 자신들의 한계를 뛰어넘어, 실력을 키웠고, 끈기와 열정으로 가득 찬 길을 달렸습니다. 결국, 그들은 첫 번째 목표를 향한 여정의 종착지에 도달했고, 이는 그들이 이루어낸 위대한 성취의 시작에 불과했습니다.
무슨 소리냐구요? 7월 말부터 했던 프로젝트의 개발이 완료됐고 제출했고 결과만 기다리고 있단 소리였습니다. 이 프로젝트를 진행하면서 정말 고생 많이 했습니다. 인턴쉽을 하면서 매일 밤을 밤새며 열정을 불태웠죠. 그리고 그 열정을 어떻게 불태웠는지 이 글을 통해 이야기해 보고자 합니다.
프로젝트 시작
사실 이 대회는 개발을 안 해도 되는 대회입니다. 정확히는 개발할 필요가 없이 아이디어만 있어도 충분한 대회죠. 하지만 팀장님은 개발해서라도 자신이 기획했던 시스템이 작동하는 것을 심사위원에게 보여주고 싶었고 그렇게 저와 디자이너 한 분이 프로젝트에 참여했습니다.
결론부터 말하자면 하나의 거대한 UAM 및 긴급 차량들의 중앙통제시스템을 기획했고 저는 그것을 구현해야 했습니다. 주요점은 다음과 같았습니다.
- 신고를 받으면 신고 위치로부터 가장 가까운 UAM 출발지에서 출발 후 도착 시간이랑 소방, 의료 차랑 출발지에서 출발 후 도착 시간 비교 후 최적경로 선택
- 이동 시뮬레이션
그리고 시뮬레이션 내용은 시나리오에 따라 달라졌는데 크게 3가지가 있었습니다.
장기 이송 / 혈액 배송 / 구급대원 출동
UAM과 운송 차량의 이동 시간 비교 후 빠른 운송 수단 선택
화제 진압
화제 지점까지 UAM과 소방차 간의 이동 거리 및 이동 시간 비교 후 다중 선택 후 출동
응급 환자 이송
사고 지점까지 UAM만 이용하여 도달 후 병원까지 운송하는 경우랑 UAM을 이용해서 사고 지점 도착 후 환자를 인계점으로 이동 후 구급차를 통해서 병원 이송이 빠른지 비교하여 최적 경우 선택
지금 생각해 보면 미친 짓이었는데 그 당시에는 해낼 수 있을 거라는 근거 없는 믿음이 있었고, 실제로도 성공했으니, 근거는 생겼습니다.
프로젝트 개발
일단 기존에 작성했던 포스트 중에 이 프로젝트에 관련된 글을 통해 프로젝트 구성을 살펴보도록 하겠습니다.
- UNREAL에 SQLITE 붙이기 – EXTENSIONS
이 프로젝트가 시뮬레이션을 통해 여러 경우를 비교 분석하고, 다양한 데이터를 사용자에게 제공해야 하는 이 프로젝트 특성상 ROUTER를 사용해서 다양한 페이지를 관리하도록 구성했습니다. - UNREAL에서 ROUTER 사용하기
그 페이지를 담당하는 데이터는 API를 통해서 다양한 다른 웹 서비스를 통해 가져왔습니다. - UNREAL 에서 API 호출하기
다만 서비스 특성상 무료로 사용할 수 있는 양은 정해져 있었고, 추가할 돈은 없었기 때문에, 사용한 데이터를 저장하고 다른 데이터를 추가로 저장하도록 데이터베이스를 사용했습니다.
그리고 다음은 블로그에는 따로 작성하지 않은 부분입니다.
A* 알고리즘을 통한 길찾기
UAM이 공중에서 길을 찾는 알고리즘은 거대한 2d 공간에서 다양한 방해물을 피해 길을 찾아야 하므로 여러가지 알고리즘을 찾았지만 임의의 공간에서 사용 가능한 A* 알고리즘을 사용했습니다.
그리고 이 임의의 공간 위에 지형 정보, 건물 정보, 기상 정보들을 통합하여 이동 가능, 불가능 노드를 설정하고 최적 경로를 찾았습니다.
Spline을 통한 Path 시각화
언리얼에서 선을 사용자에게 효과적으로 보여주기 위해서 SplineComponent를 통해 맵상에 알고리즘을 통해 찾은 결과, 혹은 네이버 맵 API를 통해서 받은 결과를 가지고 경로를 표현했습니다.
좋았던 점
가장 좋았던 점은 이 전에 인턴쉽을 진행하면서 배웠던 것을 이 프로젝트에 적용해서 개발했다는 점입니다. 웹 서비스 회사에서 인턴쉽을 진행하면서 웹 서비스를 구현하는 법을 배웠고, 이번 프로젝트에서 처음 든 생각이 이 프로젝트에 딱 알맞는 방법이 그 방법이다라는 생각이 들었죠.
또한 어려움이 있을지언정 결국 원했던 기능은 모두 구현했다는 점입니다. 다른 서비스에서 데이터를 가져와서 가공 후 사용자에게 보여지는 과정을 남들의 도움 없이 결국 해냈다는 만족감은 여간 더 할 나위가 없었습니다.
어려웠던 점
일단 블로그에 따로 작성했던 점들이 주요하게 어려웠던 점들이었습니다. 데이터베이스를 사용하려고 했는데 SQlite를 무료로 사용할 수 있는 방법이 없어서 오래된 플러그인을 수정해서 사용해야 한다던가, 사용하려고 보니 지원하지 않는 함수들이 있어서 직접 넣어줬다던가… 다양한 곳에 사용할 API를 통합해서 관리하려고 하는데 각기 다른 Callback을 만들어줘야 하는 아키텍처적 고민이라든가 말이죠.
그 외로 어려웠던 점은 Spline을 사용할 때 또 한번 나타났습니다.
언리얼에서 사용자에게 경로를 표시하기 위해 Spline을 사용했지만, 지형에 가려지거나 바닥에 박히는 등, 기존 상용 서비스와 비교하면 확실히 열등한 점을 보였습니다. 이 문제를 해결하기 위해 떠올린 방법 중 하나는 지도를 평평하게 만드는 것이었습니다. 하지만 우리 프로젝트 특성상, 3D 지형은 필수적인 요소이기 때문에 이를 포기할 순 없었고 다른 해결책을 떠올려야 했죠.
그리고 떠올린 방법은 네이버 맵 API에서 찾았습니다. 해당 API는 지형에 따라 자세하게 나눠진 좌표 값을 반환하는데, 이를 활용해 경로 사이사이의 좌표마다 맵에 Ray를 쏘아 지형의 높이를 측정하고, 그 높이에 맞춰 Spline을 조정했습니다. 이 방법 덕분에 깔끔하고 명확하게 경로를 표시할 수 있었죠.
배운 점
일단 가장 크게 배운 점은 UI와 액터들 사이에서 데이터를 교환하는 방법에 대해 크게 배웠습니다. 처음 프로젝트를 구성할 때 UI랑 액터랑 역할을 확실하게 나누고, 기능을 제한했기 때문에 서로 간의 통신이 매우 중요했는데, 이때 싱글톤이나, 게임 모드를 통해 정보를 교환하면서 다양한 활용법이랑 개선점을 떠올릴 수 있었습니다. 그리고 미숙하게 사용하여 생긴 버그들을 수정하면서 다시 한번 조심해야 할 점들을 되새겼죠.
예를 들면 하도 캐스팅을 많이 해서 그냥 만들어버린 이런 함수라던가..
그리고 언리얼에서 제공하는 TSharedPtr 을 좀 활용해야겠다는 생각을 했습니다. 이번 프로젝트에서 자꾸 포인터 관련 이슈가 터져서 해결할 방법이 없나 고민하고 있었는데 TSharedPtr을 쓰면 좀 덜하다는 이야기를 듣고 적용해보니 확실히 프로젝트 자체가 튕기는 경우가 많이 줄어들었습니다.
아쉬운 점
일단 가장 크게 아쉬운 점은 아키텍처를 웹 서비스처럼 구성해서 개발했다고 진짜 개발을 웹 서비스같이 진행했다는 점입니다. 이게 무슨 이야기냐면 컴포넌트로 묶을 수 있는 요소조차 한 페이지 안에 박아 넣어서 하나를 수정하면 다른 페이지까지 전부 열어봐서 수정해야 했다는 점이죠. 물론 나중에 컴포넌트로 빼서 개발하긴 했는데 좀 늦었다는 생각이 들었습니다.
또한 언리얼 UI에서 제공하는 기능들이 상당히 제한적인 것이 아쉬웠습니다. 물론 활용하면 못 만들 것은 없지만 그 것을 만드는 데 걸리는 시간 또한 무시할 수 없었기 때문에 이 경우에서는 가능하면 이미지를 추출해서 background 로 활용하는 방법을 택했지만 기본적으로 제공하면 좋을 것 같다는 생각을 했습니다. TabPage는 직접 구현했습니다.
이런 시뮬레이션 개발을 혼자 하는 건 한번으로 족한 것 같습니다.
후기 2편은 아마 결과가 나온 후 쓸 듯 합니다.
Leave a Reply
Want to join the discussion?Feel free to contribute!