마우스에 해당하는 글 1

[아두이노] 아두이노 마우스 제어

IOT/아두이노|2019. 6. 25. 09:00

[아두이노] 아두이노 마우스 제어



지난 시간에 아두이노 마이크로 보드로 키보드 제어를 해 보았습니다. 오늘은 마우스를 제어해보는 시간을 갖도록 하죠. 키보드와 마찬가지로 마우스도 몇개의 함수만 이해하시면 쉽게 아두이노를 이용해서 마우스의 동작을 수행할 수 있습니다.

이제 본격적으로 마우스 제어를 해볼까요.


1. 아두이노 키보드 제어



위 사전학습으로 읽고 오시면 됩니다. 사전학습 자료를 보시면 7개의 함수가 있는데 이 함수만 알면 마우스 제어를 마음대로 할 수 있습니다. 간단히 함수에 대해 살펴 볼까요.

  • button : MOUSE_LEFT (default), MOUSE_RIGHT, MOUSE_MIDDLE
  • 마우스 시작 : Mouse.begin()
  • 마우스 클릭 : Mouse.click() or Mouse.click(button)
  • 마우스 종료 : Mouse.end()
  • 마우스 이동 : Mouse.move(xVal, yPos, wheel) - x축, 축, 스크롤 휠의 움직임 양
  • 마우스 버턴 클릭 : Mouse.press() or Mouse.press(button)
  • 마우스 버턴 해제 : Mouse.release() or Mouse.release(button)
  • 현재 마우스가 눌러진 정보 반환 : Mouse.isPressed() or Mouse.isPressed(button)

함수도 그렇게 어렵지 않죠. 기본적으로 마우스 클릭과 마우스 이동에 관한 함수만 이해하시면 됩니다.

1) 마우스 이동 제어


마우스 이동 제어하는 방법은 다음과 같습니다.

[기본소스]

#include <Mouse.h>

void setup(){
  Mouse.begin();
}
void loop(){
  if(버턴누름){
    Mouse.move(x, y, 스크롤휠);
  }
}

위 소스가 기본 마우스 이동 동작입니다. 마우스로 위로 이동한다면 어떻게 코딩할까요.

if(digitalRead(Pin_Up) == LOW){ //위로
  Mouse.move(0, -1, 0);
}

참골, 위/아래, 좌/우로 움직임을 x,y값만 바꾸시면 되고, 위로 이동하는 위 명령문을 수정하여 코딩하시면 나머지 동작 명령을 수행할 수 있게 됩니다.

2) 마우스 클릭 제어


[기본소스]

#include <Mouse.h>

void setup(){
  Mouse.begin();
}

void loop(){ 
  if(버턴누름){
    Mouse.click();
  }
}

기본 보스를 보면 Mouse.click()함수는 디폴트로 MOUSE_LEFT 클릭이 됩니다. 특정 키를 누르고 싶다면 어떻게 코딩할까요.

Mouse.click(MOUSE_RIGHT);

어떤 느낌인지 아시겠지요.

  • button : MOUSE_LEFT (default), MOUSE_RIGHT, MOUSE_MIDDLE

기본적으로 버턴은 위의 세가지 왼쪽, 오른쪽, 중앙 버턴으로 나뉘고 지정해주면 해당 버턴이 클릭됩니다. 지정하지 않으면 디폴트로 왼쪽 버턴을 클릭하신다고 보시면 됩니다.

추가로, Mouse.click()함수는 클릭 이벤트입니다. 다른 방식으로 표현하면은 다음과 같습니다.

void loop(){ 
  if(버턴누름){
    Mouse.press(MOUSE_LEFT);
    delay(100);
    Mouse.release(MOUSE_LEFT);
    delay(200);
  }
}

마우스 키를 누름과 해제로 마우스 클릭 이벤트를 만들어 냅니다. 이와 같은 방식은 사실 클릭함수만 있으면 되지 구지 이 함수로 표현을 하냐 하실분들이 있을거에요. 누름(press)과 해제(release) 함수는 사용되는 곳이 따로 있습니다. 가령, 웹페이지가 있으면 특정 영역을 복사하기 위해서 어떻게 하나요 마우슨 왼쪽을 누른 상태에서 드래그를 하고 복사할 위치에서 마우스 누른 상태를 해제합니다. 이렇게 마우스의 클릭이 아니라 일정시간 마우스의 누름이 필요할 때는 사용되는 함수입니다. 클릭으로 사용해도 되고 또는 특정한 누름 일정시간 동안 유지가 필요할 때도 사용됩니다.

  if(버턴누름){
    Mouse.press(MOUSE_LEFT);        
  }else if(버턴 해제 && Mouse.isPressed()==1){
    Mouse.release(MOUSE_LEFT);
  } 

버턴을 누르고 있는 동안은 마우스 왼쪽 버턴이 클릭된 상태가 되겠죠. 이방식은 계속 클릭 명령을 내리기 때문에 별로 좋지 않습니다. 한 상태를 계속 유지하고 클릭을 반복 명령을 내리게 하고 싶지 않다면 아래와 같이 변경해야 합니다.

 if(버턴누름){
    if( Mouse.isPressed()==0) Mouse.press(MOUSE_LEFT);      
  }else if(버턴 해제 && Mouse.isPressed()==1){
    Mouse.release(MOUSE_LEFT);
  } 

이런게 마우스 클릭 상태정보가 0이면 클릭상태가 아니기 때문에 마우스왼쪽 버턴을 클릭하고 클릭상태가 1이면 클릭되어 있으니깐 계속 그 상태를 유지되고 있으니 구지 다시 클릭명령을 내릴 필요가 없습니다.

3) 마우스 상태 정보 반환


Mouse.isPressed() or Mouse.isPressed(button) 함수로 현재 마우스 상태 정보를 읽어 올 수 있습니다. 만약에 마우스 왼쪽 버턴을 눌렀다면 왼쪽버턴을 누른 상태 정보를 반환해 오겠죠.

정확히 어떤 값을 갖는지 살펴볼까요.

if(digitalRead(버턴핀) == LOW){ //버턴클릭
  Mouse.press(MOUSE_LEFT);
  Serial.println(Mouse.isPressed());
  delay(100);
  Mouse.release(MOUSE_LEFT);
  Serial.println(Mouse.isPressed());
  delay(200);     
}

[결과]

1
0

이렇게 출력됩니다 마우스를 press() 클릭하면 isPressed()함수로 해당 클릭 상태 정보 1을 반환합니다. 그리고 다시 release()함수로 해제하니깐 isPressed()함수로 반환되는 값은 0이 됩니다.

마우스 상태 정보 반환하는 함수는 해당 마우스버턴을 현재 클릭 정보를 통해서 다른 동작 명령을 다른 동작을 수행하거나 락을 걸어주거나 어떤 조건을 만들어 주기위해서 사용합니다. 위의 마우스 클릭 처럼 버턴을 클릭했다면 클릭했을 때 상태정보가 1이면 다음 클릭에서도 그 상태를 유지하니깐 구지 두번 명령을 내릴 필요가 없게 표현이 가능합니다. 그리고 어떤 클릭된 상태가 되었을 때 그 상태를 해제하고 싶을 때 먼저 클릭이 되었는지 확인하는 목적으로 사용됩니다. 클릭도 안했는데 클릭해제를 수행할 필요는 없겠죠.

2. 아두이노 키보드 제어 회로도


  • 준비물 : 스위치버턴 5개, 아두이노 마이크로
  • 내용 : 스위치버턴을 아두이노 마이크로 2,3,4,5,6번핀에 순서대로 연결하시오.
  • 참고 : [아두이노] 아두이노 키보드 제어 회로도


지난 시간의 회로도를 그대로 적용합니다.

3. 코딩


스위치 버턴은 5개 입니다. 실험에서 2번 핀은 인터럽트 핀으로 사용하여 안전장치를 마련하고 나머지 3,4,5,6번 핀은 마우스 위치를 조절하는 핀으로 사용하겠습니다. 아쉬운 점은 스위치 버턴이 더 없어서 마우스클릭 이벤트까지는 적용을 못하였네요. 인터럽트 핀을 마우스 클릭 이벤트로 사용하면 좋은데 혹시 모를 에러를 예방하는 차원으로 안전장치가 필요하기 때문에 마우스 클릭 이벤트는 실험하지 않겠습니다.

1) 키보드 안전장치


지난 시간의 소스를 그대로 가져 왔네요. 복습차원으로 다시 봐 주시기 바랍니다.
[기본소스]

const byte interruptPin = 2;
boolean state = true;

void setup() {   
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), exchange, FALLING);  
}
void loop(){
  if(state==false){
    
    키보드 명령;
    
    }
}
void exchange() {
 state=!state;
}

위 코딩의 설명은 지난 시간 post를 보시기 바랍니다.

2) 마우스 이동 실험


  • Mouse.move(x, y, 휠) 함수로 마우스를 직접 움직이는 실험을 해 보겠습니다.

핀번호을 선언 합니다.

const byte Pin_Up = 3;
const byte Pin_Down = 4;
const byte Pin_Left = 5;
const byte Pin_Right = 6;

스위치 버턴 모두 내부풀업모드 방식을 사용하니깐 pinMode()은 다음과 같이 INPUT_PULLUP 모드로 선언 합니다.

 pinMode(Pin_Up, INPUT_PULLUP); 
 pinMode(Pin_Down, INPUT_PULLUP);
 pinMode(Pin_Left, INPUT_PULLUP);
 pinMode(Pin_Right, INPUT_PULLUP);

Pin_Up키 누름 이벤트 명령은 다음과 같습니다. 내부풀업모드로 초기상태가 HIGH 입니다. 그래서 스위치를 누르면 LOW로 바뀌게 되고 IF문이 참이 되어 키 누름과 해제 명령을 수행하게 됩니다.

 if(digitalRead(Pin_A) == LOW){
    Mouse.move(0, -1, 0);
 }

나머지 스위치 버턴도 위와 같이 동일하게 코딩하면 됩니다.

3) 종합소스


위 안전장치 코딩과 키 누름 코딩을 합쳐서 종합해 보면 아래와 같이 코딩을 할 수 있습니다.

#include <Mouse.h>

const byte Pin_Up = 3;
const byte Pin_Down = 4;
const byte Pin_Left = 5;
const byte Pin_Right = 6;

const byte interruptPin = 2;
boolean state = true;

void setup() {    
  pinMode(Pin_Up, INPUT_PULLUP); 
  pinMode(Pin_Down, INPUT_PULLUP);
  pinMode(Pin_Left, INPUT_PULLUP);
  pinMode(Pin_Right, INPUT_PULLUP);

  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), exchange, FALLING);  

   Mouse.begin();
}

void loop() {
  if(state==true){
    if(digitalRead(Pin_Up) == LOW){ //위로
       Mouse.move(0, -1, 0);
    }else if(digitalRead(Pin_Down) == LOW){ //아래로
       Mouse.move(0, 1, 0);
    }
    if(digitalRead(Pin_Left) == LOW){ //왼쪽
       Mouse.move(-1, 0, 0);
    }else if(digitalRead(Pin_Right) == LOW){ //오른쪽
       Mouse.move(1, 0, 0);
    }   
  } 
}
void exchange() {
 state=!state;
}

스위치 버턴을 누름으로써 마우스의 해당 방향으로 움직이게 됩니다.

여기서, if문의 표현을 잘 봐주세요.

if문이 위/아래를 한쌍으로 묶었고 좌/우를 한쌍으로 묶었습니다. 왜 이렇게 했을까요. 바로 위를 누른 상태에서 아래를 누를 수 없고 좌를 누른 상태에서 우를 누를 수 없잖아요. 즉, 위/아래는 하나의 상태만 존재하고 좌/우는 하나의 상태만이 존재하기 때문에 위와 같이 IF 조건문으로 표현한 것이죠.

주의할점은, 4개의 상태를 if문으로 4개를 개별적으로 만들면 안됩니다.

예)

 if(digitalRead(Pin_Up) == LOW) {  }
 if(digitalRead(Pin_Down) == LOW) {  }

이렇게 코딩하면 안됩니다. 버턴을 동시에 누른다면 어떤 현상이 발생할까요. 두가지 상태를 모두 수행하기 때문에 어떤 의미로는 충돌에 가깝다고 보시면 됩니다. 그렇다고 해서 위 코딩이 동작하지 않는 것은 아닙니다. 의미상으로 코딩의 문제가 있는 것이죠. 어느시점에 오로지 딱 하나의 조건만이 있어야지 위/아래가 동시에 일어나는 것은 좀 문제가 있겠죠.

그리고, 위/아래의 하나의 상태와 좌/우의 하나의 상태는 동시에 일어날 수 있기 때문에 if문으로 분리해 줘야 합니다.

왜! 위에서 IF문을 저렇게 표현했는지에 대한 의미를 정확히 이해해 주세요.

이 코딩은 단지 동작을 테스트 할 목적의 코딩이기 때문에 복잡한 동작 명령은 생략합니다.

4. 결과



스위치버턴은 말풍선의 순서대로 해당 키보드 키명령을 가지고 있습니다. 해당 스위치 버턴을 해당 명령을 PC에서 수행합니다.

결과는 아래 동영상에서 확인하시면 됩니다.


영상을 보시면 처음 업로드 키를 눌러야 하는데 컴파일 키가 눌러졌네요. 이미 해당 코딩이 업로드 된 상태입니다. 업로드 부분부터 촬영을 하려고 하다 보니깐 실수가 발생했네요. 업로드가 이미 된 상태이다 보니깐 업로드 버턴이 아닌 컴파일 버턴을 누르고 영상을 계속 진행시켜 버렸네요. 재촬영하기 귀찮아서 그냥 올렸네요. 감안하시고 보세요. 참고로 한손에는 폰이 한손에는 마우스조정기가 있다 보니깐 대각선 움직임을 제대로 보여드리지 못했네요. 위/아래, 좌/우로만 움직였는데 실제로 조정하면 대각선으로도 움직입니다.

마무리


간단히 마우스 이동만 시켰네요. 키 누름 이벤트까지 3개를 만들고, 마우스 휠을 움직이는 명령까지 수행하게 했다면 완벽한 마우스가 완성되었겠죠. 약간 아쉬운 실험이 되었네요.

Mouse 라이브러리를 이용하니깐 Mouse.move()함수로 쉽게 PC 마우스를 움직일 수 있게 되었습니다. 이처럼 아두이노는 오픈소스로 많은 것들을 제공해주고 우리들은 제공된 라이브러리를 이용하여 쉽게 아두이노를 제어할 수 있습니다. 여러분들에게 필요한 것은 단지 뭘 만들고 싶은가의 상상만 필요할 뿐이죠.

여러분들은 지난시간에 배운 키보드 제어와 오늘 배운 마우스 제어를 통해 뭘 만들고 싶으신가요. 한번 상상의 나래를 펼쳐 보세요.


댓글()