아두이노로 만드는 DIY 핀볼 머신: 완벽 가이드
부품 및 소모품
| 부품 |
수량 |
비고 |
| 아두이노 메가 2560 |
1 |
다수 I/O 핀 필요 |
| 아다프루트 2핀 LCD 디스플레이 |
1 |
점수/볼 수 표시용 (시리얼 인터페이스) |
| 24V 파워 서플라이 |
1 |
플리퍼, 팝 범퍼, 슬링샷 구동용 |
| 아다프루트 포스 센서 |
1 |
볼 분실 감지용 (아웃홀 압력 감지) |
| 팝 범퍼 어셈블리 |
1 |
코일, 스위치, 캡 포함 |
| 팝 범퍼 스위치 |
1 |
|
| 타겟 스위치 |
1 |
드롭 타겟 등 |
| 롤오버 스위치 |
1 |
레인/롤오버 레인용 |
| 플리퍼 어셈블리 |
1 |
좌/우 플리퍼, 코일, 스위치, 버튼 포함 |
| LED 램프 |
여러 개 |
플레이필드 조명 및 점수 표시등 |
프로젝트 소개
목공, 기계, 전자, 프로그래밍 기술이 종합된 아두이노 제어 핀볼 머신입니다. 약 6개월의 파트타임 작업으로 완성되었으며, 제가 만든 것 중 가장 복잡한 프로젝트입니다. 핀볼 머신 제작 정보를 찾기 어려워 직접 시행착오를 겪으며 만들었는데, 이 문서가 후배 메이커들에게 도움이 되길 바랍니다. 모든 부품을 프로토타입 보드에서 먼저 테스트하고 본체에 설치하세요. 많은 시간과 좌절을 줄일 수 있습니다.

캐비닛 (본체)
- 재료: 오크 합판 (홈센터 구매), 모든 치수는 인치
- 전면/후면: 20H x 23W, 측면: 20H x 47L
- 모서리 마이터 조인트 + 비스킷 조이너 + 목공본드 (포켓 스크류도 가능)
- 바닥에서 1인치 위에 3/4인치 다도 홈 파서 선반 떠받침 (접착 안 함, 수축/팽창 여유)
- 플레이필드: 22W x 42L, 캐비닛보다 짧음 (앞쪽 3인치 여유: 플리퍼 버튼 배선, 볼 플런저 공간)
- 플레이필드는 양쪽 측면에 나사로 고정한 작은 나무 블록 위에 올려놓음 (약 4인치 아래)
- 뚜껑 열면 플레이필드 들어내어 내부 접근 가능
다리 및 각도 조절
- 핀볼 머신은 1~7도 경사 필요 (각도 클수록 빠름)
- 나무 다리(홈센터 구매) 끝에 12인치 깊이 구멍 뚫고 3/8인치 티너트 에폭시로 고정
- 3/8인치 나사봉 12인치 끼우고 너트 + 레벨링 풋으로 높이 조절
- 다리 마운팅 플레이트를 하단 선반에 나사로 고정
- 나사봉 돌려 높이/각도 조절 후 너트 조여 고정
부품 링크: 레벨링 풋, 티너트
뚜껑 (백글라스)
- 오크 프레임, 외부 치수 캐비닛과 동일
- 상단/양옆 1.5인치, 하단 5인치 폭 (플레이필드와 캐비닛 사이 간격 가림)
- 내측에 다도 홈 파서 플렉시글라스(Plexiglas) 끼움 (유리보다 가볍고 안전, 절단 용이)
- 포켓 스크류로 조립 (플렉시글라스 교체 시 분해 가능)
- 내부에 장식용 컬러 LED 스트립 부착
- 피아노 힌지로 캐비닛에 연결 (매립형)

아두이노 메가 2560 역할
- 스위치 입력 감지 (타겟, 롤오버, 팝 범퍼, 볼 슈트, 아웃홀)
- 해당 램프/LED 점등/소등
- 점수 계산 및 볼 카운트 관리
- LCD에 점수와 볼 번호 표시
대부분 배선은 단순: 스위치 한 쪽은 아두이노 디지털 입력 (INPUT_PULLUP), 다른 쪽은 GND. 입력이 HIGH→LOW로 바뀌면 히트 감지.
팝 범퍼 특수 처리
팝 범퍼는 24V 별도 전원으로 구동되어 스위치 신호도 고전압. 아두이노 직접 연결 불가 → 전압 분할기로 5V 이하로 낮춰 아날로그 입력 핀으로 읽음. 아날로그 임계값(500 이상)으로 노이즈와 신호 구분.
점수 시스템
- 특정 타입(타겟, 팝 범퍼, 롤오버) 모두 히트 시 해당 램프 점멸 후 소등, 해당 아이템 점수 배율 증가
- 타겟: 8개 모두 히트 → 점수 5배
- 롤오버: 3개 모두 히트 → 총점 2배, 롤오버 점수 10배
- 팝 범퍼: 4개 모두 히트 → 팝 범퍼 점수 2배
볼 감지 및 게임 오버
- 포스 센서로 아웃홀에 볼이 떨어지면 압력 감지 → 볼 분실 처리
- 볼 5개 소진 시 게임 오버: 모든 램프 순차 점멸, LCD에 "Game Over!!!" 표시
- 볼 슈트 스위치(하단/상단)로 새 볼 발사 감지 → 볼 카운트 증가
전원 공급
- 24V 파워 서플라이로 플리퍼, 슬링샷, 팝 범퍼 구동
- 팝 범퍼엔 다소 약할 수 있음 → 더 강한 파워 서플라이 고려 (전압 분할기 재설계 필요)
- 버스 바(전원 분배 막대)를 플레이필드 하단에 장착해 배선 정리
볼 슈터 (플런저)
구매 링크: Marco Specialties
- 캐비닛 전면에 구멍 뚫고 내부에서 나사로 고정
- 정렬 중요: 플레이필드에 직선 자 대고 플런저 중심이 핀볼 중심(1 1/16인치 구슬의 절반 높이)과 일치하도록
플레이필드
- 1/4인치 자작나무 합판
- NASA 허블 이미지 포스터를 스프레이 접착제로 라미네이트 후 트리밍
- 이미지 출처: HubbleSite
플리퍼
구매: Pinball Life
배선도는 아래 그림 참조 (플리퍼 코일, EOS 스위치, 버튼, 다이오드, 24V 연결).

슬링샷
완성 어셈블리 구매 가능. 핀, 고무줄 별도 구매. 16게이지 와이어(24V측), 22게이지(아두이노측) 사용.
플리퍼 옆에 금속 레일 필요 → 크롬 강선(잔디 경계용)으로 직접 제작, 에폭시로 고정.

팝 범퍼
어셈블리, 스위치, 캡 별도 구매. 3개 구멍 뚫기 (지지봉 2개, 스위치 축 1개). 볼이 백색 디스크 누르면 축 내려가 리프 스위치 작동 → 솔레노이드 작동 → 금속 링 당겨져 볼 튕겨 나감.

타겟, 롤오버, 램프
배선은 모두 아두이노 섹션에서 설명한 방식과 동일 (INPUT_PULLUP + LED 출력).
소스 코드
const int TxPin = 17; // LCD 시리얼 TX
long Score = 0, OldScore = 0;
long Target = 1, Pop = 1, Roll = 10;
int Targets[8], Rolls[3], Pops[4];
int Milli = 10, Flash = 100;
int Ball = 0, Shot = 0, Lost = 0, Pressure = 1024;
#include
SoftwareSerial mySerial(255, TxPin); // RX=-1(미사용), TX=17
void setup() {
pinMode(TxPin, OUTPUT); digitalWrite(TxPin, HIGH);
mySerial.begin(9600);
mySerial.write(12); // Clear
mySerial.write(17); // Backlight on
// 타겟 입력 핀 2~9 (INPUT_PULLUP)
for (int i = 2; i <= 9; i++) pinMode(i, INPUT_PULLUP);
// 롤오버 입력 핀 10~12
for (int i = 10; i <= 12; i++) pinMode(i, INPUT_PULLUP);
// 볼 슈트 스위치 15, 16
pinMode(15, INPUT_PULLUP); pinMode(16, INPUT_PULLUP);
// LCD TX 핀 17
pinMode(17, OUTPUT);
// 타겟 램프 32~39
for (int i = 32; i <= 39; i++) pinMode(i, OUTPUT);
// 롤오버 램프 40~42
for (int i = 40; i <= 42; i++) pinMode(i, OUTPUT);
// 팝 범퍼 램프 50~53
for (int i = 50; i <= 53; i++) pinMode(i, OUTPUT);
}
void loop() {
// 타겟 8개 체크
for (int i = 0; i < 8; i++) {
if (digitalRead(i+2) == LOW) {
Targets[i] = 1; Score += Target; digitalWrite(i+32, HIGH); delay(Milli); break;
}
}
// 모두 히트 시 점멸 후 소등, Target *= 5
int Sum = 0; for (int i = 0; i < 8; i++) Sum += Targets[i];
if (Sum == 8) { /* 점멸 루틴 */ for (int i = 0; i < 8; i++) { digitalWrite(i+32, LOW); Targets[i] = 0; } Target *= 5; }
// 롤오버 3개 체크 (핀 10~12, 램프 40~42)
for (int i = 0; i < 3; i++) {
if (digitalRead(i+10) == LOW) {
Rolls[i] = 1; Score += Roll; digitalWrite(i+40, HIGH); delay(Milli); break;
}
}
Sum = 0; for (int i = 0; i < 3; i++) Sum += Rolls[i];
if (Sum == 3) { /* 점멸 */ for (int i = 0; i < 3; i++) { digitalWrite(i+40, LOW); Rolls[i] = 0; } Score *= 2; Roll *= 10; }
// 팝 범퍼 4개 체크 (아날로그 0~3, 램프 50~53)
for (int i = 0; i < 4; i++) {
if (analogRead(i) > 500) {
Pops[i] = 1; Score += Pop; digitalWrite(i+50, HIGH); delay(Milli); break;
}
}
Sum = 0; for (int i = 0; i < 4; i++) Sum += Pops[i];
if (Sum == 4) { /* 점멸 */ for (int i = 0; i < 4; i++) { digitalWrite(i+50, LOW); Pops[i] = 0; } Pop *= 2; }
// 볼 슈트 감지 (핀 15, 16) → 볼 카운트 증가, 5볼 후 게임 오버 리셋
// 아웃홀 포스 센서 (아날로그 7) → 압력 임계값 초과 시 볼 분실 처리
// 게임 오버 시 전체 램프 점멸, LCD "Game Over!!!"
// LCD 업데이트 (점수 변경 시만)
if (Score != OldScore) {
mySerial.write(12); delay(5);
mySerial.print(Score); mySerial.write(13); // Form feed
mySerial.print("Ball = "); mySerial.print(Ball);
OldScore = Score;
}
}
회로도
대표적인 각 부품(타겟, 롤오버, 팝 범퍼, 플리퍼, 램프) 하나씩만 배선 예시로 표시. 모두 그리면 너무 복잡함.

요약
이 가이드로 기본 틀을 잡으셨다면, 이제 여러분만의 벨과 휘슬(추가 기능)을 더해보세요!