아두이노 레오나르도와 3D 프린팅으로 MS 플라이트 시뮬레이터용 커스텀 스로틀 쿼드런트 & 트림 휠 만들기
부품 및 소모품
아두이노 레오나르도 (또는 마이크로)
아두이노 하나당 최대 6개의 컨트롤 연결 가능
1개
후크업 와이어
모듈당 3선 필요
3개
로터리 포텐셔미터 50kΩ
모듈당 1개 (본문 참조)
1개
필요한 도구 및 장비
납땜 인두
3D 프린터 (ABS 필라멘트 권장)
소프트웨어 및 온라인 서비스
아두이노 IDE
프로젝트 소개
최근 PC를 업그레이드하여 MS FS2020을 구동할 수 있게 되면서, 더 나은 비행 조작감을 위해 직접 컨트롤러를 제작하기로 했습니다. 키보드로는 비행의 몰입감을 느끼기 어렵고, 고가의 정식 콕핏 장비를 구매하거나 설치할 공간과 예산이 부족했기 때문입니다. 주로 경비행기를 즐겨 타기 때문에, 스로틀, 플랩, 랜딩 기어용 단일 레버와 엘리베이터 트림 휠을 목표로 설계했습니다.
완성된 스로틀 쿼드런트와 트림 휠
설계
보유한 도구로 제작 가능하면서 실제 항공기 조작감을 재현할 수 있는 형태로 CAD 설계했습니다. 실제 항공기 조종 경험은 없지만, 시뮬레이터 경험과 자료 조사를 바탕으로 직관적인 조작감을 구현하는 데 집중했습니다.
트림 휠은 가장 까다로운 파트였습니다. 여러 날에 걸쳐 스케치를 반복하며 원하는 외관과 손맛을 모두 만족하는 기어 메커니즘을 고안했습니다.
제작
모든 부품은 ABS 필라멘트로 3D 프린팅한 후 도색하고 배선했습니다. 처음에는 아두이노 레오나르도를 사용했다가 나중에 마이크로로 교체하여, 사용하지 않을 때 쉽게 보관할 수 있는 플러그 앤 플레이 장치로 완성했습니다.
부품 목록 (3D 프린팅 파트)
레버 모듈 (스로틀, 플랩, 기어 등) - 모듈당 필요 부품
바디 좌측 1개
바디 우측 1개
레버 (디텐트 개수별 2~6단계 5가지 변형 중 선택) 1개
레버 엔드 1개
노브 (6가지 변형 중 선택) 1개
마찰 플레이트 (3가지 변형 중 선택) 1개
포텐셔미터 홀더 1개
트림 휠 모듈
트림 휠 바디 좌측 1개
트림 휠 바디 우측 1개
트림 휠 기어 1개
트림 휠 허브 1개
트림 휠 (조립식 선택 시) 1개
트림 휠 돌기 8개 (조립식 선택 시)
트림 휠 일체형 (일체형 선택 시) 1개
트림 휠 쿼드런트 1개
트림 휠 쿼드런트 드라이브 1개
포텐셔미터 홀더 1개
뒤쪽 박스 파츠를 이용해 아두이노와 배선을 수납할 수 있습니다.
코드 설명
아두이노 레오나르도/마이크로의 기본 HID 조이스틱 라이브러리(Joystick.h)를 사용합니다. 각 아날로그 핀(A0~A5)에 연결된 포텐셔미터 값을 읽어 0~1023 범위로 매핑한 뒤, 해당 조이스틱 축(스로틀, Rx, Ry, Rz, X, Y)에 할당합니다.
캘리브레이션 모드: setting 변수를 0~5로 설정하면 시리얼 모니터에 원시 ADC 값과 변환된 값이 출력됩니다. 이 값을 axisLimits 배열에 입력하면 됩니다.
축 활성화: a0Used~a5Used 불리언으로 각 축 사용 여부를 제어합니다.
translateValue 함수: 포텐셔미터의 최소/최대값을 0~1023 범위로 선형 보간합니다.
#include <Joystick.h>
Joystick_ Joystick;
int axisLimits0[] = {686, 338};
int axisLimits1[] = {345, 695};
int axisLimits2[] = {327, 678};
int axisLimits3[] = {342, 692};
int axisLimits4[] = {0, 1023};
int axisLimits5[] = {0, 1023};
bool a0Used = true;
bool a1Used = true;
bool a2Used = true;
bool a3Used = true;
bool a4Used = false;
bool a5Used = false;
int setting = -1; // -1: 정상, 0~5: 해당 핀 캘리브레이션 출력
void setup() {
if(a0Used) pinMode(A0, INPUT);
if(a1Used) pinMode(A1, INPUT);
if(a2Used) pinMode(A2, INPUT);
if(a3Used) pinMode(A3, INPUT);
if(a4Used) pinMode(A4, INPUT);
if(a5Used) pinMode(A5, INPUT);
Joystick.begin();
if(setting >= 0) Serial.begin(9600);
}
void loop() {
int value = 0, pos = 0;
if(a0Used){ value = analogRead(A0); pos = translateValue(value, axisLimits0[0], axisLimits0[1]); Joystick.setThrottle(pos); if(setting == 0) settingPrint(value, pos); }
if(a1Used){ value = analogRead(A1); pos = translateValue(value, axisLimits1[0], axisLimits1[1]); Joystick.setRxAxis(pos); if(setting == 1) settingPrint(value, pos); }
if(a2Used){ value = analogRead(A2); pos = translateValue(value, axisLimits2[0], axisLimits2[1]); Joystick.setRyAxis(pos); if(setting == 2) settingPrint(value, pos); }
if(a3Used){ value = analogRead(A3); pos = translateValue(value, axisLimits3[0], axisLimits3[1]); Joystick.setRzAxis(pos); if(setting == 3) settingPrint(value, pos); }
if(a4Used){ value = analogRead(A4); pos = translateValue(value, axisLimits4[0], axisLimits4[1]); Joystick.setXAxis(pos); if(setting == 4) settingPrint(value, pos); }
if(a5Used){ value = analogRead(A5); pos = translateValue(value, axisLimits5[0], axisLimits5[1]); Joystick.setYAxis(pos); if(setting == 5) settingPrint(value, pos); }
delay(5);
}
int translateValue(int v, int f1, int f2){
int result = 0, start = 0; float range = 0;
if(f1 < f2){ start = f1; range = f2 - f1; }
else{ start = f2; range = f1 - f2; }
result = (v - start) * (1023 / range);
if(result < 0) result = 0;
if(result > 1023) result = 1023;
return result;
}
void settingPrint(int value, int pos){
Serial.print(value); Serial.print(" "); Serial.println(pos);
}
3D 모델 파일
STEP 파일(released_u3k8QjPXzJ.stp)에 모든 파츠가 포함되어 있습니다. 탭이 없는 버전도 제공됩니다.
회로도
추가 컨트롤은 5V, GND 공통으로 연결하고 A1~A5 핀을 사용하면 됩니다. (quadrant_ZkMygPyRiE.fzz Fritzing 파일 참조)
마무리
코딩은 매우 단순하지만, 트림 휠의 '손맛'을 구현하는 설계 과정이 진짜 도전이었습니다. 직접 만든 컨트롤러로 비행 시뮬레이터를 즐기니 몰입감이 완전히 달라집니다. 파일과 코드를 공유하니 여러분도 나만의 콕핏을 만들어 보세요!