프로젝트

나도 메이커! 메이커스 여러분들의 작품/프로젝트를 공유하는 공간입니다.

DIY BLE 조이스틱 만들기(v1.0)

2016-02-17 17:11:12

안녕하세요! Klant입니다. 오랜만에  프로젝트를 소개하는 것 같아요:)

벌써 새해가 시작되고도 2달이 다 되어가네요ㅎㅎ 여러분들은 새해 잘 보내고 계신가요? 

이번에 진행한 프로젝트는 'DIY BLE 조이스틱'입니다. 

게임이 거대한 문화 컨텐츠로 자리잡으면서, 스마트폰 또는 콘솔게임기를 통해 많은 분들이 게임을 즐기고 계세요;) 

게임하면 떠오르는 그것! 바로 조이스틱(컨트롤러)이죠? 

조이스틱도 시간이 갈수록 점점 부드럽고 날렵한 디자인으로 변해가는 것 같네요.

 

 

어렸을 적 친구들과 함께 문방구 앞에 있던 오락기의 조이스틱 버튼이 닳도록 열심히 눌러댔던 기억이 나네요!

 

출처 : 네이버

 

남자분들이라면 위의 사진에 대해 격한 공감을 하실 거라고 생각해요(이미 고개를 끄덕 끄덕하고 계신 분들도 있겠죠?ㅎㅎ)

어릴 적 추억 생각도 나고 뭔가 복고풍의 조이스틱과 현재의 조이스틱을 적절히 섞어서 만들어 보고 싶은 생각이 들어 이번 프로젝트를 진행하게 되었습니다.

자 그럼 DIY BLE 조이스틱에 대해 소개해볼까요? 

 

 

 

 

개요

 

 

이번 프로젝트는 오렌지보드(BLE)를 활용해 만든 조이스틱입니다.

위에서 언급한 것처럼 복고풍의 옛날 조이스틱의 감성과 현재의 조이스틱을 어떻게 적절히 조합할까에 대해 많이 고민했던 것 같습니다. 

게임을 많이 하는 편은 아니지만 어렸을 때 팩 게임기도 가지고 있었고, 몇 년 전 X-Box도 가지고 있었던 경험을 바탕으로 정리한 컨셉은 아래와 같습니다.

 

복고풍의 조이스틱에서 좋았던 부분 

- 특유의 각지고 간결한 디자인 

- 옛날 게임에서의 게임 효과음(옛날 팩 게임 시절의 게임 효과음은 정말 간단했죠ㅎ)

 

현재 조이스틱에서 좋았던 부분

- 조이스틱의 진동감(Xbox 조이스틱을 처음 잡았을 때 느꼈던 그 진동은 아직도 잊을 수가 없습니다. 정말 신기했거든요)

 

추가로 다양한 기기와 연결해서 사용할 수 있도록 블루투스 통신 기능이 들어가 있으면 좋겠다는 생각을 했습니다. 

 

작동 원리는 간단합니다. 

- 8개의 버튼을 누르면 각 버튼에 해당하는 데이터가 전송됩니다.

- 버튼이 누르는 동시에 진동모터가 진동하며, 피에조 소리에서 소리(간단한 효과음)가 납니다.

 

모델링툴은 스케치업을 사용하였습니다.

이전의 프로젝트보다 사이즈를 작게 만들어야 했기에 모델링에 조금 더 신경을 쓴 것 같습니다. 

또 3D 프린터의 사용 빈도가 높아지다보니 3D 프린터에서 뽑기 쉽게(또는 좋게) 모델링하는 것도 매우 중요하다는 것을 알았습니다. 

모델링은 많이 해보는 것이 좋을 것 같다는 생각이드네요!

 

 

 

 

관련 튜토리얼

 

이 프로젝트는 택트 스위치, 진동 모터, 피에조 부저를 사용하고, 미들 웨어로 프로세싱을 사용합니다.

코코아팹 튜토리얼을 참고해 미리 사용법을 익혀주세요!

- 택트 스위치 사용하기

- 피에조 부저 사용하기

- dc모터 사용하기(진동 모터의 사용법은 dc 모터의 사용법과 크게 다르지 않습니다)

 

 

 

 

부품 목록

 

NO 부품명 수량 상세 설명
1 오렌지보드 나노 BLE 1 arduino NANO
2 택트 스위치 8 mini size
3 슬라이드 스위치    
4 진동 모터 3V
5 피에조 부저 1  
저항 1 330
7 다이오드 1  
8 트랜지스터 1  
9 9V 건전지, 연결 케이블    

 

부품명 택트 스위치 슬라이드 스위치 진동 모터 피에조 부저 다이오드
파트
부품명 트랜지스터 저항 건전지 건전지 연결 케이블
파트

 

 

 

 

 

 

하드웨어 메이킹

 

브레드보드 레이아웃

 

 

 

회로도(스케메틱)

 

 

 

 

 

소프트웨어 코딩

 

아두이노 코딩 

 

오렌지보드에 업로드 되는 코드입니다. 

/*
 제목		: DIY BLE 조이스틱 만들기(v1.0)
 내용		: 옛날 게임기 콘솔 같은 복고풍 게임 조이스틱을 직접 만들어보고, 조이스틱을 통해 직접 게임을 해봅시다. 
 */
 
 
// 데이터를 수신 받을 버퍼 
byte buffer[1024]; 
// 버퍼에 데이터를 저장할 때 기록할 위치
int bufferPosition; 
// 조이스틱에 사용되는 버튼의 핀 리스티
int buttonList[] = {2,3,6,7,8,9,10,11};

// 방향키와 START, PAUSE, A, B키에 관한 핀 번호를 설정
const int LEFT = 2;
const int RIGHT = 6; 
const int UP = 7; 
const int DOWN = 3; 
const int START = 8; 
const int PAUSE = 9; 
const int A = 10; 
const int B = 11;
const int vibration = 12;
const int piezo = A0;
  
void setup(){
	//시리얼 통신 속도를 9600bps로 설정
	Serial.begin(9600); 
	//조이스틱의 사용되는 8개의 핀을 입력 핀으로 설정
	for(int i = 0 ; i < 8 ; i++){
		pinMode(buttonList[i], INPUT_PULLUP);
	}
	//진동모터로 사용할 핀을 출력 핀으로 설정
	pinMode(vibration, OUTPUT);
	//피에조 부저로 사용할 핀을 출력 핀으로 설정
	pinMode(piezo, OUTPUT);
}

void loop(){
	//윗 버튼이 눌렸을 때
	if(digitalRead(UP) == LOW){
		// 왼쪽 버튼이 눌렸다면
		if (digitalRead(LEFT) == LOW) { 
			// 'q' 데이터를 보냄
			Serial.write('q');
			Serial.write('\n');
			delay(20);
    	} 
    	
    	// 오른쪽 버튼이 눌렸다면
		else if (digitalRead(RIGHT) == LOW) { 
			// 'e' 데이터를 보냄
			Serial.write('e');
			Serial.write('\n');
			delay(20);
    	} 
    	
    	// 윗 버튼이 눌리지 않았다면
    	else { 
    		// 'V' 데이터를 보냄
       		Serial.write('V');
       		Serial.write('\n');
       		// 'S' 데이터를 보냄
       		Serial.write('S');
       		Serial.write('\n');
       		delay(20);
    	}   
	}
	
	// 아래 버튼이 눌렸을 때 
	else if(digitalRead(DOWN) == LOW){
		// 왼쪽 버튼이 눌렸다면
		if (digitalRead(LEFT) == LOW) { 
       		// 'z' 데이터를 보냄
       		Serial.write('z');
       		Serial.write('\n');
       		delay(20);
    	} 
    	
    	// 오른쪽 버튼이 눌렸다면
    	else if (digitalRead(RIGHT) == LOW) { 
       		// 'c' 데이터를 보냄
       		Serial.write('c');
       		Serial.write('\n');
       		delay(20);
    	} 
		
		// 아래 버튼이 눌리지 않았다면
    	else{
    		// 'v' 데이터를 보냄
     		Serial.write('v');
     		Serial.write('\n'); 
     		// 's' e데이터를 보냄
     		Serial.write('s');
     		Serial.write('\n');
     		delay(20);      
    	}
	}
	
	// 위, 아래 버튼이 눌리지 않았을 때
	else{
		// 왼쪽 버튼이 눌렸다면
		if (digitalRead(LEFT)==LOW) { 
			// 'h' 데이터를 보냄
       		Serial.write('h');
       		Serial.write('\n');
       		// 's' 데이터를 보냄
       		Serial.write('s');
       		Serial.write('\n');
       		delay(20);
		} 
    	
    	// 오른쪽 버튼이 눌렸다면
		else if (digitalRead(RIGHT)==LOW) { 
			// 'H' 데이터를 보냄
       		Serial.write('H');
       		Serial.write('\n');
       		// 's' 데이터를 보냄
       		Serial.write('s');
       		Serial.write('\n');
       		delay(20);
    	}
		
		//위, 아래 버튼이 눌리지 않았다면
    	else{
    		 // 'S' 데이터를 보냄
    		 Serial.write('S');
		     Serial.write('\n');
		     // 's' 데이터를 보냄
      	     Serial.write('s');
      		 Serial.write('\n');
       		 delay(20);
   		}
  }
  
	// 만약 START 버튼이 눌렸다면
	if (digitalRead(START) ==  LOW) { 
		// 'l' 데이터를 보냄
		Serial.write('l');
     	Serial.write('\n');
     	//진동 모터를 킴
     	digitalWrite(vibration, HIGH);
     	//소리 출력
     	tone(piezo,1500);
     	delay(20);
     	//진동 모터를 끔
     	digitalWrite(vibration, LOW);
     	//소리 출력을 정지함
     	noTone(piezo);  
	} 

	// 이하 PAUSE, A, B 버튼의 코드는 Serial.write를 통해 날리는 데이터만 다를 뿐 구조는 같습니다.
	if (digitalRead(PAUSE) ==  LOW) { 
		Serial.write('d');
     	Serial.write('\n');
     	digitalWrite(vibration, HIGH);
     	tone(piezo,1500);
     	delay(20);
     	digitalWrite(vibration, LOW);
     	noTone(piezo);  
  	} 

	if (digitalRead(A) ==  LOW) {  
   		Serial.write('r');
     	Serial.write('\n');
     	digitalWrite(vibration, HIGH);
     	tone(piezo,1500);
     	delay(20);
     	digitalWrite(vibration, LOW);
     	noTone(piezo);  
  	} 
	
	if (digitalRead(B) ==  LOW) {  
     	Serial.write('u');
     	Serial.write('\n');
     	digitalWrite(vibration, HIGH);
     	tone(piezo,1500);
     	delay(20);
     	digitalWrite(vibration, LOW);
     	noTone(piezo);  
  	} 
  
 	else{
 		// 줄바꿈 데이터를 보냄
    	Serial.write('\n');
    	delay(20);
  	}
}

 

 

 

프로세싱 코딩

 

아래 코드는 프로세싱 코드입니다. 오렌지보드에 업로드하는 코드가 아닙니다.

프로세싱 사용법은 아래 링크를 참고하세요! 

 - 프로세싱 사용법

 

/*
조이스틱과 PC를 연결해 키보드를 제어하기 위한 프로세싱 소스입니다. 
게임 에뮬을 실행하기전 아래의 소스를 실행시켜야 키 입력이 가능합니다.
*/

import processing.serial.*;
import java.awt.*;
import java.awt.event.KeyEvent;

Serial myPort;

boolean temp;
boolean flagX = false;
boolean flagY = false;

void setup() {
	// 현재 PC에 연결되어 있는 포트를 출력합니다.
	println(Serial.list());
	// 아두이노가 연결되어 있는 포트에 맞게 설정해주어야 합니다.
	// 예를들어 com6(다른 기기), com19(아두이노)가 연결 되어 있다면 2번째 포트가 아두이노이기 때문에 Serial.list()[1]로 바꿔줘야 합니다.
	println(Serial.list()[0]);
	String portName = Serial.list()[0];
	myPort = new Serial(this, portName, 9600);
	myPort.bufferUntil('\n');
}

void draw() {
	serialEvent(myPort);
}

// 키보드 이벤트를 위한 함수
void serialEvent(Serial myPort) {
	String inputString = myPort.readStringUntil('\n');
	try{
		inputString = trim(inputString);
		RobotTest(inputString);
	}
	catch(NullPointerException ne){
		inputString = "0";
	}
}

void RobotTest(String temp) {
	try{
    	Robot robot = new Robot();
     	robot.setAutoDelay(10);
     	// 오렌지보드에서 'V' 데이터가 들어오면
		if(temp.equals("V")) {
			// 키보드 위 방향키를 누릅니다.
      		robot.keyPress(KeyEvent.VK_UP);
      		flagY = true;
     	}
     	// 오렌지보드에서 'v' 데이터가 들어오면
     	if(temp.equals("v")) {
     		// 키보드 아래 방향키를 누릅니다.
      		robot.keyPress(KeyEvent.VK_DOWN);
      		flagY = true;
     	}
     	// 오렌지보드에서 'H' 데이터가 들어오면
     	if(temp.equals("H")) {
     		// 키보드 오른 쪽 방향키를 누릅니다.
       		robot.keyPress(KeyEvent.VK_RIGHT);
       		flagX = true;
     	}
     	// 오렌지보드에서 'h' 데이터가 들어오면
     	if(temp.equals("h")) {
     		// 키보드 왼쪽 방향키를 누릅니다.
       		robot.keyPress(KeyEvent.VK_LEFT);
       		flagX = true;
     	}
     	// 오렌지보드에서 'q' 데이터가 들어오면
     	if(temp.equals("q")) {
     		// 키보드의 왼쪽 방향키와 위 쪽 방향키를 누릅니다.
       		robot.keyPress(KeyEvent.VK_LEFT);
       		robot.keyPress(KeyEvent.VK_UP);
       		flagX = true;
       		flagY = true;
     	}
     	// 오렌지보드에서 'e' 데이터가 들어오면
     	if(temp.equals("e")) {
     		// 키보드 오른쪽 방향키와 위 쪽 방향키를 누릅니다.
       		robot.keyPress(KeyEvent.VK_RIGHT);
       		robot.keyPress(KeyEvent.VK_UP);
       		flagX = true;
       		flagY = true;
     	}
     	// 오렌지보드에서 'z' 데이터가 들어오면
     	if(temp.equals("z")) {
     		// 키보드 왼 쪽 방향키와 아래 쪽 방향키를 누릅니다.
       		robot.keyPress(KeyEvent.VK_LEFT);
       		robot.keyPress(KeyEvent.VK_DOWN);
       		flagX = true;
       		flagY = true;       
     	}
     	// 오렌지보드에서 'c' 데이터가 들어오면
     	if(temp.equals("c")) {
     		// 키보드 오른쪽 방향키와 아래 쪽 방향키를 누릅니다.
       		robot.keyPress(KeyEvent.VK_RIGHT);
       		robot.keyPress(KeyEvent.VK_DOWN);
       		flagX = true;
       		flagY = true;      
     	}
     	// 오렌지보드에서 'S' 데이터가 들어오고 X flag가 참이라면
     	if(temp.equals("S") && flagX == true ) { 
     		// 키보드 오른쪽 방향키와 왼 쪽 방향키를 땝니다.
       		robot.keyRelease(KeyEvent.VK_RIGHT);
       		robot.keyRelease(KeyEvent.VK_LEFT);
       		flagX = false;
     	}
     	// 오렌지보드에서 's' 데이터가 들어오고 y flag가 참이라면
     	if(temp.equals("s") && flagY == true) {
     		// 키보드 위쪽 방향키와 아래 쪽 방향키를 땝니다. 
       		robot.keyRelease(KeyEvent.VK_UP);
       		robot.keyRelease(KeyEvent.VK_DOWN);
       		flagY = false;
     	}
  		// 오렌지보드에서 'l' 데이터가 들어오면
    	if(temp.equals("l")) {
    		// 키보드의 A 키를 눌렀다 땝니다.
     		robot.keyPress(KeyEvent.VK_A);
     		robot.delay(5);
     		robot.keyRelease(KeyEvent.VK_A);
    	}
    	// 이하 코드는 오렌지보드에서 들어오는 데이터와 눌리는 키보드의 키만 다를 뿐 코드는 같습니다.
    	if(temp.equals("d")) {
     		robot.keyPress(KeyEvent.VK_S);
     		robot.delay(5);
     		robot.keyRelease(KeyEvent.VK_S);
    	}
    	if(temp.equals("r")) {
     		robot.keyPress(KeyEvent.VK_D);
     		robot.delay(5);
     		robot.keyRelease(KeyEvent.VK_D);
    	}
    	if(temp.equals("u")) {
     		robot.keyPress(KeyEvent.VK_C);
     		robot.delay(5);
     		robot.keyRelease(KeyEvent.VK_C);
    	}
    	if(temp.equals("t")) {
     		robot.keyPress(KeyEvent.VK_1);
     		robot.delay(5);
     	robot.keyRelease(KeyEvent.VK_1);
    	}
	}
 	catch(Exception e){
  	}
}

 

 

제작 과정

 

DIY 조이스틱을 만드는 과정에 대해 소개해보도록 하겠습니다 ;) 

우선 조이스틱의 외관부터 만들어 봐야 겠죠? 

스케치업을 통해 외관 디자인을 진행해주었습니다!

 

DIY 조이스틱은 총 3층으로 구성되어 있으며, 1층은 건전지, 2층은 오렌지보드, 3층은 조이스틱 기판이 위치하게 됩니다. 

1층부터 차근 차근 살펴볼까요? 

 

1층은 9V 건전지와 각종 선들이 들어가는 공간입니다. 우측에 건전지가 들어갈 공간을 만들어 줍니다. 

건전지는 소모 후 교체가 필요하기에 건전지 교체가 가능하도록 덮개를 더 만들어주었습니다.

 

 

2층은 오렌지보드가 들어갈 공간입니다. 우측의 구멍은 건전지의 높이를 고려해 뚫어주었습니다. 좌측의 구멍은 usb를 꽂기 위한 구멍이구요!

 

 

3층은 조이스틱 기판(만능 기판)이 놓여질 자리입니다. 2층의 오렌지보드에 연결되는 선들이 많기 때문에 많은 공간들을 비워두었습니다. 

 

 

마지막으로 조이스틱의 덮개 부분입니다. 피에조 부저와 8개의 버튼들이 나올 공간을 생각하고 모델링을 진행해주어야 합니다. 

저 같은 경우 만능 기판의 구멍 간격을 기준으로 모델링하였습니다. 

 

 

 

조이스틱 윗면을 장식해줄 파츠와 버튼들도 모델링을 진행해주었습니다. 

 

 

모든 파츠들을 적층한 모습입니다~ 

모델링을 마무리 했으니 이제 부품들을 연결할 차례입니다. 

3D 프린터로 출력하는 과정은 사진을 미쳐 찍지 못했네요ㅜㅜ 다음 프로젝트부터는 사진 찍는 걸 습관화 해야겠어요!

부품 연결 과정도 살펴볼까요? ~ ;)

 

 

부품을 만능 기판위에 배치 시켜 준 후 납땜을 진행합니다. 

 

 

만능 기판에 배치한 소자들을 오렌지보드와 연결해줍니다. 연결한 후에는 미리 파놓은 홈에 오렌지보드를 고정시켜줍니다.

 

 

1층에 해당하는 파츠에 전원 제어 역할을 하는 on, off 스위치도 결합해줍니다. 

 

 

건전지와 on, off 스위치도 오렌지보드에 연결한 후 만능 기판 까지 적층해줍니다. 

이제 어느정도 조이스틱의 느낌이 나지 않나요? 

 

 

덮개를 덮고 버튼까지 결합을 시켜준 모습입니다. 하지만 아직 좀 밋밋합니다.(흠.....2% 부족해)

이런 걸 대비해 모델링 해준 덮개 파츠를 윗면에 부착해줍니다. 

덮개 파츠까지 부착한 조이스틱의 최종 완성 모습을 감상해보실까요?

 

 

 

 

완성 모습

 

완성된 DIY 조이스틱의 모습입니다. 주황색 덮개가 올라가니 밋밋한 느낌이 확 사라졌죠?~

 

 

조이스틱의 전원을 키면 측면에 파란색 LED가 점등됩니다. 이 LED를 통해 조이스틱의 on, off 상태를 체크할 수 있습니다. 

 

 

 

 

게임 조작 영상

 

네오지오의 메탈슬러그를 조작하는 영상입니다~ ;)

 

 

 

 

리소스

 

프로젝트에 사용된 소스들입니다. 이미지를 클릭하여 해당 파일을 다운받으세요! ;)

 

                                        

 

마치며...

 

이번 버전에서는 컴퓨터와 유선으로 연결하여 게임을 조작하여 보았지만, BLE 기능이 내장된 조이스틱인 만큼 컴퓨터에 무선으로 연결하여 게임을 해봐야겠죠? 

다음 버전에서는 다양한 기기들과 연결해 게임을 플레이하는 과정을 설명하도록 하겠습니다! 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Klant

오픈소스 하드웨어, 코코아팹, 아두이노, 오렌지보드, 조이스틱, 블루투스, opensource hardware, kocoafab, arduino, orangeboard, joystick, bluetooth, BLE, DIY