[아두이노] 조이스틱 방향키 값 출력

IOT/아두이노|2019. 4. 26. 09:00

[아두이노] 조이스틱 방향키 값 출력



지난 조이스틱 포스트에서 현재 상태값을 출력하는 실험을 했었습니다. 그리고 조이스틱 두번째 포스트에서는 조이스틱 X축 0~1023 아날로그 신호 값을 기준으로 Servo Motor를 제어도 해보았습니다. 마무리에 방향 조절에 대한 로직을 간단히 글로 소개 한 적이 있는데 이번에 제대로 이 주제에 대해 포스트를 할까 합니다.


날씨가 우중충해서 그런가 사진이 이상하게 나왔네요.

1. 조이스틱 방향키 값 만들기




위그림은 지난 조이스틱 회로도 입니다.


조이스틱의 X(A0)핀, Y(A1)핀 값을 위 그림과 같은 방향 키값으로 만들어 내려고 합니다.

[복습] : 조이스틱 현재 상태값 출력

const int AXIS_X = A0;
const int AXIS_Y = A1;
const int SW_P = 2; 
 
void setup() {
  Serial.begin(9600);
  pinMode(SW_P,INPUT_PULLUP);
}
 
void loop() {

  Serial.print("Axis_X: ");
  Serial.println(analogRead(AXIS_X));

  Serial.print("Axis_Y: ");
  Serial.println(analogRead(AXIS_Y));

  Serial.print("SW_P:  ");
  Serial.println(digitalRead(SW_P));

  delay(500);
}

위 소스는 조이스틱의 상태값을 시리얼모니터로 출력하는 예제입니다. 방향키 값을 만들기 위해서 Axis_X, Axis_Y 값에서 방향값으로 분리해 낼 능력이 필요합니다.

Axis_X, Axis_Y 값은 0~1023의 아날로그 값을 가집니다. 이론상으로 조이스틱의 중심값은 (X, Y)은 (512, 512)가 됩니다.

여기서, X축으로 아날로그 값 0~1023에서 A방향의 아날로그 신호값의 범위는 0~512 사이가 되고 D방향의 아날로그 신호값의 범위는 512~1023 사이가 됩니다. 그런데 실제로 조이스틱은 512가 중심값이 아니라고 했죠. 하드웨어 자체 조립과정의 문제와 환경적 요인에 의해 512의 근사값이라고 저번 시간에 이야기 했는데 오늘 실험에서는 정밀 제어가 아닌 기초적인 간단한 제어임으로 512이라고 가정하겠습니다.

위 그림을 보면 동그라미 모양이 있죠. 이 동그라미 영역은 방향 불인정 영역으로 잡아 놓고 나머지 영역을 방향으로 하면 방향을 명확하게 나눌 수 있습니다. 즉, 조이스틱의 방향을 움직일 때 동그라미 영역을 무시하고 그 나머지 신호값을 해당 방향의 키값으로 설정하면 명확하게 나누어지게 됩니다. 그 이유는 중심 근처는 방향 신호값의 변화가 너무 심하기 때문입니다. A와 D값의 교차 변화가 중심 근처에서 빈번하게 발생하면 키 값이 교차로 빈번하게 출력되고 그 값을 통해서 움직이는 물체는 떠는 것처럼 "덜덜덜" 하면서 움직이게 됩니다. 움직임의 값이 크게 세팅하면 왔다 갔다 반복하는 현상이 그 중심점에서 빈번하게 일어난다고 생각하시면 될 듯 싶네요. 그래서 중심지점 근방은 방향 신호값으로 인정 안함으로써 좀 도 명확하게 방향키 값을 잡는 것이죠.

제 경우는 그냥 500을 기준으로 X축 좌/우 방향을 200씩 무시구간을 잡았습니다. 정확히 200이 아니라 그냥 500기준 200으로 정교함보다는 의미 전달 방향키 값임을 참고하고 보시기 바랍니다.

[X축 키값 구하기]

  //X축 방향값
  if(analogRead(AXIS_X)<=300){
    Serial.println('a');
  }
  else if(analogRead(AXIS_X)>=700){
    Serial.println('d');   
  }

위 코딩은 X축을 기준으로 방향키 a, d를 출력하는 로직입니다. 500을 기준으로 300이하일때 왼쪽(a)키로 인정하고 700이상일때 오른쪽(d)키로 인정한다는 문장입니다.
만약에, 정확하게 나눌려면 조이스틱 X중심이 521로 설정되어 있으면 200차이로 나눈다면 왼쪽 기준은 321이고, 오른쪽 기준 721이겠죠. 간단한 실험이라 수치를 보기 편하게 단순화 시킨 수치입니다. 여러분들은 조이스틱로 실제 제어한다면 300, 700으로 하지 말고 좀 더 조정된 값으로 제어를 하셨으면 합니다.

여기서, if문을 개별적으로 해도 되지만 else if문을 쓴 이유가 뭘까요. AXIS_X 기준 신호로 보면 기준 신호 값에서 +, - 값인 둘중 하나상태만 존재하기 때문입니다. 예를 들면은 X축의 조정신호 값이 오른쪽이면서 왼쪽일 수 없잖아요. 오른쪽이면 오른쪽 신호값만 왼쪽이면 왼쪽 신호값만 존재합니다. 동시 오른쪽, 왼쪽이 나올 수 없습니다. 그래서 if~else if 문으로 왼쪽이냐 묻고 아니면 오른쪽이냐 묻는 문게 했습니다. 이 표현이 가장 괜찮은 코딩으로 이렇게 if~else if문을 사용하게 되었습니다.

반대로, Y축을 살펴볼까요 동일합니다.

[Y축 키값 구하기]

//Y축 방향값
  if(analogRead(AXIS_Y)<=300){
    Serial.println('w');      
  }
  else if(analogRead(AXIS_Y)>=700){
    Serial.println('s');
  }

그러면, 여기서 왜 X축과 Y축을 다 묶어서 if~else if문을 쓰지 않았을 까요.

  if(analogRead(AXIS_X)<=300){
    Serial.println('a');
  }
  else if(analogRead(AXIS_X)>=700){
    Serial.println('d');   
  }
  else if(analogRead(AXIS_Y)<=300){
    Serial.println('w');      
  }
  else if(analogRead(AXIS_Y)>=700){
    Serial.println('s');
  }

이렇게 안한 이유는 조이스틱에서 X, Y축을 동시에 읽어오게 됩니다. 그러면 X축을 읽고 X축의 값에 만족하는 왼쪽/오른쪽이 결정되면은 Y축은 무시하고 넘어가게 됩니다. 그래서 X축의 방향키를 구하고 Y축의 방향키를 구하는 식을 따로 if문을 분리해서 코딩한 것이죠.

if문을 어떻게 처리하냐에 따라서 그 의미는 완전 달라지기 때문에 if문도 신중하게 써야 합니다. 그리고 위 코딩도 썩 좋은 코딩이 아닙니다. 해당 축을 읽는 함수는 한번으로 하면 좋지만 두번 연속으로는 읽는다면 비효율적이겠죠.

int x = analogRead(AXIS_X);
int y = analogRead(AXIS_Y);

x, y값을 if문으로 비교하시면 구지 두번 반복해서 읽을 필요는 없게 됩니다. 전 그냥 2번 반복읽기로 뒀네요.

2. 코딩


const int AXIS_X = A0;
const int AXIS_Y = A1;
const int SW_P = 3; 
 
void setup() {
  Serial.begin(9600);
  pinMode(SW_P,INPUT_PULLUP);
}
 void loop() {
  //X축 방향값
  if(analogRead(AXIS_X)<=300){
    Serial.println('a');
  }
  else if(analogRead(AXIS_X)>=700){
    Serial.println('d');   
  }
  //Y축 방향값
  if(analogRead(AXIS_Y)<=300){
    Serial.println('w');      
  }
  else if(analogRead(AXIS_Y)>=700){
    Serial.println('s');
  }
  delay(20);
}

스위치 버턴도 선언은 했지만 그냥 해당 버턴키는 만들지 않았습니다. 다음에 processing과 연동 할 때 줌인/줌아웃키로 하려고 햇는데 스위치버턴이 한개라 따로 뻥판에 스위치 버턴을 만들어 표현 할 수 있었지만 그냥 방향제어만으로만 포스팅을 하고 위 틀은 확장 코딩을 할 수 있는 상태로 표현했다고 생각하시면 될 듯 싶네요. 나머지 코딩은 여러분들이 추가로 스위치 버턴을 가지고 제어해보시라고 남겨 둡니다.

미완성 코딩으로 위에 아날로그 신호값을 읽어 변수에 저장하는 것과 스위치 버턴을 추가로 로직을 짜셔 완성 시켜보세요.

3. 결과


시리얼 모니터로 출력되는 영상 입니다.


깔끔하게 잘 나오네요. 다음은 폰으로 조이스틱을 움직일 때 키 값이 나오는 영상입니다.


마무리


오늘은 간단히 조이스틱의 방향 키 값을 시리얼모니터로 출력 했습니다. 이 출력이 무슨 키 값이야 하고 생각하실 수 있지만 내일 포스트는 processing과 연동합니다. 시리얼통신으로 보내지는 이 알파벳 값을 processing에서 읽고 그 값을 기준으로 지난 processing 예제인 box 3D 도형을 도형을 움직이게 할 예정 입니다. 키보드로 제어 했던 부분을 오늘 배운 키 값으로 제어하겠다는 의미인 셈이죠. 왜! 키 값인지 아시겠지요.

오늘 포스트 한 내용을 잘 따라오셔야 내일 재밌는 것을 할 수 있습니다.

이상 마무리 하고 오늘도 배운 내용을 어디서 써먹을지 상상의 나래를 펼쳐 보세요.

댓글()