Fluid Ardule은 사운드폰트 기반 DIY 신시사이저 모듈로서 충분한 목표 기능에 도달하였다. UNO-2(아두이노 기반 MIDI 입력 처리기)는 Fluid Ardule의 필수 구성품은 아니지만 DIN MIDI IN/OUT을 갖춘 장비를 연결하기 위한 기구 용도로 사용해 왔었다.
UNO-2에 달린 MIDI OUT을 이용하여 내부에서 생성된 MIDI 연주 신호를 외부 모듈로 보내보려고 노력해 보았으나 결과는 그렇게 만족스럽지 않았다. 그래서 USB MIDI 케이블을 사용해 보기로 했다. 라즈베리 파이에 연결한 키보드의 연주 신호를 그대로 복제하여 USB MIDI 케이블로 내보내는 것은 그다지 어렵지 않았다. 이를 'Mirror' 기능이라 부르기로 하였다.
다음으로는 이렇게 연결한 외부 모듈이 File Player를 통해 작동하게 만들었다. MIDI file 재생 중 stop/pause를 실시하면 stuck note가 발생한다. 소프트웨어 신스를 쓸 때에는 자동적으로 재시작을 하게 만들었지만, 외부 모듈에까지 미치지는 못한다. 이 문제를 해결하기 위하여 약간의 작업을 실시하였다.
여기까지 진행을 하면 다음 단계는 너무나 자연스럽게 Program Change가 되도록 만드는 것 아니겠는가? 구현은 그다지 어렵지 않았다.
![]() |
| 드디어 Fluid Ardule을 통해 외부 GM sound module의 제어가 되기 시작하였다. |
하나를 해결하면 또 다음 숙제가 자연스럽게 떠오른다. USB MIDI cable 말고도 나는 롤랜드 사운드캔버스 SC-D70을 갖고 있지 않은가? 라즈베리 파이와 이것을 USB 케이블로 연결하면 외부 DAC와 MIDI interface 및 음원으로서 활용 가능하다. 이토록 훌륭한 기능을 가능성으로만 남겨 둘 이유가 없다.
그래서 열심히 일요일 개발을 이어갔는데... 드디어 6천 라인을 넘겼다. 리팩토링을 시작할 시점이 되었다는 신호를 주고 있는 셈이다. 원하는 기능은 어렵지 않게 구현하였다. 복잡한 메뉴 속에서 길을 잃을 상황은 아니다. 거미줄처럼 뒤엉킨 케이블을 내가 어떤 의도로 연결했는지 잊지 않는 것이 중요하다.
이 장치의 복잡성은 라즈베리 파이에 연결된 USB 기기가 결정한다. 키보드 컨트롤러라면 그것으로 끝이다. 하지만 UNO-2라든가, 사운드캔버스 SC-D70의 경우라면 이야기가 달라진다(사실 SC-D70을 DAC가 아닌 USB 기기로 동작시키는 것은 오늘 구현하였음). SC-D70은 MIDI 신호를 받아서 내부 음원을 울릴 수 있지만. 자체 DIN MIDI IN/OUT을 통해 확장이 가능하기 때문이다. 따라서 오늘 개발의 마지막 단계에서는 '(라즈베리 파이에) 꽂아야 UI에 비로소 보인다'는 원칙을 지키고자 하였다.
새 버전의 파이썬 스크립트(launch_fluidardule.py, 저장소)가 만들어졌을 때 테스트할 기능도 점점 많아져서 이제는 점검용 시나리오를 써야 할 수준이 되었다. 그에 따라서 UI 자체가 심각하게 복잡해지지는 않았으니 다행이라고나 할까.
![]() |
| 취미의 시작은 '(장비)탑 쌓기'로부터 시작한다. 그러나 이건 너무나 소박한 탑이다. |
원래 systemctl로 시작해야 할 파이썬 스크립트를 테스트하기 위해 터미널에서 직접 실행 및 중단('Ctrl + C')을 반하다보면 UNO-1(아두이노 기반 UI 입력 컨트롤러, 버튼/인코더/포텐셔미터를 처리)과의 시리얼 통신이 깨지고는 한다. 왜 그러한지 ChatGPT에게 상세한 설명을 부탁하였다.
수동 실행 시 UNO-1 시리얼 연결이 불안정해지는 이유
launch_fluidardule.py를 systemctl로 실행할 때에는 UNO-1과의 통신이 대체로 안정적이다. 그러나 터미널에서 직접 실행하고 Ctrl+C로 종료한 뒤 다시 실행하면, 가끔 UNO-1이 기대한 것처럼 리셋되지 않거나 연결이 불안정해지는 경우가 있다.
1. 기본 구조
UNO-1은 Raspberry Pi와 USB-serial 방식으로 통신한다.
UNO-1 → USB serial → Raspberry Pi의 Python 스크립트
Python 스크립트는 지정된 시리얼 포트를 열어 UNO-1과 데이터를 주고받는다.
2. DTR의 역할
Arduino UNO는 시리얼 포트가 열릴 때 DTR(Data Terminal Ready) 신호 변화에 의해 리셋되는 구조를 갖고 있다. 이는 Arduino IDE에서 스케치를 업로드할 때 보드를 자동으로 리셋하기 위한 일반적인 동작이다.
serial.open()
→ DTR 신호 변화
→ UNO 리셋
따라서 Fluid Ardule 스크립트가 UNO-1의 시리얼 포트를 열면, 보통 UNO-1은 자동으로 리셋되고 초기 상태에서 통신을 시작한다.
3. 터미널 수동 실행에서 생길 수 있는 문제
터미널에서 스크립트를 직접 실행하고 Ctrl+C로 종료하는 과정을 반복하면 다음과 같은 상황이 생길 수 있다.
- 이전 Python 프로세스가 아직 시리얼 포트를 점유하고 있음
Ctrl+C종료 시 시리얼 포트가 완전히 정리되지 않음- DTR 상태가 이미 바뀐 상태로 남아 있어 다시 열어도 리셋 펄스가 발생하지 않음
systemd서비스와 수동 실행 프로세스가 같은 포트를 동시에 사용하려 함- UNO-1 리셋 직후의 초기 메시지와 새 실행의 통신이 섞임
이 경우 UNO-1이 리셋되지 않거나, Python 스크립트가 초기 handshake를 안정적으로 받지 못할 수 있다.
4. systemctl 실행과의 차이
systemctl로 실행할 때에는 보통 부팅 후 한 번만 스크립트가 시작된다.
부팅
→ systemd 서비스 시작
→ Python 스크립트 실행
→ 시리얼 포트 open
→ DTR 변화
→ UNO-1 리셋
→ 정상 통신 시작
반면 터미널 수동 실행에서는 다음과 같은 흐름이 반복된다.
python3 실행
→ Ctrl+C 종료
→ 다시 python3 실행
→ 이전 시리얼 상태가 남아 있을 가능성
따라서 재부팅 후에는 정상인데, 터미널에서 반복 실행할 때만 불안정한 현상이 나타날 수 있다.
5. 수동 테스트 시 권장 절차
터미널에서 직접 테스트할 때에는 먼저 서비스를 중지하고, 남아 있는 프로세스가 없는지 확인하는 것이 좋다.
sudo systemctl stop fluid_ardule.service
pkill -f launch_fluidardule.py
sleep 1
python3 /home/pi/scripts/launch_fluidardule.py
필요하면 시리얼 포트를 점유한 프로세스를 확인할 수 있다.
lsof /dev/serial/by-id/usb-Arduino__www.arduino.cc__Arduino_Uno_12724551266415469650-if00
이 명령에서 아무 프로세스도 나오지 않아야 수동 실행하기 좋은 상태다.
6. DTR을 명시적으로 토글하는 방법
더 확실한 리셋이 필요하다면 Python 코드에서 DTR을 명시적으로 토글할 수 있다.
ser.setDTR(False)
time.sleep(0.1)
ser.setDTR(True)
다만 이 방법은 개발 편의용 보강책에 가깝다. 실사용 환경에서 systemd가 부팅 시 한 번 실행하는 구조라면 반드시 필요한 처리는 아니다.
7. 정리
터미널에서 수동 실행할 때 UNO-1 연결이 가끔 불안정해지는 것은 하드웨어 고장이라기보다 USB-serial 포트와 DTR 신호 상태가 반복 실행 과정에서 깔끔하게 초기화되지 않기 때문일 가능성이 높다.
재부팅하면 정상으로 돌아오고, systemctl 실행에서는 문제가 없다면 구조적인 결함으로 보기보다는 개발 중 수동 실행에서 생기는 일시적인 상태 꼬임으로 보는 것이 적절하다.
ChatGPT의 설명은 여기까지.
오늘의 결론은 간단하다. Fluid Ardule은 이제 내부 SoundFont 음원 모듈을 넘어 외부 GM sound module까지 제어할 수 있는 작은 MIDI 스테이션이 되었다. 그러나 동시에 더 이상 무작정 기능을 얹어서는 안 되는 단계에 도달했다. 앞으로의 과제는 기능 추가가 아니라 정리, 저장, 그리고 리팩토링이다.
그리고... 이런 책을 읽기 시작하였다. 내가 지금의 취미 개발 프로젝트를 하는 것은 샘 올트먼이 세운 '제국' 덕분이다. 이 기술이 취미 생활의 효율을 상상할 수 없는 수준으로 가속하는 것은 인정하지만, 세상의 모든 자원을 빨아먹는 이 기술에 나 자신과 세계관을 맞추어 나가야 하는지는 여전히 의심스럽다.








