들어가며
졸업을 위해서는 3학년 2학기에 캡스톤디자인I을, 4학년 1학기에 캡스톤디자인II를 수강해야 한다. 졸업 작품 만드는 강의다.
졸업 작품은 학부 생활을 마무리짓는 프로젝트인 만큼, 팀을 이루어 두 학기동안 진행된다. 한 학기 동안은 아이디어를 내고 남은 한 학기 동안 실제로 작품을 만든다.
우리 팀은 실제로 행동에 돌입하는 게 늦었다. 많이 늦었다. 겨울방학에도, 개강 후에도, 심지어 발표회가 다가와도 단톡방에 아무도 말이 없었다.
5월 중순이 되어서야 발등에 불이 떨어졌다.
5월 13일.
나의 놀고먹는 방학생활(?)을 끝내버리신 교수님의 카톡.
일정 확정
같은 날, 학과 사무실로부터 메일을 받았다. 졸업작품발표회 일정이 확정되었다고 했다.
발표회는 6월 12일. 메일을 받은건 5월 13일. 딱 30일 이 남은 상태였다.
팀 단톡방은 난리가 났고, 이대로 가다가는 다 죽겠다는 생각이 머리를 스쳤다.
아래부터는 기한 안에 뭐라도 만들어보려 발악하다 죽어간 기록이다. 아무래도 내가 맡은 파트 위주로 서술하였다.
30일의 기록
D-30
5월 13일
꿈이었으면 좋겠다고 생각했다. 10일만에 교수님이 만족할 수준으로 작동하는 구현체를 만들라니.
보여지는 것에 집중해야 했다. 도메인이고 뭐고 다 때려치우고 UI부터 만들기 시작했다. 일단 탭 네비게이션을 만들었다.
방학 동안에 열심히 만들어 놓은 라이브러리를 가져다 썼다.
그리고는 사용하지 않던 JUnit
테스트를 소스에서 지워버렸다. 이 정도면 되었다 싶어서 단톡에 보고하고 넘어갔다.
D-29
5월 14일
일단 UI를 만들어야 하니까 속이 텅텅 빈 액티비티와 프래그먼트를 만들었다. 각 탭은 각자의 네비게이션 스택을 가진다.
탭별 네비게이션을 정의하는 xml
리소스부터 각 탭을 대표하는 호스트 프래그먼트, 그리고 실제 UI가 들어가는 각 프래그먼트를 틀만 만들었다.
UI와 뷰모델을 이을 때에는 Android Jetpack의 Data binding을 사용하였다.
만들고 보니 문제가 하나 있었는데, 화면 전환시에 레이아웃이 자연스럽게 스크롤되는 것이 아니라 그냥 잘려나가는 것이었다. root에 ScrollView
를 두고, 그 안에 원래 레이아웃을 LinearLayout
으로 감싸서 해결했다.
D-28
5월 15일
비가 오는 날이었다. 이 날은 코딩은 쉬었다. 이때까지만 해도 여유가 있었다.
저녁으로 먹은 불닭볶음면. 나는 맵찔이지만 매운게 좋다.
D-27
5월 16일
앱의 얼굴인 실시간 압력 뷰 화면을 만들기 시작했다. 신발에 달린 센서 12개로부터 [0, 15]
구간의 압력 데이터가 들어온다. 이를 받아서 표시해주는 역할이다. 어떻게 만들지 한참 고민하다가 ConstraintLayout
을 상속받아 커스텀 뷰를 만들기로 했다.
커스텀 뷰는 처음인지라 상당히 낯설었는데, 프래그먼트에 inflater
로 레이아웃 씌우고 이거저거 하는 것과 별반 다르지 않았다.
지금 보면 정말 허접하다.
딱히 참조할 레퍼런스도 없고, 영감도 떠오르지 않고, 디자인을 배운 적도 없고, 그냥 이렇게 접근하면 돌아가긴 하는지가 궁금해서 대충 만들어 봤다.
D-26
5월 17일
홈 화면이라 부를 만한 것이 나왔다.
내부적으로 중요한 디자인 결정을 내렸는데, 툴바를 각 프래그먼트 아닌 부모 액티비티에 정의했다. 원래 툴바는 각 화면 레이아웃의 일부로써, 매 화면마다 따로 정의하는 것이 맞다. 다만 이 앱에서는 모든 화면에서 모두 동일한 툴바를 사용할 것이었기에 (일반적으로는 바람직하지 않은) 편법을 사용한 것이다.
iOS의 시계 앱을 많이 참고했다.
D-25
5월 18일
디자인을 극적으로 개선했다.
구글을 한참 뒤져 영감을 많이많이 얻었다. 앱 컨셉을 피트니스쪽이 아닌 테크와 의료, 조금 전문적인 방향으로 선회하면서 어둡고 있어보이는(?) 테마를 선택했다.
기적적으로 적절한 발 모양 이미지를 얻었다.
내부적으로는 style
대신 현재 테마의 attribute
를 사용하는 쪽으로 코드를 수정하였다.
예를 들어, android:background="@color/backgroundLittleDark
대신 android:background="?attr/barBackground"
를 사용하였다. 그냥 상수인 style
대신, 선택한 테마에 따라 적절한 리소스가 배정되도록 하였다.
스타일 다루는 것은 예-전에 QKSMS라는 앱을 뜯어보면서 배웠다. 그리고 여기에 잘 써먹었다. ㅎㅎ
D-24
5월 19일
보통 압력을 시각화할 때에는 열 분포와 비슷하게 표현한다. 압력이 센 곳은 빨갛게, 약한 곳은 파랗게.
이걸 도와주는 라이브러리가 있나 해서 찾아 보니 AndroidHeatMap이라는게 있었다.
AndroidHeatMap 적용 완료.
저 점 하나 하나를 마커(marker
)라고 하는데, 마커 색상을 HSV gradation으로 주게 되어 있었다.
HSV 색 공간에 대한 이야기는 예전에 모니터 캘리브레이션 할 때나 올해 초 이미지 처리 배울 때에 잠깐 들어봤던 것이 전부였다. 사진에 있는 테두리로 갈수록 투명해지는 주황색을 구현하기 위해 무식한 방법을 취했다. 컬러 코드를 조금씩 바꿔가며 타이핑과 빌드를 수백 번 반복했다.
도메인과 데이터 레이어에서는 양 신발의 센서에서 들어오는 샘플을 하나로 합치기 위해 구글과 스택오버플로우에게 빌어 두 개의 DataSource
를 가지는 CombinedLiveData
를 구해다가 사용했다. RxJava
같은 걸 쓰면 별 복잡하고 기괴한 데이터 흐름도 다룰 수 있던데, 그것에 비하면 이건 참 straightforward하다.
D-23
5월 20일
이 날부터 학교에서 남아 썩기 시작했다.
드디어 홈 화면을 레이아웃부터 뷰모델까지 끝내고 도메인-데이터 레이어에 손을 대기 시작했다.
센서의 현재 값을 LiveData
로 제공하는 SensorStateRepository
를 두고, 이를 사용하여 기기 연결과 샘플 기록을 담당하는 SensorDeviceService
를 두었다.
뷰모델에서는 실시간 센서 상태에 접근할 때에는 SensorStateRepository
를 사용하였고, 센서 모듈과 연결을 하고자 할 때에는 UseCase
를 통해 SensorDeviceService
를 호출하였다.
홈 화면에 있는 압력 뷰가 잘 작동하는지 확인하기 위해 임의의 가짜 데이터를 생성하는 로직을 두었다.
이제 하드웨어가 슬슬 준비되어야 하는데, 하드웨어 담당 팀원은 프로토타입을 만들려면 멀어 보였다.
일정상 80%는 완성되어 있어야 했다.
날씨는 좋았다.
우리 학교가 노을이 참 예쁘다.
모여서 코딩하다가 지하철 역까지 뛰어서 막차 타고 집에 갔다.
지하철역은 저-멀리에. 막차까지 남은 시간은 10분.
D-22
5월 21일
발 압력 뷰(FootPressureView
)를 여기저기서 쓰게 되었다. 이를 위해서 해당 뷰가 parent 뷰에 의해 크기가 정해질 수 있도록 수정하였다.
족저압 검사 화면을 구현하기 시작했다. 검사(diagnosis) 탭을 누르면 가능한 검사 목록이 나오고, 하나를 선택하면 검사 화면으로 넘어간다. 이때 이 넘어가는 transition에 애니메이션을 적용하였다.
휴게실에서 완성했다. 리모델링된 휴게실 참 좋다. 학비는 이런 데에 써야지 ㅎ
FootPressureView
는 압력 분포를 표시하기 위해 AndroidHeatMap
라이브러리를 사용하는데, 이 녀석이 UI 스레드에서 그래픽 렌더링을 처리하는 것이다. 이 작업은 무려 초당 100회가 넘게(센서의 샘플율이 좀 높다) 진행되는지라 화면 전환이 버벅였다. 그래서 백그라운드에서 코루틴으로 수행하도록 바꾸었다.
코루틴은 스레드와 다르게 매우 저렴하다. 하지만 스레드에 민감한 Realm
같은 녀석과 함께 사용하면 대참사가 일어날 수도 있다 (후술한다…)
정보기술대학교 휴게실 풍경
D-21
5월 22일, 교수님에게 데모 영상 제출 D-1, 포스터 시안 마감일
처음으로 밤을 샜다.
홈 화면과 진단 화면에 이어 보고서 화면을 만들었다.
당연히 데이터는 모두 뻥이다.
늘 하던 대로 프래그먼트에 RecyclerView
를 만들고, LayoutManager
는 LinearLayoutManager
로, 데이터는 뷰모델에서 꺼내서 그대로 넘겨주고, 리스트 아이템은 적당히 ConstraintLayout
으로 필요한 정보를 뿌리도록 했다.
어댑터에서는 ViewHolder
를 상속받아 적당히 뷰를 찾아 데이터를 표시하는 코드를 양산해내었다.
프래그먼트가 만들어질 때에(onCreate
) 뷰모델을 구해와서 데이터를 꺼내 그대로 어댑터에 끼워 넣어 주었다.
잘 돌아는 갔다. 포스터에 실릴 정도로 ‘멋지지가 않’ 아서 문제였지. 팀원의 피드백을 바닥부터 끌어내어 모으고 모아 코드에 그대로 녹여내어 드렸다. 결국 새벽을 지나 아침에 해가 뜨고도 점심 가까이 못 잤다. 결국 그날 약속 취소했다.
팀원들은 학교에서 밤을 샜다. 하드웨어를 담당하는 팀원이 개 뻘짓 + 삽질 을 해대는 바람에 데모 영상 촬영 당일까지 하드웨어가 준비되지 않은 탓 이었다.
상당한 환멸감이 느껴지는 날이었다.
D-20
5월 23일, 교수님에게 데모 영상 제출 마감일
총체적 난국이었다.
하드웨어 담당자는 그토록 호언장담하던 완성 데드라인도 맞추지 못한 채 삽으로 흙이나 퍼나르고 있었다. 밤까지는 데모 영상을 제출해야 하는데, 납땜 연기 몇번 마시더니 그대로 두통을 호소하며 뻗어버렸다. 어쩔 수 없이 눈속임을 사용할 수 밖에 없었다.
커밋 메시지: “Generating fake data.”
발을 세로로 4등분한 다음에 각 섹션별로 걸음 phase마다 가해지는 압력을 손으로 하나 하나 기입해가며 자연스러워 보이는 가짜 데이터 생성기를 만들었다.
아는 상태로 보면 조금 부자연스럽다.
private val phaseToSectionWeights = arrayOf(
listOf(0f, 0f, 0f, 0f),
listOf(0f, 0f, 0f, 0f),
listOf(0f, 0f, 0f, 0f),
listOf(0f, 0f, 0f, 0f),
listOf(0.25f, 0f, 0f, 0f),
listOf(0.5f, 0f, 0f, 0f),
listOf(0.75f, 0f, 0f, 0f),
listOf(1f, 0f, 0f, 0f),
listOf(1f, 0.3f, 0f, 0f),
listOf(1f, 0.6f, 0f, 0f),
listOf(1f, 1f, 0f, 0f),
listOf(0.75f, 1f, 0.5f, 0f),
listOf(0.5f, 1f, 1f, 0f),
listOf(0f, 1f, 1f, 0.5f),
listOf(0f, 0.5f, 1f, 0.75f),
listOf(0f, 0f, 1f, 1f),
listOf(0f, 0f, 0.6f, 1f),
listOf(0f, 0f, 0.3f, 1f),
listOf(0f, 0f, 0f, 1f),
listOf(0f, 0f, 0f, 0.75f),
listOf(0f, 0f, 0f, 0.5f),
listOf(0f, 0f, 0f, 0.25f),
listOf(0f, 0f, 0f, 0f),
listOf(0f, 0f, 0f, 0f),
listOf(0f, 0f, 0f, 0f),
listOf(0f, 0f, 0f, 0f)
)
한 걸음 내에서의 자연스러운 압력 변화는 저렇게 생겼다.
성공적으로 보이는 영상을 촬영, 제출하고 나니 뻗어있던 팀원이 컨디션을 회복했다.
그리고 막차를 놓친 나는 택시를 타고 집에 갔다.
지출 1만 5천원
D-19
5월 24일 (일요일)
금요일에는 원래 약속이 있다. 그 약속을 일요일로 옮겼다.
코딩에서 벗어나 잠시 행복한 하루를 보냈다.
D-18
5월 25일
하드웨어는 마감 기한을 3일째 넘긴 후에도 진전이 없었다. 이 팀원이 이걸 해낼 것이라는 희망을 그냥 접었다.
안드로이드 휴대 전화와 센서 모듈은 블루투스로 연결된다. 신뢰성 있는 통신을 위한 블루투스 연결 기반이 이날 완성되었다.
안드로이드의 블루투스 라이브러리를 다음과 같이 사용하였다:
- 페어링된
BluetoothDevice
로부터BluetoothSocket
을 가져온다. - 소켓을 열고
InputStream
을 얻어 백그라운드에서 계속 읽는다. - 프로토콜에 맞는 메시지가 들어오면 해석하여 처리한다.
한번에 잘 되면 좋았겠지만, BluetoothSocket
을 가져오는 것 부터 문제 투성이였다.
BluetoothDevice
로부터 소켓을 가져오는 createRfcommSocketToServiceRecord
메소드가 자꾸 IOException
을 토했다. 스택오버플로를 한번 산책하고 와 createRfcommSocketToServiceRecord
해결책을 찾았다.
createRfcommSocketToServiceRecord
말고 숨겨진 createRfcommSocket
메소드가 존재했다. 이는 @Hidden
처리되어 있었지만, 자바의 reflection으로 꺼내어 쓸 수 있었다. 이를 createRfcommSocketToServiceRecord
의 fallback method로 사용하여 실패하지 않는 연결을 구축할 수 있었다.
구현을 해 놓고 보니, createRfcommSocketToServiceRecord
가 실패하는 원인이 궁금했다. 구글을 한 바퀴 더 돌고 오니, 해당 메소드를 호출할 때에 인자로 UUID 00001101-0000-1000-8000-00805F9B34FB
를 넘겨주면 된다고 한다.
00001101-0000-1000-8000-00805F9B34FB
는 블루투스 프로토콜 중 시리얼 포트 서비스를 위해 사용되는 UUID 라고 한다. UUID를 변경한 후 fallback method까지 갈 것도 없이 바로 잘 연결되었다.
이 날은 비교적 이른 10시 반 즈음에 집에 갔다.
D-17
5월 26일
도메인 레이어를 완성했다.
뷰모델의 모든 동작은 UseCase
를 호출하고, UseCase
는 Service
나 Repository
에게 실제 동작을 위임한다. Service
와 Repository
는 데이터 레이어에서 구현되며, DB에 접근하거나 기기와 연결하는 등 실제 구현을 담고 있다.
D-16
5월 27일
본의 아니게 구술 발표를 하게 되었다.
아…ㅎㅎ
교수님이 시연 영상 제출하라고 지시하시던 당시에 “완성되면 구술발표 하게 해주세요” 라고 말해놓은 것이 화근이었다. 성공적으로 보이는 시연 영상이 구술 발표에 참여하고자 하는 적극적 의지의 표명으로 해석된 것.
이미 명단은 학과 사무실에 넘어갔고, 포스터 제작이 시작됐다.
완성을 해야 했다.
일단 reactive한 데이터 흐름을 위해 Realm
을 도입했다. 무려 데이터 계층부터 표현 계층까지를 한번에 이어 주는, 가장 깊은 곳에서 데이터의 변경이 생기면 그것이 바로 자동으로 뷰에 반영되게 도와 주는, zero-copy 네이티브 데이터베이스이다.
Realm
에 의존하여, 엔티티 대부분을 RealmObject
로 바꾸는 등, Realm
으로의 전환을 마쳤다.
이날 신발 센서 모듈 절반이 완성되었다며(절반은 작동하지 않는다 함) 팀원이 사진을 보내 왔다.
이때부터 매우 불길한 예감이 들었다.
그래도 날씨는 좋았다.
오후 4시 29분.
D-15
5월 28일
하드웨어가 팀원 손에서 완성되기를 기대하기 어려워졌다. 추가로 재료비를 신청하여 새로운 설계로 다시 만드는 방법을 추진하였다. 당장 재료비 신청이 다음날까지 였고, 학교에 도착한 시간이 오후 6시였다.
머리에 떠오른 구상대로 디바이스 마트에서 장바구니에 담고, 압력 센서를 가장 빨리 조달할 수 있는 국내 기업을 찾았다. 해당 기업 고객센터에 연락하여 결제 후 당일 발송된다는 소식을 듣고 구매처를 결정하였고, 구매할 품목을 엑셀로 작성하여 교수님의 승인을 받은 뒤 빠르게 학과 사무실에 전달하였다.
구술 발표 순서가 나왔다. 우리 팀은 10팀 중 8번째. 그나마 다행이었다.
이 프로젝트에서 앱이 의존하는 존재는 센서 모듈
과 서버
이다. 개발 과정에서 둘 다 사용 가능한 경우는 거의 없었기에, 둘 없이 앱을 온전하게 굴리면서도 기능을 테스트할 수 있는 방법이 필요했다.
안드로이드가 지원하는 product flavor를 사용했다. 실제 서버
/목업 서버
와 실제 센서 기기
/가상 센서 기기
, 이렇게 총 4개의 경우에 따라 다른 소스 세트를 사용하여 빌드하였다.
블루투스 목업(가상 센서 기기)은 이전에 만든 FakeDataGenerator
의 출력을 마치 블루투스 소켓을 통해 전달받는 것처럼 가상화하여 준다.
D-14
5월 29일
소프트웨어는 안정기에 접어들었다.
앱에 아이콘과 스플래시 스크린을 추가하고, 검사 화면을 이탈할 때에 타이머가 멈추지 않는 버그를 해결하였다.
다만 이때까지도 하드웨어는 준비되지 않았다. 데이터 분석을 담당하는 팀원은 분석할 데이터를 수집하지 못해 큰 어려움을 겪었다.
D-13
5월 30일
이 날은 카카오 바이크를 탔다 :)
그리고 지하주차장에 주차해서 정지를 먹었다.
서버와의 통합을 시작하였다.
앱 내의 저수준 데이터 분석기의 출력을 서버로 전달하는 부분을 작성하였다.
Retrofit2
를 사용했다. 늘 하던 대로 인터페이스를 정의하고 모델을 정의했다. 팀원이 작성한 서버의 API 문서가 확정되지 않아 초반에 어려움을 겪었다.
서버에서 반복적으로 500
에러가 발생하여 원인을 찾아내느라 테스트에 애를 먹었다.
D-12
5월 31일
서버와의 통합이 마무리되었고, 서버 목업도 작성을 마쳤다.
회원 관리 체계를 도입하면서 로그인 화면과 회원가입 UI를 추가하였다.
그리고 하드웨어는 결국 완성되지 않았다. 센서마다 물리적 특성도 다르고 입력값이 상당히 불안정했다.
프로토타입의 프로토타입
D-11
6월 1일
최종 발표 영상 제출 마감이 9일 남은 시점에서 하드웨어가 이 모양이었다.
망했음을 직감했다.
앱은 완성 단계에 이르렀으나, 하드웨어가 더 이상 팀원에게 맡길 수 없는 지경까지 가버렸다. 신청한 재료가 도착하면 바로 실행에 옮겨야 헀다.
일단 도면을 그렸다.
종이에 볼펜
그리고 디지털로 옮겼다.
Graphics
회로는 아래처럼 브릿지 보드를 사용하여 제작할 계획을 세웠다.
D-10
6월 2일
부품이 도착했다.
압력 센서와 브릿지 보드를 집에서 택배로 수령하고, 디바이스마트에서 구매한 부품은 마침 근처라 방문수령하였다.
디바이스마트가 집 앞에 있다.
압력 센서를 MCU와 연결하는 데에 필수인 pull-down 브릿지 보드 3개를 연장하여 12채널 브릿지 보드를 제작하였다.
직접 만든 12채널 브릿지 보드. 정성스런 50포인트 납땜.
D-9
6월 3일
슬슬 마감의 압박이 찾아오기 시작했다.
나머지 한 쪽 브릿지 보드도 제작을 마쳤다.
케이블도 만들었다. 소켓은 몰렉스 5264.
그리고 바로 센서 패널(깔창 부분) 제작에 착수했다.
아름답지는 않다.
제작 도중 예상치 못한 복병을 마주했다. 케이블이 너무 두꺼워서 얇게 만들 수가 없는 것. 주문제작형 인쇄 박막 기판을 만들자니 돈과 시간이 없고, 피복 달린 케이블을 그대로 쓰자니 내구도와 완성도가 심각하게 떨어질 것 같았다.
한참 동안 구글신에게 빌어 영감을 얻는 뒤 내린 결론은, 구리 박막을 전선으로 하여 flex PCB를 직접 만들자 는 것이었다.
D-8
6월 4일
이날은 새벽부터 시작했다. 잠을 잘 수가 없었다.
구리 박막은 없지만 구리 테이프는 있었다. 구리 테이프를 가공하려면 비닐 커터가 필요하다. 그런데 당장 비닐 커터를 대여해서 사용할 수 있는 곳이 생각나지 않았다. 다른 대안을 찾아야 했다.
혹시나 학교 4호관에 새로 생긴 Maker space에 장비가 있나 싶어 홈페이지를 찾아가 보았다. 비닐 커터는 없었지만 레이저 커터가 두 대나 있었다. 레이저 커터에 대해 알아 보니, 얇은 재료는 물론, 어느 정도 두꺼운 재료도 깔끔하게 잘라내는 도구였다. 바로 예약을 하고 도면을 그렸다.
맥의 Graphics 앱 사용, 앱스토어에 있다.
레이저 커터에게 작업을 지시해야 하니, 도면을 일러스트레이터로 옮겨서 .dxf
포맷으로 export했다.
3D 미리보기
잠깐 동안 잠을 잔 뒤에 학교로 이동하였다.
레이저 커터에 재료를 넣고 도면을 업로드하여 가공을 시작하였는데, 구리 테이프가 잘리지 않았다. 이게 무슨 일인가 싶어 같은 위치에 종이를 두었더니 잘 잘렸다. 금속은 아무리 얇아도 자를 수 없는 모양이었다.
구리 테이프에는 흠집조차 나지 않았다.
결국 가내수공업을 택했다.
구리 테이프에 도면을 붙여 가위로 수동 가공(…)
여기서 팀워크가 빛을 발휘했다. 아주 빠른 시간 안에 모든 배선을 가공해 내었다.
가공 후 딱풀로 붙였다.
자정이 지나기 전에 한쪽을 완성했다.
센서와 구리테이프는 얇은 배선과 납으로 연결했다.
나머지 한 쪽은 밤에 학교에서 머무르며 만들었다.
D-7
6월 5일
이미 한 쪽을 만들어 놓은 터라 레퍼런스와 노하우를 모두 보유하고 있었다. 덕분에 다른 한 쪽은 훨씬 깔끔하게 만들 수 있었다.
깔끔한 순간접착제 마감
말리는 중.
그렇게 다 완성하고 아침 8시에 학교를 나왔다.
안개가 가득 꼈다.
D-6
6월 6일
마감 작업을 시작했다. 신발 속에 들어가서도 파손되면 안 되며, 적당히 유연해야 했다. 팀원의 아이디어를 차용하여 절연테이프로 센서 패널을 마감하였다.
폭이 아주 넓은 전기테이프가 있었으면 하는 바람이었다.
그렇게 하나의 세트가 완성되었다.
왼쪽부터 배터리, MCU 보드, 블루투스 모듈, 브릿지 보드, 센서 패널.
나머지 한 쪽도 완성한 후 테스트를 진행하였다.
기대한 만큼 잘 작동하였다.
D-5
6월 7일
이 날은 집에서 편히 쉬다가 발표 자료를 만들었다. 발표에 할당된 시간은 5분이었는데, 구현 이야기로 채우니 심히 모자라 아쉬웠다.
D-4
6월 8일
정보대 앞
마감 완료한 패키지를 신발에 장착하였다.
신발, 앱, 서버와의 연동을 점검하고 최종 발표 영상에 넣을 시연 영상을 촬영했다.
D-3
6월 9일, 최종 발표 영상 제출 D-1.
역할이 사라진 (전)하드웨어 담당 팀원이 영상 편집을 맡겠다고 나섰다.
영상 제출까지는 30시간 이상이 남은 상태.
D-2
6월 10일, 최종 발표 영상 제출 마감.
영상 제출 마감은 오전 11시였다. 편집을 맡겠다고 했던 팀원은 전날 확보해둔 24시간을 모두 소비하고 자정이 지나서야 편집을 시작하였다. 이마저도 노트북의 퍼포먼스나 전원 공급 문제로 차질이 생겨 아침까지 최종 렌더링된 편집본을 받아볼 수 없는 상황이었다.
결국 내가 했다.
IdeaBoom 사이트에 올라갈 상세 설명도 작성하였다. HTML 에디터를 지원하기에, 원하는 것을 모두 표현할 수 있었다.
D-1
6월 11일, 졸업작품발표회 D-1.
IdeaBoom에 올라간 작품에 좋아요가 몇 개나 달리는지 구경했다.
발표회 당일 시연을 위해 리허설을 진행하였다. 프로젝트 특성 상 휴대전화 화면과 사람이 걷는 모습을 동시에 보여 주어야 했기에 다음 옵션들이 후보에 올랐다.
- 휴대전화 화면과 사람이 걷는 모습을 동시에 카메라에 담기.
- 휴대전화 화면을 미러링하고, 사람이 걷는 모습을 카메라에 담아 화면 분할로 표시하기.
가시성과 깔끔함을 위해 후자를 택하였다.
D-0
6월 12일, 졸업작품발표회 당일.
아침 일찍 학교에 모였다.
카메라를 고정하기 위해 삼각대를 들고 갔다.
휴대전화와 신발을 연결하고, 화면을 컴퓨터에 미러링하였다. 카메라를 설치하고 컴퓨터에 연결하여 두 화면을 동시에 띄워 Zoom 화면 공유로 송출하였다. 약간의 딜레이 이슈가 있어 여러 솔루션을 검토해 보았고, LTE-핫스팟
+ TeamViewer
환경에서 가능한 가장 만족스러운 품질을 얻을 수 있었다.
앞에 7팀이 있어 우리 팀까지 오는 데에 시간이 조금 걸렸다. 교수님의 질문은 역시 날카로웠다. 긴장이 되면서도 한편으로는 빨리 끝났으면 좋겠다는 생각이 들었다.
우리 팀의 차례가 되어 시연을 시작하였다. 초반에 연결 문제로 1분 가량 심장이 떨리는 일이 있었지만 다행히 너그럽게 넘어가 주셨다. 시연이 끝난 후 질의응답 시간이 찾아왔다. 데이터 분석을 담당한 팀원은 전문성을 드러내며 좋은 답변을 내놓았다. 나는 방심하고 또 긴장한 탓에 구현 과정에서 느끼고 배운 것들을 절반도 꺼내지 못했다. 아쉽긴 하였으나 최악은 면하였다.
발표회는 일정보다 이르게, 정오에 끝났다.
밖에 나가 보니 공대 앞에 장미가 만개하였다.
마치며
CPU에게 일 시키는 것에 특화된 컴퓨터 공학 전공자에게 있어 실제 세계에서 물리적인 일을 하는 것은 전문 영역 밖의 일이다. 하드웨어를 만들면서 공학 전공과목 하나 들은 적 없는 내가 공대와 친해진 기분이 들었다.
소통과 협업 능력이 항상 화두가 되는 것은 그것이 중요하지만 부재하는 경우가 많기 때문일 것이다. 나 또한 예외가 아니어서, 서로 지향하는 가치가 다른 경우에 미숙하게 대처하는 우를 범하였다. 개발자로서는 1인분 이상을 해내었으나 팀장으로서의 책무를 다하지 못한 것에 책임감을 느낀다.
이제는 다 끝나서 다행이라는 생각이 든다. 너무 많은 인내력을 이 프로젝트에 소비해 버렸다. 당분간은 쉬고 싶다.
댓글