2026년 6월 17일 수요일

Fluid Ardule, 드디어 '돌리고 누르는' 손맛이 살아났다

오늘(실은 자정이 지났으니 어제 6월 16일)은 Fluid Ardule의 새로운 기능을 추가하지 않았다. 그럼에도 불구하고 사용감은 그 어느 때보다 크게 좋아졌다. 어쩌면 이런 종류의 개선이야말로 완성도를 높이는 데 가장 중요한 작업인지도 모르겠다.


그동안 가장 마음에 걸렸던 것은 로터리 인코더였다. 천천히 돌릴 때는 별 문제가 없었지만, 조금만 빠르게 돌리면 메뉴가 손의 움직임을 따라오지 못했다. 분명 다섯 칸 정도를 돌렸는데 두세 칸밖에 이동하지 않는 경우도 있었다. 인코더의 문제가 아니라 소프트웨어가 사용자의 의도를 제대로 받아들이지 못했던 것이다.

원인을 추적해 보니 두 군데를 손봐야 했다. 먼저 Arduino UNO-1의 운영용 펌웨어는 인터럽트(Interrupt Service Routine, ISR)를 사용하지 않고 주기적으로 인코더 상태를 읽는 방식이었다. 이를 ISR 기반으로 바꾸자 빠르게 돌려도 입력이 거의 누락되지 않았다. 여기에 버튼 디바운스 시간도 조금 줄여 조작감을 한층 경쾌하게 만들었다.

하지만 이것만으로는 부족했다. UNO는 ENC:+3처럼 "세 칸 움직였다"는 정보를 정확히 보내고 있었는데, Raspberry Pi의 Python 프로그램은 이를 결국 "아래로 한 칸"이라는 버튼 입력처럼 처리하고 있었던 것이다. 결국 Python 쪽도 수정하여 ENC:+N이라는 이동량(delta)을 그대로 메뉴 이동에 반영하도록 바꾸었다. 이제는 빠르게 인코더를 돌리면 실제 손의 움직임만큼 메뉴가 자연스럽게 스크롤된다.

흥미로운 점은 이번 업데이트에서 새로운 기능은 단 하나도 추가되지 않았다는 사실이다. 그럼에도 한 화면(5~6 줄 정도)을 드르륵 돌리면 누락 없이 시원하게 넘어가는 모습을 보니 마치 전혀 다른 제품을 사용하는 느낌이다. 전자악기에서 중요한 것은 화려한 기능보다도 손의 움직임에 얼마나 자연스럽게 반응하느냐는 점인데, Fluid Ardule도 이제는 그 기준에 한 걸음 더 가까워진 것 같다.

물론 아직 완벽한 것은 아니다. 아주 빠르게 돌리면 가끔 한 칸 정도 더 이동하는 경우가 있고, TFT-LCD의 화면 갱신도 Windows처럼 즉각적으로 이루어지는 것은 아니다. 그러나 이것은 Raspberry Pi 3B와 SPI TFT라는 하드웨어 구조가 가진 한계에 가까운 문제다. 중요한 것은 입력 자체를 잃지 않는다는 점이며, 오늘 그 목표는 거의 달성했다고 생각한다.

개발을 하다 보면 새로운 기능을 만드는 날보다 기존 기능을 다듬는 날이 더 뿌듯할 때가 있다. 오늘이 바로 그런 날이었다. 기능 목록은 어제와 똑같지만, 손끝으로 느껴지는 Fluid Ardule는 분명 어제보다 한 단계 더 성숙해졌다.

직경 13mm짜리 알루미늄 노브(구입처: 엘레파츠 EPXJ6BGX). 기기를 조작하는 즐거움은 이렇게 직접 손으로 조작하는 부품에서 온다.

어제도 알리익스프레스에서 '마무리 작업용' 부품을 주문하였음을 솔직하게 시인한다.

2026년 6월 15일 월요일

Fluid Ardule, 드디어 모습을 찾다

프로토타입 형태로 테스트해 왔던 Fluid Ardule이 드디어 제대로 설계하여 만든 인클로저와 함께 재탄생하였다. '제대로 설계'한 것이 맞기는 할까? 생애 두 번째로 그린 CAD 도면을 실제 결과물로 받아보니 마음에 들지 않는 구석이 눈에 뜨였기 때문이다. 

2026년 6월 15일의 Fluid Ardule.


GitHub 프로젝트 사이트 또한 이에 맞추어서 새로운 자료를 추가하였다. 외형은 완성 모드에 진입하였으나, 보고 있으면 개선할 점이 자꾸 보인다. 알리익스프레스를 통한 부품 구입은 도무지 끝이 보일 기미가 보이지 않는다. 마무리 작업에서 가장 신경을 많이 쓴 것은 바로 커넥터 활용 문제이다. 지금은 듀폰 커넥터를 이용하여 아주 편리하게 배선을 하여 왔지만 진동이나 반복적인 사용에는 취약할 수밖에 없다. 조금 번거롭더라도 기판 형태의 것을 위에 끼운 뒤 커넥터를 달아 주는 것이 바람직하다. 

  1. 라즈베리 파이를 TFT-LCD로 연결하는 리본 케이블을 짧은 것으로 교체
  2. 접촉 불량을 야기하기 쉬운 듀폰 커넥터를 점진적으로 커넥터로 교체(라즈베리 파이, 아두이노 우노 전부 해당) 
  3. 전면 패널의 헤드폰 잭을 long thread용으로 교체(패널이 3mm로 너무 두꺼워서 너트가 충분히 잠기지 못함) → 패널 뒤에서 10mm 드릴날을 손으로 돌려 구멍을 넓혀서 해결함. 약 0.5mm 정도만 너트가 더 들어가면 되는 상황이라서 이런 임시 조치가 통했다.
  4. 후면의 외부용 5V 출력 단자의 용도 변경: 3.5mm TRS 커넥터를 달아서 CP2102 USB to UART 어댑터 연결용으로 활용

제품화를 염두에 둔 것은 아니지만. 프로토타입은 어디까지나 프로토타입일 뿐이다. 이번 작업을 마무리하는 단계에 접어들면서 꼭 1년 전에 쓴 글 세상의 모든 커넥터(링크)를 몇 번이나 업데이트했는지 모른다. 버그 없는 프로그램을 짜는 것도 중요하지만 실제 눈으로 보고 손으로 만져서 작동하는 물건은 신뢰성 높게 만들어야 한다. 그러려면 심사숙고를 거쳐 면밀히 계획하고, 좋은 부품을 써야 함은 당연하다. 2026년 상반기의 작품 하나를 이렇게 건졌다.


2026년 6월 12일 금요일

Terps란 무엇인가 - 워싱턴 D.C.를 짧게 둘러보고 출장을 마무리하다

워싱턴 D.C. 인근의 요즘 날씨는 장난이 아니다. 오후에 잠깐 비가 쏟아지다가 그치고 이내 뜨거운 햇볕이 쪼이면서 숨이 막힐 지경으로 습도가 높아진다. 6월 중순이 이러니 한창 더운 칠팔월에는 어떻게 견뎌 나가야 할 것인가? 정말 기후가 예전과는 많이 달라졌다.


이런 상황에서 외출을 하기가 너무 어려워서 근처 상점에서 모자를 하나 샀다. 'Terps'라는 빨간 글씨가 새겨져 있었다. 스포츠 팀의 이름 같은데 전혀 들어본 일이 없었다. 검색을 해 보니 미국 메릴랜드 대학교 컬리지파크(UMD)의 공식 스포츠 팀 명칭인 메릴랜드 테라핀스(Maryland Terrapins)의 줄임말이라고 한다(공식 홈페이지). 메릴랜드주를 상징하는 거북이의 이름이라던가...


이번 출장길의 유일한 기념품.


UMD의 상징, Testudo(사진 출처 링크). Testudo는 라틴어로 거북이를 뜻한다.



UMD는 지리적 이점을 바탕으로 FBI의 주요 연구 파트너 역할을 하며, 특히 FBI에 가장 많은 졸업생이 진출하고 있다고 한다. UMD의 범죄학 및 형사사법학과(Department of Criminology and Criminal Justice, CCJS)는 미국 내에서도 독보적인 위치를 차지하고 있다니 정말 흥미롭다. 즉흥적인 쇼핑이 뜻하지 않게 상식을 넓혀 주었다.

INSDC 연례 회의는 6월 11일 오전에 모든 공식 일정이 끝났다. 귀국 항공편은 내일이라서 잠깐 시간을 내서 링컨 기념관 근처를 가 보기로 했다. 이른바 '내셔널 몰' 일대를 제대로 보려면 두어 시간으로는 어림도 없을 것이다. 레드 라인을 타고 오가는 시간(왕복 약 두 시간)을 포함하여 딱 네 시간만 투자하자고 생각하고 호텔을 나섰다. Rockville의 Twinbrook 역에서 Farragut North 역까지 간 뒤 또 남서쪽으로 약 1.4 마일을 걸어야 한다.

데이비드 글래스고 패러것(David Glasgow Farragut). 미국 해군 역사상 최초의 4성 제독.


링컨을 만나러 가는 길은 너무나 멀고 더웠다. 새로 사서 신고 온 신발이 불편하여 발바닥에서는 슬슬 물집이 잡히기 시작하였다. 독립 250주년 행사를 위해 시설물을 설치하고 리허설을 하느라 매우 정신이 없고 어수선하였다.






남쪽으로 계속 내려가니 그 유명한 워싱턴 기념탑이 보인다. 저쪽으로도 박물관이 있을텐데!


서쪽으로 방향을 틀어서 제2차 세계대전 기념비를 지났다. 분수에서 발을 적시는 사람들이 많았다.






링컨 기념관 앞의 Reflecting Pool은 그 크기가 무려 619m x 51m나 된다. 저 멀리 링컨 기념관이 보인다. 불볕 더위에 땀을 뻘뻘 흘리며 다가갔으나...


행사 준비 관계로 올라가는 계단이 차단된 상태였다. 출입증을 목에 걸고 있는 관계자와 같은 사람들만 듬성듬성 보일 뿐이었다. 거대한 링컨 조각상을 가까이서 바라보면서 뭔가 영감을 얻고 싶었지만 그 기회조차 차단되어서 너무나 아쉬웠다. 솔직히 말하자면 관촉사나 대조사의 보살상을 찾아가는 순례자의 심정이었다. 하지만 눈앞까지 가서도 만날 수 없었으니 그 아쉬움이 더욱 컸다.



알링턴 메모리얼 브릿지 쪽에서 찍은 사진.

아쉽지만 기념관 남동쪽에 가까이 위치한 한국전쟁 참전 기념공원(Korean War Veterans Memorial)으로 향했다. '자유는 공짜가 아니다(Freedom is not free)'라고 새겨진 글씨가 인상적이었다.





OUR NATION HONORS

HER SONS AND DAUGHTERS

WHO ANSWERED THE CALL

TO DEFEND A COUNTRY

THEY NEVER KNEW

AND A PEOPLE

THEY NEVER MET

우리 국가는 한 번도 알지 못했던 나라와 한 번도 만나 본 적 없는 사람들을 지키라는 부름에 응답한 아들딸들을 기린다.

휴전 이후 한반도 남쪽에서 우리가 자유와 번영을 누리게 된 데에는 이러한 미군의 희생이 크게 기여하였음을 인정해야 한다. 그것도 가까운 이웃나라가 아니라, 생전 알지도 못하던 이역만리 먼 나라의 젊은이들이었다. 이 전쟁에서 미군 약 3만 6천 명이 목숨을 잃었다. 결코 작은 숫자가 아니다. 참고로 2차대전에서 목숨을 잃은 미군은 무려 40만명에 달한다.

참전 희생자의 가족에게는 큰 슬픔이지만, 미국 정부로서는 참전을 결정하게 된 다른 전략적 이유도 있었을 것이다. 냉전이라는 시대적 배경 속에서 공산주의 확산을 저지하고 동아시아 질서를 유지하려는 현실적 계산이 작용했음은 부인하기 어렵다. 그러나 한국전쟁 참전 기념공원의 비문은 그러한 국가적 이해관계가 아니라, 그 결정의 결과로 목숨을 잃은 젊은 병사들의 희생을 기억하려는 문장으로 읽힌다.

한국전쟁 사망자 수를 조금은 다른 시각에서 바라보자.


군인에 비해 민간인의 희생이 훨씬 크다. 또한 북한군의 사망자 수는 미군과 기타 유엔군은 물론, 한국군의 희생을 크게 웃돈다. 먼저 침략을 감행하였으니 이러한 결과를 당연한 대가로 보아야 할까? 전쟁을 일으킨 책임과 전장에서 목숨을 잃은 개별 병사의 죽음은 반드시 같은 차원에서 논할 수만은 없다.

목숨은 누구에게나 소중하다. 미국은 자유를 지키고 공산주의의 확산을 막기 위해 참전했다고 설명한다. 중국 역시 압록강까지 진출한 유엔군에 대응하고 자국의 안보를 지키기 위해 참전했다고 주장하였다. 각국 정부가 내세운 명분의 타당성은 별도로 평가할 문제이겠지만, 전장에서 죽어 간 병사들 대부분은 그러한 국가적 결정에 따라 동원된 평범한 젊은이들이었다는 사실 또한 잊어서는 안 된다. 순전히 그들이 자유의지로 결정된 것이 아니다.

물론 이러한 모든 논의의 출발점에는 북한의 남침이라는 사실이 존재한다. 그러나 전쟁의 책임을 논하는 일과 전쟁의 희생자를 바라보는 일은 반드시 같은 문제는 아니다.

이렇게 미국 메릴랜드주 락빌에 위치한 호텔방에서 이런저런 성찰을 하면서 국외 출장의 마지막 밤을 보낸다. 출장 결정까지 많은 우여곡절이 있었고, 개인적으로도 많은 결심을 하게 되었으며, 어느 정도의 성과도 있었다고 생각한다.

건너편 건물 유리창에 비친 EVEN Hotel Rockville의 불빛. 왼쪽 아래에 삽입한 사진은 호텔 공식 페이스북(링크)에서 가져온 것이다. 

2026년 6월 10일 수요일

제39회 INSDC 연례 회의에 참석하다

INSDC(International Nucleotide Sequence Database Collaboration)란 전 세계 생명과학 연구자들이 생산한 DNA·RNA 염기서열 데이터를 수집·보존·공유하기 위해 운영되는 국제 협력체이다. 미국 NCBI의 GenBank, 유럽의 European Nucleotide Archive(ENA), 일본의 DNA Data Bank of Japan(DDBJ)이 공동으로 참여하며, 어느 한 곳에 등록된 데이터는 세 기관에 자동으로 공유된다. 

1980년대부터 이어져 온 이 협력체는 생명과학 분야의 대표적인 오픈사이언스 성공 사례로 평가받으며, 오늘날 유전체 연구와 바이오인공지능(AI)의 발전을 가능하게 한 핵심 공공 인프라 가운데 하나이다. 연구자들은 누구나 무료로 데이터를 등록하고 활용할 수 있으며, 이를 통해 연구의 재현성과 데이터 재사용성을 높이고 전 세계적인 지식 공유를 촉진하고 있다.

우리나라의 KOBIC(Korea Bioinformation Center, 국가생명연구자원정보센터)은 일종의 옵저버 자격으로 INSDC 연례 회의에 4년 연속 참석하고 있다. 이렇게 된 데에는 KOBIC과 오랜 협력관계에 있었던 DDBJ의 도움이 매우 컸다. 원래 이 회의는 미국-유럽-일본 순으로 매년 돌아가면서 개최된다. 작년 영국에 이어서 올해는 일본이 개최할 순서였지만, DDBJ가 한 해를 미루어서 내년에 40주년 기념 행사와 더불어 개최하기를 희망함에 따라 올해는 2년 만에 다시 미국에서 열렸다. 

행사가 열리는 Bethesda North Marriot Hotel & Conference Center.


한국(KOBIC)에서는 나를 포함하여 총 세 명이 참석하였다. 나는 이 미팅에는 처음 참석한다. DDBJ쪽 주요 인사들(Masanori Arita, Yasukazu Nakamura, Yuichi Kodama, 그리고 한국인인 이경범 박사님, 링크)는 국내외를 오가며 여러 차례 만나서 이미 친숙한 인물들이다.

2024년, INSDC는 회원 기관을 확장하겠다는 의지를 공식적으로 표명하였다(링크). 여기에는 한국의 KOBIC, 중국, 인도(IBDC) 등이 높은 관심을 보이고 있다. 중국에는 꽤 많은 생명과학 데이터센터가 있는데, 오늘의 발표에서는 CNSDC(CNGDC였나?)가 단일 창구 역할을 하는 것으로 결정했음을 밝혔다.

NCBI의 Acting Director인 Kim Pruitt가 인삿말을 하고 있다. 2년 전 워싱턴 D.C.에서 열렸던 AI-바이오과학 협력회의에서 그녀의 발표를 들은 일이 있다(관련 글). RefSeq를 만든 장본인이라고 생각하면 된다.

Prospective member는 기술적 역량에 더하여 다음의 사항도 충족해야 한다. 이는 매우 중요한 기준이므로 잘 명심해 두어야 한다.

  • 장기적 운영 지속성
  • 데이터 공개 정책
  • 국제 협력 의지(outreach)
  • 안정적인 재원
  • 데이터 교환 능력

3개 회원 기관 및 3개 prospective member의 발표를 들은 뒤에는 실무진 소그룹에서 논의한 의제를 놓고 활발한 토론이 이어졌다. 생물학적 데이터 센터의 모임이므로 당연히 인공지능에 대한 이야기가 첫날부터 쏟아져 나와야 할 것 같은데 전혀 그렇지 않았다. 물리적 실체가 없이 컴퓨터로 만든 서열의 취급 문제가 거론되기는 했으나, 점차 제출량이 증가하고 있는 MAG(metagenome-assembled genome) 관련 사항과 TPA(third-party annotation)에 대해서 장시간 토론이 이어졌다. 예를 들어 MAG 데이터는 ENA의 경우 한 species에 대해 대표적인 것 하나만 등록하는 것이 원칙이지만, NCBI는 그렇지 않다. 사실 prokaryote의 종 내 다양성은 상상을 초월하는 것이라서, 대표성은 strain 수준으로 더욱 레벨을 좁혀야 한다는 말이 나올 수 있다. 또한 shotgun metagenome 데이터는 제출된 MAG에 의존할 수도 있으나 raw data를 직접 다운로드하여 각자의 파이프라인으로 조립해서 활용하려는 연구자가 꽤 많다.

한 방에 모인 참가자들이 각자 노트북 컴퓨터로 Teams에 접속해 사용하는 모습은 조금 특이했다. 우리나라 같으면 현장 참여자의 경우 발표자가 아니면 개별적으로 Teams나 Zoom을 켜지는 않을 텐데 말이다. 테이블에 비치된 마이크와 노트북의 마이크가 동시에 켜져 있으면 피드백이 발생하여 매우 곤란하다. 잠깐 동안 잡음을 유발했던 장본인은 Teams 사용법에 익숙하지 않았던 나였다!

EC(Executive Committe)의 2026년도 최우선순위 업무.

AI 학습을 위해 메타데이터의 필수 항목을 늘리고 더욱 점검을 강화해야 한다, 등록된 데이터의 활용 방안을 강구해야 한다, 이용자를 위해 클라우드 기반 컴퓨팅 자원을 제공해야 한다... 우리나라 환경이라면 요즘 단골로 나오는 이러한 주제는 내가 알아듣기로 거의 나오지 않았다. 물론 내일 있을 2일차 오전 발표에서 DDBJ는 GLM-based annotation system에 대하여 발표를 할 예정이라고 하였다. 

나로서는 정말 신선한 경험이었다. 모든 연구자가 AI를 향해서 '받들어 총' 자세를 취하고, AI 학습을 용이하게 만들어 줄 '데이터셋'을 얼마나 확보하고 있느냐고 질문을 받는 묘한 분위기에만 절어 있다가 '디톡스'를 하고 온 느낌이었다. 물론 오늘 1일차 공식 일정을 마치고 저녁을 먹는 자리에서는 AI 기술에 대한 피로감을 다들 토로하였지만... 아니, 우리나라는 정말 누구에게나 기본이 될 만한 레퍼런스 데이터를 만들어서 과학계에 기여한 적이 있었나.

제39회 INSDC 연례회의 첫날 자리에서 내가 느낀 것은 신기술을 얼마나 빨리 수용하고 있는지를 자랑하는 분위기가 아니었다. 오히려 모든 연구자에게 공평하게 제공될 생물학 서열 데이터를 얼마나 정확하고 안정적으로 보존하고 서비스할 것인지에 대해 진지하게 고민하는 모습이었다. 유행은 바뀌어도 공공 데이터 인프라의 가치는 쉽게 변하지 않는다는 사실을 다시 생각하게 되었다.

INSDC 회원은 데이터 표준안을 수립하는 권위가 있지만(오해하지 말기를. 제출자를 불편하게 만드는 필수 항목이 잔뜩 들어 있는 표준안이 아니라, 'minimum standard' 방식으로 접근한다), 동시에 전 세계 연구자들이 의존하는 데이터를 장기간 안정적으로 보존하고 서비스해야 하는 의무도 따른다.

따라서 '국내 연구데이터나 잘 모아서 국내 활용이나 잘 되게 하면 되지, 무엇하러 외국 데이터를 미러링하는가?'라는 단순한 논리를 따라서는 안 된다. 이번 회의에 참석하면서 INSDC 회원 자격이 단순한 명예나 지위가 아니라는 사실을 새삼 느꼈다. prospective member에게 강조되는 기준 가운데 하나가 바로 outreach이다. 이는 단순한 홍보 활동이 아니라 국경을 넘어 연구자와 기관을 연결하고, 글로벌 지식 생태계에 기여하려는 의지를 뜻한다. 우리나라도 언젠가는 데이터를 소비하는 나라를 넘어 공공 데이터 인프라를 제공하고 유지하는 나라로 한 걸음 더 나아갈 수 있기를 기대한다.

2026년 6월 6일 토요일

5개의 누름버튼을 하나의 아날로그 입력으로 읽는 방법

아두이노 응용 DIY에서 다섯 개의 누름버튼 스위치 조작을 입력하는 가장 간단한 방법은 버튼 하나에 대해서 디지털 입력 하나를 할당하는 것이다. 노이즈에도 강할 것이고, 동시 누름도 인식할 수 있다. 그러나 '귀한' 디지털 핀을 이렇게 소비하는 것은 너무 아깝다. 버튼 수만큼 디지털 핀이 필요함은 당연하다.

아날로그 입력 핀 하나를 이용하여 여러 개의 버튼 입력을 소화할 수 있는 방법이 있다. 사실 Fluid Ardule의 개발 전에는 전혀 몰랐던 기법이었다. 이는 전기 또는 전자공학 전공이라면 누구나 알 만한 기초적인 지식일 것이다. 알리익스프레스에서는 이미 이러한 용도의 5-button keypad module을 판매하고 있다. 

실제로 사용해 보면 약간 까다로운 면이 없지는 않다. 아날로그 입력값이 가끔 흔들리므로 보정을 해 주어야 하기 때문이다. 이 보정 기능을 구현하느라 아두이노 펌웨어의 상당히 깊은 부분까지 손을 대게 되었다. 단순히 기준값을 측정하여 펌웨어에 상수로 하드코딩하는 것이 아니라, 실행 중에 측정한 값을 EEPROM에 저장해 두고 다음 부팅 시 다시 읽어 오도록 만들었다.

CAD로 설계하며 만든 전면 패널은 매우 만족스러웠으나, 키패드 모듈의 측정을 제대로 하지 못해서 도저히 고정을 하는 것이 불가능하였다. 그래서 다음과 같이 패널 고정용 버튼 스위치 5개를 달아서 대신하고자 한다.



이를 쓰려면 아두이노 우노의 아날로그 입력 단자로 신호를 보낼 저항 회로를 별도로 만들어야 한다. ChatGPT는 위 사진의 빨간색 기성품 키패드에서 흔히 쓰이는 방식과는 약간 다른 회로를 제안하였다. 두 회로의 차이를 설명하기 위해 하나의 그림으로 정리해 보았다. 자동 생성한 자료이므로 세부 배선이나 수치는 100% 정확하다고 단정할 수는 없지만, 두 방식의 개념을 비교하는 데에는 도움이 된다.

5버튼 입력을 위한 두 가지 저항 인코딩 회로(수정판-1번 방식의 회로 오류를 바로잡음). 나는 2번 방식, 즉 풀업 저항과 버튼별 저항을 조합하는 방식을 쓰려고 한다.

위에서 소개한 것 중 두 번째 것은 2026년 6월 14일 실제로 만들어서 잘 작동함을 확인하였다.



2026년 6월 5일 금요일

Fluid Ardule, 케이스 가조립을 시작하다

라즈베리 파이와 TFT-LCD를 연결하는 리본 케이블(20cm)이 너무 길다. 10cm짜리로 구입했어도 될 것을. 양 말단 커넥터를 female-female로 구입한 것도 실수였다. 

훌륭하게 가공을 거친 Fluid Ardule의 전후 패널(두께 3mm, 무광 마감)이 도착하였다. 도면에 매우 충실하게 만들어졌지만, 보다 신중하게 설계하여 가공 의뢰를 하지 못한 것에 대한 후회가 밀물과 같이 밀려오기 시작하였다.

  • 5-button keypad 모듈은 무척 애를 써서 구멍 간격 측정을 한 뒤 도면을 그렸음에도 불구하고 잘 맞지 않았다. 어긋난 구멍은 드릴로 넓힐 수 있지만, 패널 뒤에 모듈을 고정하게 되니 거리가 너무 멀어져서 기존의 tactile switch의 버튼 캡을 쓸 수 없었다. 그래서 갖고 있던 패널 고정형 누름버튼 스위치(다섯 개!)를 쓰기로 하였다. 신뢰성은 높지만 누를 때 '딸깍'하는 느낌이 없고 저항 사다리를 이용한 회로를 꾸며야 한다.
  • 볼륨 포텐셔미터와 인코더의 간격을 너무 좁게 만들어서 노브 선택의 폭이 좁아졌다. 인코더는 D-shaft 노브를 쓰는데, 이것을 생각하지 않고 저품질 spline knob만 잔뜩 구입해 놓았다. 축간 간격이 22mm이므로 이보다 직경이 작은 노브를 다시 골라야 한다.
  • DXF 파일의 dimension layer에 참고용 텍스트를 달아 두었는데 너무나 충실하게 가공에 반영되었다. 실제로 새겨 넣지는 말아 달라고 부탁을 했어야 하는데... 그나마 후면판의 경우 내부에 새겨져 있어서 보이지 않는다. 실제로 글자가 필요했다면 올바른 면에 새겨달라고 했었을 것이다.
  • 뒷면의 퓨즈-파워소켓-전원 스위치의 배치가 마음에 들지 않는다. 파워 스위치를 모서리에 가깝게 배치한 것은 작동의 편의성을 위한 것이나, 파워소켓으로부터 퓨즈를 거쳐서 배선이 가로질러야 하니 보기에는 별로 좋지 않다.

고정 전의 부품을 케이스 안에 담아 보았다. 생각보다 공간이 좁다. 바닥 면적이 A4 용지보다는 넓어서는 안 된다는 생각으로 설계를 했기 때문이다. 덕분에 적당히 아담하고 전체적인 중량도 적게 나가겠지만, 조립이 까다로울 것 같다.

라즈베리 파이와 아두이노 우노를 고정할 방법도 생각해 봐야 한다. 바닥이 나무판이라고 하여 단순하게 나사못을 박아서 고정할 수 있는 것도 아니기 때문이다. 온갖 시나리오를 머리에 떠올리면서 고민에 고민을 거듭하고 있다.

오늘은 별로 고민하지 않고 마무리할 수 있는 전원부 재구성부터 손을 대야 되겠다.

2026년 6월 6일 업데이트



주말 작업은 주요 부품을 고정한 뒤 소리를 들어보는 것으로 마무리하였다.

2026년 6월 4일 목요일

Fluid Ardule, 콤비(Combi) 기능을 구현하다

음악 신시사이저에서 '콤비(Combi)'란 여러 음색을 조합하여 하나의 연주 환경을 만드는 기능을 말한다. 가장 흔한 예는 피아노와 현악기 앙상블을 동시에 울리는 경우이다. 이를 위해 내장 음원의 서로 다른 MIDI 채널에 각 음색을 배치하고, 키보드에서 들어오는 연주 정보를 여러 채널로 복제하여 전달한다. 이렇게 여러 음색을 겹쳐 연주하는 방식을 레이어(layer)라고 한다.



콤비에는 스플릿(split)도 포함된다. 예를 들어 건반의 왼쪽 영역은 베이스, 오른쪽 영역은 피아노를 연주하도록 설정하면 마치 한 사람이 두 악기를 동시에 연주하는 것 같은 효과를 얻을 수 있다. 이 경우 들어오는 노트 정보를 음높이에 따라 구분하여 각 파트로 전달한다. 따라서 레이어가 동일한 연주 정보를 여러 파트에 복제하는 방식이라면, 스플릿은 연주 정보를 건반 영역에 따라 분배하는 방식이라고 할 수 있다.

Fluid Ardule 개발의 마지막 단계는 바로 콤비 음색 활용까지를 구현하는 것이다. '전원을 켠 뒤 건반을 연결하여 연주하면 소리가 난다'는 겉보기에 단순한 목표를 달성하는 것은 결코 쉽지 않았다. 이 때에는 콤비까지는 크게 생각하지 않았었다. 버튼과 인코더를 이용하여 매끄럽게 돌아가면서도 직관적이면서 안정적인 UI를 만드는 과정은 참으로 힘겨웠다. 게다가 순수히 재미 삼아 시도한 음원 파일(MP3, OGG, WMA...) 재생 기능 및 인터넷 라디오 기능이 이렇게까지 자잘한 재미를 더해 줄지 누가 알았겠는가?

엄밀히 말하자면 소프트웨어적으로 원하는 기능을 구현하는 것보다 모든 부품을 견고한 케이스에 넣어서 '음악 감상 및 공연장에서도 라이브용으로 쓸 만하게' 만드는 것이 더 중요할 수도 있다. 나무틀은 제작 완료되었고, CAD로 설계한 전후판은 가공을 마치고 오늘 집으로 배송될 것이다. 이를 기다리는 동안 콤비 기능을 몇 시간에 걸쳐 구현한 셈이다.

가장 먼저 한 일은 콤비 음색을 JSON 파일로 정의한 것이다. 현대적 신시사이저에서는 직접 프리셋을 한 레이어씩 쌓아서 콤비를 만드는 일은 흔하지 않다. 이미 마련된 콤비를 불러서 쓰다가 적절히 편집한 뒤 유저 영역에 저장하는 것이 일반적이다. 이번에 정의한 JSON 파일 역시 ChatGPT의 도움을 받아 초안을 만들었다. 우선은 단일 사운드폰트 파일(FluidR_GM.sf2)를 이용하는 것으로 단순한 체계로 구축하였다.

전체 파이썬 스크립트가 이제 1만 라인에 육박하고 있다. 콤비 기능은 별도의 스크립트 파일로 분리해야 하는지 약간 고민을 하였었는데, 지금까지 큰 문제 없이 기능 구현이 된 것을 생각하면 아직 그럴 필요는 없다고 생각한다. 콤비의 편집 및 저장까지 마치면 더 이상 바랄 것이 없는 수준이 되는 것이다. 

Fluid Ardule을 케이스에 넣는 과정에서 예상하지 못한 문제가 또 발생할 것이다. 미국 출장을 앞두고 있어서 금주 안에 마무리 작업을 하는 것은 너무 성급하다. 7월이 오기 전에 외관과 소리 모두 완성된 모습을 만들도록 하겠다.

2026년 5월 29일 금요일

Fluid Ardule, LCD의 외계어 표시를 없애다 - 10uF 전해 커패시터의 힘

Fluid Ardule의 UI 컨트롤러에 해당하는 아두이노 우노에는 I2C LCD 모듈이 연결되어 있다. 이것이 이따금 '외계어'를 표시하는 문제가 있었다. 가끔 일어나는 노이즈 문제라고 생각하기에는 그 빈도가 너무 잦았다. USB 커넥터를 뽑았다가 다시 연결해도 완벽하게 해결되지 않았다. 만약 내가 만드는 물건이 '상품'을 목표로 한다면, 도저히 시장에 내놓기 부끄러운 상태였다.


이 모습은 영화 <프레데터>에 나오는 Yautja 알파벳을 닮았다. 작년에 개봉한 <프레데터: 죽음의 땅> 관련 기사(LA Times 링크)에서는 이 문자와 언어 체계에 대한 상세한 정보가 담겨 있다. 



문제는 이것이 단순한 미관상의 문제가 아니라는 점이다. LCD는 Fluid Ardule의 보조 진단 장치 역할을 한다. 전원을 넣은 직후 상태를 알려주고, Raspberry Pi와 연결되었는지 여부도 표시한다. 따라서 화면이 깨진다는 것은 사용자가 장비를 신뢰하기 어렵다는 뜻이다. 설령 실제 기능은 정상이라 하더라도 말이다.

처음에는 I2C 통신 자체를 의심했다. 하지만 곧 이상한 사실을 발견했다. 외계어 현상은 Raspberry Pi와의 통신이 시작되기 전에도 발생한 적이 있었다. 그렇다면 원인이 Serial 통신에만 있는 것은 아니었다.

ChatGPT와 더불어 온갖 가설 수립과 실험을 해 보면서 생각이 조금씩 바뀌었다. 

문제는 LCD가 아니라 초기화 순서일 수 있었다.

UNO, PCF8574 I2C backpack, HD44780 LCD 컨트롤러는 전원이 들어온 뒤 각각 안정화되는 시간이 조금씩 다르다. 만약 Arduino가 너무 빨리 실행되어 lcd.init()를 호출한다면 LCD 쪽이 아직 완전히 준비되지 않았을 가능성이 있다.

전원을 넣으면 아두이노 우노가 켜지면서('cold start') LCD 모듈(컨트롤러 포함)에도 전원이 인가되어 자연스럽게 화면이 나온다. 이 때에도 외계어가 발생한 사례가 있었지만 매우 드물었다.

그러나 라즈베리 파이가 완전히 부팅되고 Fluid Ardule 서비스가 시작되면서 아두이노 우노와 USB를 통한 시리얼 통신을 수립하는 과정에서 우노는 다시 재시작될 수 있다. Arduino Uno의 기본 자동 리셋(auto-reset) 기능 때문이다.

이 경우 LCD는 계속 전원이 공급되고 있는데 우노만 다시 시작되는 상황이 발생한다. ChatGPT는 이러한 비대칭적인 재시작 과정이 LCD 상태 불안정의 한 원인일 가능성을 제기하였다. 다만 이것이 유일한 원인인지는 아직 단정할 수 없다.

그래서 RESET-GND 사이에 10µF 전해 콘덴서를 추가하는 실험을 했다.

이 콘덴서는 전원 안정화용이 아니다. RESET 핀의 상승 시간을 약간 늦추어 Arduino가 조금 더 늦게 시작하도록 만든다. 즉 LCD와 PCF8574가 충분히 준비된 뒤 초기화가 이루어질 가능성을 높이는 것이다.

놀랍게도 효과가 있는 것으로 보였다. 외계어 발생 빈도가 눈에 띄게 감소하였다.

그런데 이번에는 예상치 못한 부작용이 나타났다.

Arduino IDE에서 펌웨어를 업로드하려고 하자 갑자기 다음과 같은 오류가 발생했다.

not in sync: resp=0x55

한참 원인을 찾다가 문득 깨달았다. 10µF 콘덴서가 Arduino의 자동 리셋 기능까지 방해하고 있었던 것이다. 실제로 콘덴서를 제거하면 업로드가 정상적으로 이루어졌고, 다시 연결하면 동일한 문제가 재현되었다. 이는 콘덴서가 RESET 타이밍에 실제 영향을 주고 있음을 보여주는 간접적인 증거이기도 했다.

결국 콘덴서는 납땜된 상태로 두지 않고, 필요할 때 꽂았다 뺄 수 있는 탈착식 구조로 변경했다. 다음과 같은 프로토타입 실드(Keys 5.1 Proto Shield, 패턴 설명)를 쓰고 있기 때문에 소켓 헤더(아래 사진에서 보이는 맨 아래 가운데 부품)의 Rst와 GND에 전해 콘덴서를 필요한 때에 꽂는 것으로 충분하였다. 어제는 리셋 버튼 스위치 근처에 납땜을 하여 테스트를 했기 때문에 펌웨어 업로드 시에 뺄 수가 없었다.


소켓 헤더에 10uF 전해 콘덴서를 꽂은 사진. 6월 3일 현재 프로토타입 실드는 제거해 버렸다. 전원을 연결할 수 있는 작은 확장 보드를 만들어 대신하였기 때문이다. 단순한 것이 좋다.



그 과정에서 또 하나의 개선점을 발견했다.

현재 UNO-1 펌웨어는 전원 투입 시 LCD를 초기화하지만, Raspberry Pi와 처음 연결되는 순간에는 LCD를 다시 초기화하지 않는다. 그래서 최초 HELLO 메시지를 수신할 때 LCD를 한 번 더 재초기화하는 코드를 추가했다. 일종의 복구 계층을 만든 셈이다(Commit 0380f4a).

하지만 이번 실험에서 중요한 사실이 확인되었다. 펌웨어에서 HELLO 수신 시 LCD를 재초기화하더라도, RESET-GND 사이의 10µF 콘덴서를 제거하면 전원 투입 직후 LCD에 다시 외계어가 나타났다. 즉 소프트웨어 재초기화만으로는 이 문제를 완전히 막을 수 없었다.

정리하면 현재 구조는 다음과 같다.

  • RESET-GND 10µF 콘덴서 → 예방 계층
  • HELLO 수신 시 LCD 재초기화 → 복구 계층

하나는 문제가 발생하지 않도록 돕고, 다른 하나는 혹시 문제가 생겨도 다시 정렬해 준다.

10µF 콘덴서는 UNO-1의 리셋 해제 시점을 늦추어 LCD와 I2C 주변 회로가 안정된 뒤 초기화가 이루어지도록 돕는다. 반면 HELLO 수신 시 LCD 재초기화는 Raspberry Pi와의 연결이 수립된 뒤 화면 상태를 다시 정렬하는 보조적인 안전장치에 가깝다.

수정 후에는 서비스 재시작을 25회 이상 반복했지만 외계어 현상은 관찰되지 않았다. 물론 원래도 매우 낮은 빈도로 나타나던 문제였기 때문에 완전 해결을 선언하기는 이르다. 그러나 적어도 지금까지의 결과는 상당히 고무적이다.

돌이켜보면 이번 사건은 단순히 LCD 글자가 깨지는 문제를 해결한 것이 아니었다. 오히려 시스템의 초기화 시퀀스를 이해하게 된 과정에 가까웠다. 전원 투입, RESET 해제, LCD 초기화, Raspberry Pi와의 링크 수립이 서로 어떤 관계를 갖는지 다시 생각하게 만들었다.

가끔은 가장 작은 부품 하나가 가장 큰 교훈을 준다.


질문에 독이 있다

모르는 것을 상대에게 묻는 것을 질문이라 한다. 자신이 모르는 정보를 알아내고 싶거나, 이해와 설명을 구하기 위함이다. 따라서 질문이란 나의 무지를 전제로 하며, 질문하는 태도에는 겸손함이 따라야 한다. 그러나 많은 경우에 질문자는 답변을 통해서 상대를 평가하려는 숨은 의도가 있다. 그리고 그러한 의도를 굳이 숨기려고 하지도 않는다. 좋은 점이 드러나면 다행이지만, 망신을 당하기도 한다. 선거를 앞두고 벌어지는 토론회가 그러한 사례가 될 것이다. 토론회는 원래 그런 목적으로 열리는 것이니까.

이러한 의도를 품은 질문은 미처 방어할 준비를 하지 못한 상대를 당혹스럽게 만든다. 질타하거나 비난거리를 찾기 위한 질문이 바로 그러한 질문이다. 질문자가 '갑'의 위치에 있을 때, 그리고 그 대화가 이루어지는 자리에 다른 사람들이 많이 모여 있을 때 그러한 질문은 더욱 위력을 발휘한다. 자신의 영향력이나 지위를 과시하기 위해 던지는 질문도 흔하다.

"내가 몰라서 묻는 줄 아세요?"

이렇게 질문을 하고 의기양양하게 좌우를 둘러보는 사람도 있었다.

이 말과 제스쳐는 사실 질문의 목적을 스스로 폭로하는 것이다. 자신이 알고 있는 것을 이미 정답으로 정해 놓았음을 선언하는 것이며, 정보를 얻기 위함이 아니라 상대를 시험하고 압박하고 있음을 보여주는 행위이다.

질문이 압박의 도구가 되면 심문으로 바뀐다. 그러면 올바른 답변이 나오지 않는다. 흔히 'garbage in, garbage out'이라 한다. 질문도 이에 비유할 수 있다. 올바르지 않은 질문에는 좋은 답변이 나오지 않는 법이다. 잘못된 전제를 깔고 있는 질문, 어떤 답변을 하든 상대를 불리하게 만드는 질문, 원하는 곳으로 결론을 끌고 가기 위한 질문...

그래서 나는 독이 든 질문에 답하고 싶지 않다. 그걸 잘 알면서도... 오늘도 당했다.

2026년 5월 27일 수요일

Fluid Ardule, Wi-Fi 설정 기능까지 밀어넣다

인터넷 라디오 기능까지 넣고 나니, 이 기기를 다른 장소에 가져갔을 때 휴대폰 핫스팟에 연결하여 음악을 듣고 싶어졌다. 하지만 키보드나 터치 입력이 원활하지 않은 환경에서 Wi-Fi 암호를 직접 입력하는 UI를 만드는 것은 꽤 번거로운 일이다. 그래서 이미 알고 있는 네트워크 정보를 별도의 설정 파일(/etc/wpa_supplicant/wpa_supplicant-wlan0.conf)에 저장해 두고, 현재 검출되는 SSID 중에서 하나를 선택하는 단순한 방식을 구현해 보았다.

Wi-Fi 선택 화면. '설정'이라고까지는 이야기하지 못하겠다. 암호를 입력하지는 못하므로. 상판으로 사용할 아크릴판도 오늘 도착하였다. 가공을 의뢰한 전후판만 배송되면, 수일 내로 완성품을 만들게 될 것이다. 

개발을 이어가면서 네트워킹 가이드 문서도 함께 정리하였다. Raspberry Pi OS의 실제 동작 방식과 systemd 기반 Wi-Fi 설정 구조를 반영하여 내용을 다듬었는데, 일반적인 라즈베리 파이 네트워크 설정 가이드로 보아도 크게 어색하지 않을 정도로 완성도가 높아진 것 같다.

가끔 Raspberry Pi 3 Model B 와 Arduino Uno 의 연결 상태가 끊어져 기기가 통제 불능 상태에 빠지기도 한다. 대부분은 아두이노 우노를 리셋하면 문제가 해결되지만, 그렇지 않은 경우에는 라즈베리 파이에 SSH로 접속하여 서비스를 재시작해야 한다. 또한 CP2102 기반의 시리얼 콘솔(PuTTY 등)을 이용하면 네트워크가 동작하지 않는 상황에서도 시스템 복구가 가능하다. 시리얼 콘솔은 이미 지금도 사용하고 있다. 

사실 사운드 모듈이라는 본래 목적에만 충실하다면 네트워킹 기능은 전혀 필요하지 않다. MIDI 입력과 음원 재생만으로도 독립적인 전자 악기처럼 동작할 수 있기 때문이다. 하지만 인터넷 라디오 기능까지 추가하다 보니, 결국 외부 세계와 연결되는 최소한의 통로는 유지할 수밖에 없다. Wi-Fi는 가장 일상적인 통로이고, 비상 사태에 쓰기 위한 통로는 다음의 글을 참고하라.

휴대폰을 비상 콘솔로 쓰기

라즈베리 파이 기반 장비를 헤드리스(headless)로 운영하다 보면, 가끔 SSH 접속조차 불가능한 상황이 발생한다. 특히 Fluid Ardule처럼 TFT-LCD와 아두이노 우노 기반의 전용 UI를 사용하는 시스템에서는 입력 장치 연결이 끊어지면 사실상 조작이 불가능해질 수도 있다.

이럴 때 라즈베리 파이의 UART 시리얼 콘솔은 매우 강력한 비상 복구 수단이 된다. 나는 GPIO UART에 연결된 CP2102 USB-UART 모듈을 항상 장착해 두고 있으며, 평소에는 노트북에서 PuTTY를 이용하여 접속한다. 그런데 같은 작업은 휴대폰만으로도 가능하다고 한다.

준비물

  • Android 스마트폰
  • USB OTG 어댑터
  • CP2102 USB-UART 모듈
  • 시리얼 터미널 앱(예: Serial USB Terminal)

연결 구조

Raspberry Pi UART
        ↓
      CP2102
        ↓ USB
 Android Phone

휴대폰에 OTG 어댑터를 연결한 뒤 CP2102를 꽂고, 시리얼 터미널 앱을 실행한다. 보통 baud rate는 115200bps로 설정하면 된다. 연결이 성공하면 라즈베리 파이의 Linux 콘솔 로그인 프롬프트가 휴대폰 화면에 나타난다.

간단한 복구 명령

sudo systemctl restart fluid_ardule.service
journalctl -u fluid_ardule.service -n 3

이 방식의 장점

가장 큰 장점은 네트워크 상태와 무관하다는 점이다. Wi-Fi가 죽었거나 SSH가 동작하지 않아도, UART 콘솔만 살아 있으면 시스템 복구가 가능하다. 서비스를 재시작하거나 로그를 확인하는 정도의 유지보수는 휴대폰만으로도 충분히 수행할 수 있다.

또한 Bluetooth나 VNC 같은 무거운 기능을 다시 활성화하지 않아도 된다. 최소 기능만 유지한 경량 appliance 스타일의 시스템에서는, 이런 단순한 UART 콘솔 방식이 오히려 가장 안정적이고 확실한 유지보수 수단인지도 모른다.

2026년 5월 26일 화요일

Fluid Ardule, 인터넷 라디오 기능까지 구현하다

 

가공을 의뢰한 전후판과 상판이 수일 내로 도착할 것이다.

잠시 동작이 불안정했던 아두이노 우노 펌웨어를 다시 손보고, 드디어 인터넷 라디오 기능까지 넣어 보았다. 방송국 목록은 json 파일 형태로 직접 제공하는 단순한 방식을 택했다. 기능 자체는 잘 작동하지만, 인터넷 라디오를 원활하게 쓰려면 결국 Wi-Fi 설정 문제가 따라온다.

그렇다고 Wi-Fi 설정까지 장비의 작은 UI 안에 넣으려 하면 일이 지나치게 복잡해진다. 버튼과 인코더만으로 암호를 입력하는 일은 생각보다 번거롭다. 그래서 이 부분은 장비 안에서 억지로 해결하기보다, 필요할 때 터미널에서 설정하는 편이 낫다고 보았다. 아무런 네트워크가 잡히지 않은 상태에서도 라즈베리 파이에 접근할 수 있는 방법, 즉 USB 시리얼 콘솔이 남아 있다는 점은 이럴 때 큰 장점이 된다.

위에서 소개한 사진에서는 Fluid Ardule이 SomaFM의 방송국 중 하나를 재생하고 있다. SomaFM은 미국 샌프란시스코 기반의 독립 인터넷 라디오 서비스이다. 2000년부터 운영되어 왔으며, 광고 없이(listener-supported) 운영되는 채널이 많다는 점이 특징이다. 

이 서비스는 단순히 음악을 자동 재생하는 스트리밍 사이트라기보다, 각 채널마다 뚜렷한 분위기와 선곡 철학을 가진 ‘큐레이션 라디오’에 가깝다. 특히 앰비언트, 다운템포, 드론, 전자음악, 라운지, 재즈 계열 채널이 강하며, 오랫동안 DIY 오디오 애호가와 개발자들 사이에서도 잘 알려져 있다. 

Fluid Ardule에는 우선 몇 개의 대표 채널만 시험적으로 넣어 보았다. 예를 들어 Groove Salad는 다운템포와 칠아웃 계열 음악 중심이며, Drone Zone은 느린 드론·앰비언트 음악 위주의 채널이다. Deep Space One은 우주적인 분위기의 실험적 앰비언트 전자음악을 제공한다. 

이들 방송은 공개 스트림 URL 형태로 제공되므로 별도의 웹브라우저나 계정 없이도 mpv 같은 플레이어에서 직접 재생할 수 있다. Raspberry Pi 기반의 소형 오디오 장비와 잘 어울리는 이유도 여기에 있다. 

오늘의 Fluid Ardule 파이썬 스크립트(260526b)는 7687라인이다. '미디어 스테이션'으로 복잡하게 진화하려는 욕망을 억제하는 것도 어렵다. '불편하고 작은 PC'를 만드는 것이 나의 최종 목표는 아니기 때문이다.

2026년 5월 24일 일요일

새벽의 성공, 이어지는 hotfix

원래의 제목은 '어제의 성공, 오늘의 hotfix'로 하려고 했었다. 그러나 실제로는 어제 밤늦게 작업을 한 뒤 자정을 넘겨 '성공'에 대한 포스팅을 했기 때문에 지금  hotfix에 관한 글을 쓰는 시점과 날짜는 같다. 그래서 '새벽의 성공, 이어지는 hotfix'라고 제목을 지었다. Hotfix란 급하게 수정해야 하는 버그 잡기 정도라고 정의하면 된다. 중요한 기능을 구현했다고 김칫국부터 마시면서 릴리즈했다가 치명적인 문제가 포함되었음을 깨닫고 다시 급하게 수정본을 배포하는 행위에 해당한다.

어제 Fluid Ardule의 UNO-1 입력 컨트롤러에 자동 캘리브레이션 기능을 넣고 꽤 뿌듯해하고 있었다(관련 글 링크). 저항 사다리(resistor ladder) 방식의 5-버튼 키패드는 단 하나의 아날로그 입력만 사용하기 때문에 구조가 단순하고 배선도 간결하다. 비용도 적게 든다. DIY 프로젝트에서는 꽤 매력적인 방식이다.

이번에 구현한 기능은 각 버튼의 ADC 중심값을 자동으로 측정해 EEPROM에 저장하는 방식이었다. 사용자가 LEFT, UP, DOWN, RIGHT, SELECT 버튼을 차례대로 누르면 시스템이 직접 기준값을 계산해 주는 구조다. 저항 편차나 전원 상태 변화에도 좀 더 유연하게 대응할 수 있을 것 같았다. 실제로 처음 테스트했을 때는 제법 그럴듯하게 동작했다. 이제는 펌웨어 자체를 수정하여 컴파일 후 업로드하지 않아도 작동 중에 보정치를 구해서 직접 적용할 수 있으니 정말 영리하게 목표를 달성했다고 자부하고 있었다.

하지만 늘 그렇듯, 진짜 문제는 “잘 되는 것처럼 보인 뒤”에 나타난다.

테스트를 반복하던 중 이상한 현상이 보였다. 캘리브레이션 모드에 진입한 직후 아직 LEFT 버튼을 누르지도 않았는데 시스템이 이미 LEFT 입력을 받은 것처럼 다음 단계로 넘어가 버리는 경우가 생긴 것이다. 처음에는 threshold 계산 문제인가 싶었다. 그런데 원인을 추적해 보니 더 흥미로운 곳에 문제가 숨어 있었다.

문제는 캘리브레이션 진입 자체에 사용했던 롱프레스 입력이었다.

사실 인코더 롱프레스는 원래 인코더 회전 가속(acceleration) 단계를 변경하는 기능에 이미 할당되어 있었다. 따라서 캘리브레이션 진입을 같은 롱프레스 동작에 연결하자 메뉴 의미가 충돌하기 시작했다. 결국 캘리브레이션은 인코더와 SELECT 버튼을 동시에 길게 누르는 조합 입력으로 변경하였다. 일반적인 조작과 유지보수 기능을 분리하기 위한 선택이었다.

그런데 시스템은 아직 그 입력 상태의 “잔향” 속에 있었는데도 이미 다음 단계로 넘어가 LEFT 입력을 기다리고 있었다. resistor ladder 방식에서는 버튼을 떼는 순간 ADC 값이 잠깐 불안정한 영역을 지나간다. 그 transient 값이 우연히 LEFT 버튼 영역을 스치면서 실제로는 누르지도 않은 LEFT가 눌린 것처럼 보인 셈이다.

결국 이번 hotfix에서는 캘리브레이션 state machine 자체를 손보게 되었다.

캘리브레이션 진입 직후에는 먼저 모든 버튼이 완전히 해제된 안정 상태를 확인하도록 바꾸었고, 단순히 “현재 눌려 있는 상태”가 아니라 NONE 상태 이후 새롭게 발생한 press edge만 유효 입력으로 인정하도록 수정하였다. 각 단계 사이마다 반드시 버튼 release를 확인하는 과정도 추가했다.

사실 이런 문제를 겪다 보면 임베디드 시스템에서 가장 어려운 것은 화려한 기능이 아니라 상태 전이(state transition)라는 생각이 든다. 특히 아날로그 입력, 롱프레스, 노이즈, 실시간 이벤트가 한꺼번에 얽히기 시작하면 예상하지 못한 모서리(edge case)가 끝없이 나타난다.

그래도 이런 시행착오가 재미있다. “왜 이런 일이 생겼지?”를 추적하다 보면 회로와 펌웨어가 실제 세계와 어떻게 부딪히는지가 조금씩 보이기 때문이다.

한편으로는 현재의 resistor ladder 구조를 계속 유지할지에 대한 고민도 다시 하게 된다. 장기적으로는 PCF8574 같은 I2C 기반 GPIO 확장 칩도 검토해 보고 싶다. 버튼마다 독립적인 디지털 입력을 사용하면 threshold drifting 같은 문제에서는 훨씬 자유로워질 수 있기 때문이다. 물론 배선은 조금 복잡해지겠지만 말이다.

자작나무 합판이 도착하여 드디어 케이스 만들기에 착수하였다. 목공용 플램프가 없어서 이번에도 접합 후에 단차가 약간 발생하였다. 충분히 주의하면서 위치를 잡은 후 무거운 것으로 눌러 두었음에도 불구하고... 만약 PCF8574 확장 칩을 쓴다면 사진 가운데에서 보이고 있는 패널용 누름 버튼 스위치 5개를 이용하여 약간은 수고스럽게 배선 작업을 해야 한다. 


어쩌면 이번 경험은 단순한 버그 수정이라기보다, “입력 장치를 만든다”는 것이 생각보다 훨씬 깊은 세계라는 사실을 다시 배우는 과정인지도 모르겠다.


2026년 5월 26일 업데이트

자작나무 합판으로 만든 틀에 다이소 바니시를 발라서 잘 말렸다. 전후판(알루미늄 3T)도 가공을 맡겼다. 재단한 합판을 접착해 놓고 보니 단차가 발생하여 매우 아쉽고, 겉으로 살짝 흘러나온 목공본드를 바니시 도포 전에 깨끗하게 닦아내지 못한 것은 더더욱 아쉽다.



지금은 약간 사족과 같은 '인터넷 라디오' 재생 기능을 추가해 보고 있다. 그 과정에서 UNO-1 버튼 입력 검출의 문제가 다시 드러나서 이를 수정하기 위해 적잖이 골머리를 앓고 있다. 엊그제 구현한 self-calibration 기능도 아직 완벽하지 못하다. 이를 자세히 알아보자.

현재 입력 처리 로직에서는 롱프레스가 발생한 뒤 사용자가 버튼을 실제로 떼기 전에, 여전히 눌린 상태의 입력이 새로운 버튼 이벤트로 다시 해석되는 문제가 발생할 수 있다. 특히 아날로그 저항 사다리 방식의 5-key 입력에서는 ADC 값이 잠시 유지되거나 흔들리기 때문에, 롱프레스 처리 직후 동일 버튼이 다시 short press나 다른 명령으로 인식되어 메뉴 이동, 중복 실행, 의도하지 않은 동작이 연속적으로 발생한다. 따라서 롱프레스 이벤트가 발생한 이후에는 버튼이 완전히 릴리즈되고 입력값이 안정된 것이 확인될 때까지 추가 입력을 무시하는 “wait-for-release” 상태 처리가 반드시 필요하다.

모든 불만을 저항 사다리 방식의 5-버튼 키패드 모듈 안정성 탓으로 돌리고 싶지만, 이러한 판단이 정말 공정한지는 아직도 잘 모르겠다. 하드웨어의 편차, 펌웨어의 판정 로직, 릴리즈 감지 기준, 그리고 라즈베리 파이와의 통신 구조가 서로 복잡하게 얽혀 있기 때문이다.

취미 수준으로 만족할 것이 아니라 제품 수준의 완성도를 목표로 하려면 얼마나 많은 고민과 시행착오를 거쳐야 하는지 조금은 알 것 같다.

나머지 안정성 개선은 각자의 하드웨어 환경과 시행착오 속에서 계속 다듬어질 수밖에 없을 것이다. 어쩌면 그것이 DIY 프로젝트의 한계이자, 동시에 매력인지도 모른다. 그렇다 하더라도 최초의 '기발자'(기획자 + 개발자)로서, 적어도 내가 겪은 문제와 해결 과정만큼은 끝까지 책임지고 다듬어 나가고 싶다.