조이스틱 쉴드(Joystick Shield) 퀵 스타트 가이드

조이스틱 쉴드(Joystick Shield) 퀵 스타트 가이드

먼저 조이스틱 쉴드는 키트형태의 제품으로 조립이 필요합니다. 어떻게 조립을 하여야 하는지는 조립가이드를 참고하십시오.

조이스틱 쉴드로 할 수 있는 것들은?

조이스틱 쉴드는 네개의 버튼과 조이스틱을 통하여 간단한 아날로그 입력을 줄수 있는 제품으로 멜로디 출력이나 화면상의 픽셀 출력을 제어하는데 사용할 수 있습니다. 버튼은 네비게이션 용도로 사용하거나 게임컨트롤에 사용할 수 있습니다. 아래는 조이스틱 쉴드를 사용하는 스케치 예제 코드입니다.

아래의 비디오는 조이스틱 쉴드를 이용하여 만든 일종의 게임기 프로토타입입니다.

YouTube 동영상


조이스틱 쉴드 동작시키기

조이스틱 쉴드를 동작시키는 법을 알아보기 위해 아래의 질문에 대한 답변을 위주로 살펴보겠습니다.


Q)조이스틱의 현재 위치를 어떻게 알아내나요?

조이스틱의 위치는 조이스틱안에 있는 두개의 포텐셔미터를 통해 계산됩니다. 조이스틱은 두개의 방향으로 움직일 수 있는데 보통 이것이 x,y 축이 되게 됩니다. 포텐셔미터를 읽기 위해서는 analogRead()함수를 사용합니다. 이함수는 0에서 1023까지의 숫자를 리턴하여 줍니다. 동작하기 위한 아날로그 핀 번호를 아두이노에 알려주어야 하는데 X축 위치는 아날로그 핀 0번에서 Y축위치는 아날로그 핀 1번에서 읽어 옵니다.

Serial.println(analogRead(0)); // Prints current X position
Serial.println(analogRead(1)); // Prints current Y position

X,Y축의 핀의 위치는 코드관리 편의상 const상수값으로 아래와 같이 PIN_ANALOG_X와 PIN_ANALOG_Y로 정의 하고 아래와 같이 조이스틱의 위치를 알아내는 코드를 작성하였습니다.

const byte PIN_ANALOG_X = 0;
const byte PIN_ANALOG_Y = 1;

void setup() {
  Serial.begin(9600);
}

void loop() {

  Serial.print("x:");
  Serial.print(analogRead(PIN_ANALOG_X));
  Serial.print(" ");
 
  Serial.print("y:");
  Serial.print(analogRead(PIN_ANALOG_Y));
  Serial.print(" ");  
 
  Serial.println();
}

Q)조이스틱의 현재 방향은 어떻게 알아내나요?

조이스틱이 향하는 방향을 알아내기 위해서는 X,Y 좌표값을 이용하는 것이 좋습니다. 조이스틱을 움직이지 않았을 경우 조이스틱은 X,Y좌표의 중앙에 위치하기 때문에 두개의 좌표를 이용하면 조이스틱이 향한 방향을 알아 낼수 있습니다.

각각의 좌표축은 0에서 1023의 값을 가지기 때문에 중간값은 511이나 512정도가 된다는 것을 예측할 수 있습니다. 물론 조이스틱은 물리적인 장치이기 때문에 실제 값은 이렇게 정확하지 않을 수 있기때문에 실제로 중앙에 위치된 값을 잘 알아 내는 것이 중요합니다. 이 중앙 값이 잘못설정되면 조이스틱을 움직이지 않았는데도 움직이고 있다고 계산할 수 있기 때문입니다.

중앙의 값이 실제로 아주 정확하지 않기 때문에 threshold값을 주어 특정 범위 내에 있는 값은 중앙이라고 인식하게 만듭니다.

|----------|----|----------|
0         505  515        1023

위의 그림에서는 505에서 515까지를 중앙으로 설정하였습니다. 이런 threshold값은 사용자가 가지고 있는 조이스틱에 따라 달라잘 수 있습니다. 이 thershold값도 코드관리 편의상 const상수값으로 아래와 같이 선언하였습니다.

const int X_THRESHOLD_LOW = 505;
const int X_THRESHOLD_HIGH = 515;    

const int Y_THRESHOLD_LOW = 500;
const int Y_THRESHOLD_HIGH = 510;

다음으로, 방향을 간단하게 표현하기 위해 0에서 1023사이에 있는 각각의 위치값을 -1 이나 1로 맵핑시킵니다. X축에서는 -1은 왼쪽으로 움직이는 것을 의미하고 0은 움직이지 않고 1은 오른쪽으로 움직이는 것을 의미합니다. Y축에서는 -1은 아래를 0은 안움직이는 것을 1은 위로 움직이는 것을 의미합니다.

조이스틱은 처음에는 움직이지 않기 때문에 각각의 방향을 0으로 셋팅하고, 그 후 if/else 문을 사용하여 각 축에 있는 위치값이 thershold값의 위에 혹은 아래에 있는지 확인합니다.

x_direction = 0;
  y_direction = 0;
 
  x_position = analogRead(PIN_ANALOG_X);
  y_position = analogRead(PIN_ANALOG_Y);
 
 
  if (x_position > X_THRESHOLD_HIGH) {
    x_direction = 1;
  } else if (x_position < X_THRESHOLD_LOW) {
    x_direction = -1;
  }

  if (y_position > Y_THRESHOLD_HIGH) {
    y_direction = 1;
  } else if (y_position < Y_THRESHOLD_LOW) {
    y_direction = -1;
  }

아래는 완전히 작성된 예제 코드인데 if/else문을 사용하여 방향을 print하는 부분이 추가 되었습니다.

const byte PIN_ANALOG_X = 0;
const byte PIN_ANALOG_Y = 1;

const int X_THRESHOLD_LOW = 505;
const int X_THRESHOLD_HIGH = 515;    

const int Y_THRESHOLD_LOW = 500;
const int Y_THRESHOLD_HIGH = 510;    

int x_position;
int y_position;

int x_direction;
int y_direction;

void setup() {
  Serial.begin(9600);
}

void loop () {
  x_direction = 0;
  y_direction = 0;
 
  x_position = analogRead(PIN_ANALOG_X);
  y_position = analogRead(PIN_ANALOG_Y);
 
 
  if (x_position > X_THRESHOLD_HIGH) {
    x_direction = 1;
  } else if (x_position < X_THRESHOLD_LOW) {
    x_direction = -1;
  }

  if (y_position > Y_THRESHOLD_HIGH) {
    y_direction = 1;
  } else if (y_position < Y_THRESHOLD_LOW) {
    y_direction = -1;
  }
   
 
  if (x_direction == -1) {
      if (y_direction == -1) {
        Serial.println("left-down");
      } else if (y_direction == 0) {
        Serial.println("left");
      } else {
        // y_direction == 1
        Serial.println("left-up");      
      }  
  } else if (x_direction == 0) {
      if (y_direction == -1) {
        Serial.println("down");
      } else if (y_direction == 0) {
        Serial.println("centered");
      } else {
        // y_direction == 1
        Serial.println("up");      
      }
  } else {
      // x_direction == 1
      if (y_direction == -1) {
        Serial.println("right-down");
      } else if (y_direction == 0) {
        Serial.println("right");
      } else {
        // y_direction == 1
        Serial.println("right-up");      
      }
  }

Q)조이스틱 쉴드의 버튼이 눌렸는지 알려면 아두이노를 어떻게 셋업해야 하나요?

조이스틱쉴드의 버튼이 눌렸는지를 확인하려면 먼저 아두이노가 버튼을 인식할 수 있게 셋업이 되어 있어야 합니다. 이러한 셋업은 아두이노 스케치 코드의 setup()함수 안에서 실행할 수 있습니다.

먼저 각각에 버튼에 맞는 const 상수값을 정의 합니다.

// Select button is triggered when joystick is pressed
const byte PIN_BUTTON_SELECT = 2;

const byte PIN_BUTTON_RIGHT = 3;
const byte PIN_BUTTON_UP = 4;
const byte PIN_BUTTON_DOWN = 5;
const byte PIN_BUTTON_LEFT = 6;

예전에 푸쉬버튼 스위치를 사용하여 보신분이라면 전압을 검출하기 위해 보통 푸쉬버튼의 사용이 필요하다는 점을 알고 있을 것입니다. 하지만 본 조이스틱 쉴드는 그러한 저항이 없이 설계되었습니다. 그러면 푸쉬버튼을 동작시키기 위해서 저항이 필요하는 것인가요? 라고 질문하시는 분들이 있을 지 모릅니다.

아두이노에는 사실 핀에 연결된 내부 저항이 있습니다. 이 내부 저항을 사용하기 위해서는 내부 풀업 저항을 활성화 시켜주면 됩니다.

풀업저항이 푸쉬버튼에 연결되었다는 말의 의미는 버튼이 눌리지 않았을때의 전압레벨이 HIGH임을 의미합니다. 왜냐하면 버튼이 눌리지 않았을 때는 풀업 저항이 전압레벨을 UP 시켜 놓고 있기 때문이죠. 일반적으로 아두이노 핀이 high일 경우 전압은 5v입니다. 푸쉬버튼이 눌리게 되면 핀은 LOW로 읽히게 됩니다. 왜냐하면 핀과 5V사이에 있는 저항보다 핀과 그라운드 사이의 저항이 더 낮기 때문입니다.

핀의 풀업저항을 활성화 시키기 위해서는 먼저 핀을 입력으로 설정한 후 풀업 저항을 활성화 시킵니다.

pinMode(PIN_BUTTON_RIGHT, INPUT);
digitalWrite(PIN_BUTTON_RIGHT, HIGH);

풀업저항을 활성화 시키는 위의 실제 코드를 보면 풀업저항을 활성화 시키는 부분은 어디를 봐도 없어 보이지만, 이렇게 명령을 주면 실제로는 풀업저항이 활성화 됩니다.

이렇게 설정하면 버튼이 안눌릴 경우는 HIGH로 눌릴 경우는 LOW로 읽힌다는 점을 기억하십시오.

각각의 핀을 입력핀으로 설정하고 내부의 풀업저항을 활성화 하기 위해서 아래와 같은 코드를 사용합니다.

void setup() {

  pinMode(PIN_BUTTON_RIGHT, INPUT);  
  digitalWrite(PIN_BUTTON_RIGHT, HIGH);
 
  pinMode(PIN_BUTTON_LEFT, INPUT);  
  digitalWrite(PIN_BUTTON_LEFT, HIGH);
 
  pinMode(PIN_BUTTON_UP, INPUT);  
  digitalWrite(PIN_BUTTON_UP, HIGH);
 
  pinMode(PIN_BUTTON_DOWN, INPUT);  
  digitalWrite(PIN_BUTTON_DOWN, HIGH);
 
  pinMode(PIN_BUTTON_SELECT, INPUT);  
  digitalWrite(PIN_BUTTON_SELECT, HIGH);
}

Q) 조이스틱 쉴드의 버튼이 눌렸는지 안눌렸는지는 어떻게 아나요?

아두이노가 버튼을 인식 할 수 있게 위의 코드와 같이 셋업하였다면, digitalRead()함수로 버튼이 눌렸는지 아닌지를 알 수 있습니다. 읽은 값이 LOW이면 버튼이 눌린 것이고 HIGH이면 눌리지 않은 것입니다.

if (digitalRead(PIN_BUTTON_LEFT) == LOW) {
    // Button is pressed
} else {
   // Button is not pressed
}

아래 코드는 각각의 버튼의 상태를 출력하고 조이스틱의 값을 시리얼 콘솔에 출력하는 완전히 작성된 예제입니다.

// Store the Arduino pin associated with each input

// Select button is triggered when joystick is pressed
const byte PIN_BUTTON_SELECT = 2; 

const byte PIN_BUTTON_RIGHT = 3;
const byte PIN_BUTTON_UP = 4;
const byte PIN_BUTTON_DOWN = 5;
const byte PIN_BUTTON_LEFT = 6;

const byte PIN_ANALOG_X = 0;
const byte PIN_ANALOG_Y = 1;


void setup() {
  Serial.begin(9600);

  pinMode(PIN_BUTTON_RIGHT, INPUT);  
  digitalWrite(PIN_BUTTON_RIGHT, HIGH);
 
  pinMode(PIN_BUTTON_LEFT, INPUT);  
  digitalWrite(PIN_BUTTON_LEFT, HIGH);
 
  pinMode(PIN_BUTTON_UP, INPUT);  
  digitalWrite(PIN_BUTTON_UP, HIGH);
 
  pinMode(PIN_BUTTON_DOWN, INPUT);  
  digitalWrite(PIN_BUTTON_DOWN, HIGH);
 
  pinMode(PIN_BUTTON_SELECT, INPUT);  
  digitalWrite(PIN_BUTTON_SELECT, HIGH);  
}


void loop() {
  Serial.print("l:");
  Serial.print(digitalRead(PIN_BUTTON_LEFT));
  Serial.print(" ");
 
  Serial.print("r:");
  Serial.print(digitalRead(PIN_BUTTON_RIGHT));
  Serial.print(" ");
 
  Serial.print("u:");
  Serial.print(digitalRead(PIN_BUTTON_UP));
  Serial.print(" ");
 
  Serial.print("d:");
  Serial.print(digitalRead(PIN_BUTTON_DOWN));
  Serial.print(" ");

  Serial.print("x:");
  Serial.print(analogRead(PIN_ANALOG_X));
  Serial.print(" ");
 
  Serial.print("y:");
  Serial.print(analogRead(PIN_ANALOG_Y));
  Serial.print(" ");  
 
  Serial.print("s:");
  Serial.print(digitalRead(PIN_BUTTON_SELECT));
  Serial.print(" ");
 
  Serial.println();
}

제품정보: http://vctec.co.kr/front/php/product.php?product_no=795&main_cate_no=161&display_group=1

가치창조기술

Comments