떨리는 레버, 두 번의 헛다리 — 그리고 측정이 이겼다
지난 이야기
2부에서 나는 진동 햅틱에 한 번 처참하게 실패했다. 스위치 프로콘에서 적출한 진동 소자가 아날로그 전압으로는 꿈쩍도 하지 않았고, 그게 LRA라는 완전히 다른 종류의 소자라는 걸 알아내는 데 꽤 걸렸다. 그날의 결론은 “소자를 보드에 맞춘다” — DC 전압에 비례해서 떨리는 ERM 진동모터를 주문하고 2부를 닫았다.
그 동전만 한 3V 진동모터가 도착했다. 3부와 4부에서 블랙잭을 꽂고 화면을 꾸미는 동안 서랍에서 기다리던 물건이다. 이번 편은 그 예고를 지키는 이야기인데, 예상과는 좀 다르게 흘러갔다. 한 번 성공하고, 그 성공이 가짜라는 걸 알게 되고, 결국 추리를 포기하고 측정한 이야기다.
붙였다, 떨린다
배선은 2부에서 그려둔 그대로였다. 아날로그 출력 보드에서 전압을 내보내면 모터가 그만큼 떨린다. 레버를 당긴 정도를 그대로 전압으로 바꿔 내보내도록 로직을 손보고 — 사실 이 부분은 2부에서 이미 다 써놨던 거라 손볼 것도 거의 없었다 — 게임을 켰다.
레버를 당겼다. 부르르.
2부에서 못 한 걸 드디어 했다. 맥주가 흐르는 동안 손안에서 레버가 떨린다. 잔이 차오르는 걸 눈으로 보면서 손으로도 느끼는, 그 아케이드 기계 특유의 과잉된 피드백. 이걸로 끝이라고 생각했다.
”이거 그냥 켜지고 꺼지는 거야?”
며칠 놀다가 이상한 걸 발견했다. 레버를 살짝 열어도 떨리고, 끝까지 당겨도 떨리는데 — 세기가 똑같다. 분명히 “레버 위치에 비례해서” 만들었는데 비례가 느껴지지 않았다.
여기서 나는 두 번 헛다리를 짚었다. 부끄러우니까 짧게 적는다.
첫 번째 추리는 “데드존”이었다. ERM 모터에는 기동전압이 있다. 그보다 낮으면 정지 마찰을 못 이겨서 아예 돌지 않는다. 그래서 레버 대부분의 구간이 기동전압 아래에 깔려 있고 끝에서만 겨우 도는 거라고 봤다. 그럴듯했는데, 다시 만져보니 레버를 살짝만 열어도 처음부터 떨렸다. 데드존이 아니었다.
두 번째 추리는 회로였다. 모터가 트랜지스터를 거쳐 붙어 있으니, 그게 선형 증폭이 아니라 스위치로 포화되고 있다면 어떤 전압을 넣어도 모터에는 똑같이 전원 전체가 걸린다. 이것도 그럴듯해서 배선 바꾸는 그림까지 그렸는데 — 이 회로는 아날로그 출력에 모터를 직접 물려도 충분히 돌아가는 구성이었다. 트랜지스터 탓이 아니었다.
두 번 다 “그럴듯한 이야기”였고 두 번 다 틀렸다. 세 번째 추리를 시작하려다 멈췄다. 한 번도 실제 값을 들여다본 적이 없다는 걸 깨달았기 때문이다.
추리를 멈추고 측정하기
이 게임기의 좋은 점이 여기서 나온다. 컨트롤러는 게임 상태를 표준 통신으로 계속 내보내고 있다. 화면(HMI)이 그걸 읽어서 잔을 그리는 거니까, 나도 같은 값을 읽으면 된다.
그래서 짧은 진단 스크립트를 하나 붙였다. 게임을 자동으로 시작시키고, 따르는 동안 레버 값과 진동 출력값을 같이 기록한다. 레버를 천천히 0에서 끝까지 몇 번 훑었다.
결과는 이랬다. 레버 값이 12%에서 99%까지 움직이는 동안, 진동 출력도 정확히 따라 움직였다. 값이 고정된 구간도, 튀는 구간도 없었다.
| 레버 | 출력 전압 |
|---|---|
| 10~19% | 2.15V |
| 40~49% | 2.57V |
| 70~79% | 2.90V |
| 90~99% | 3.21V |
소프트웨어는 처음부터 정상이었다. 완벽하게 비례하고 있었다. 두 번의 추리가 찾던 범인은 애초에 없었다.
진짜 원인: 창을 잘못 열었다
문제는 저 표의 맨 위 칸이다. 레버를 살짝 열었을 때 이미 2.15V가 나가고 있었다. 내가 짜둔 출력 범위는 레버 0에서 2.0V, 끝까지 당겼을 때 3.3V였는데 — 이 모터의 정격이 3V다. 즉 게임 내내 “거의 정격”과 “정격 조금 위” 사이만 오가고 있었다. 아래쪽 절반은 아예 쓰지 않고 있었던 것이다.
여기에 한 가지가 더 겹친다. ERM 모터의 진동 세기는 전압에 비례하지 않는다. 편심추가 만드는 원심력은 회전수의 제곱에 비례하고, 회전수는 대략 전압에 비례한다. 그래서 세기는 전압의 제곱을 따라간다. 하한 2.0V는 상한 3.3V의 61%지만, 세기로 환산하면 이미 **최대의 37%**다.
37에서 100 사이. 2.7배 차이다. 숫자로는 차이가 있지만, 3D 프린팅한 플라스틱 레버를 손으로 감싸 쥔 상태에서 2.7배는 “그냥 계속 떨리는 것”으로 느껴진다. 약한 쪽이 아예 존재하지 않았던 것이 진짜 원인이었다.
창을 아래로 넓히기
고치는 건 숫자 두 개였다. 출력의 하한을 훨씬 아래로 끌어내리고, 상한은 오히려 정격에 맞춰 조금 낮췄다. 전체적으로는 더 약해지고, 약↔강 폭은 훨씬 벌어지는 방향이다.
세로축은 최대 출력을 100으로 본 상대적인 체감 세기다. 붉은 선(이전)은 시작점이 이미 37에 있어서 끝까지 당겨도 2.7배밖에 차이가 안 난다. 초록 선(이후)은 13에서 시작해 6.4배까지 벌어지고, 최대 세기는 오히려 낮다.
이제 레버를 살짝 열면 손끝에 겨우 느껴질 만큼만 떨리고, 밀어 올릴수록 확실하게 세진다. 맥주를 졸졸 따를 때와 콸콸 따를 때가 손에서 구분된다. 원래 원했던 게 이거였다.
덤 — 바텐더를 카운터에 앉히기
4부에서 세운 바텐더에도 손을 봤다. 실패했을 때 표정이 바뀌면 캐릭터가 위로 껑충 올라가는 버그가 있었는데, 원인이 두 개였다. 표정마다 그림의 세로 길이가 달랐고 — 더 결정적으로 그림 안에 나무 카운터가 함께 그려져 있었다. 배경의 바 카운터와 이중으로 겹쳐서, 캐릭터가 자기 테이블을 들고 공중에 떠 있는 것처럼 보였던 것이다.

왼쪽이 4부에 실렸던 화면. 바텐더 아래에 자기만의 나무 판이 따로 떠 있다. 오른쪽은 그려진 테이블을 잘라내고 절단선을 배경 카운터에 정확히 얹은 것. 이제 바 뒤에 서 있는 사람처럼 보인다.
원본 스프라이트를 표정별로 잘라낼 때, 각자의 여백에 맞춰 자른 게 실수였다. 다섯 장을 같은 세로 범위로 통일해서 다시 자르니 표정이 바뀌어도 눈높이가 고정된다. 배경 카운터의 위치는 이미지에서 직접 픽셀을 읽어서 찾았다.
그리고 진짜 게임기가 됐다
마지막으로 남았던 일을 했다. 그동안 이 게임기는 개발 PC를 연결해야 돌아가는 상태였다. 게임기에 붙은 터치 패널에는 블랙잭이 들어가기 전의 낡은 화면이 올라가 있어서, 버튼을 눌러도 아무 일이 없었다.
최신 화면을 터치 패널로 배포하고 자동 시작을 걸었다. 이제 전원만 넣으면 타이틀이 뜨고, 게임을 고르고, 레버를 당기면 손이 떨린다. PC는 필요 없다.
시리즈를 시작할 때 목표는 Playdate 게임 〈Root Bear〉의 크랭크 조작을 실물 레버로 바꿔보는 것이었다. 그게 다섯 편을 지나 게임 두 개가 든 독립 아케이드 기계가 됐다. 원작(© TEAM ROOT)의 아이디어에 다시 한번 감사를.
이번 편의 교훈
- “비례하게 만들었다”와 “비례하게 느껴진다”는 다른 문제다. 사람의 감각과 물리량 사이에는 제곱이든 로그든 뭔가가 끼어 있다. 출력을 선형으로 만든 것과 사용자가 단계를 느끼는 것은 별개다.
- 작동 범위의 어디를 쓰는지가 절반이다. 부품의 스펙 범위를 다 쓰고 있는지 확인할 것. 나는 정격 근처 좁은 구간만 쓰면서 “왜 변화가 없나” 하고 있었다.
- 그럴듯한 추리 두 번보다 측정 한 번. 두 번의 가설은 모두 논리적이었고 모두 틀렸다. 실제 값을 한 번 찍어보는 게 훨씬 빨랐다.
- 잘라낸 그림에는 잘라낸 사람의 실수가 남는다. 스프라이트를 각자 여백에 맞춰 자르면 정렬이 깨진다. 기준을 공유해서 자를 것.
댓글
로그인 없이 이름만 적고 남기실 수 있어요. 남긴 댓글은 바로 게시됩니다.
댓글을 불러오는 중…