프로젝트

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

마우스를 사용하여 서보모터에 달린 웹캠 제어하기

2014-09-03 15:04:22

개요

개요

마우스를 사용하여 서보모터에 달린 웹캠을 제어해 보자.


얼굴을 이용하여 웹캠을 움직이는 프로젝트처럼 OpenCV라이브러리와 프로세싱을 사용하여 구현한다.
얼굴 추적 카메라 프로젝트를 만들었다면 이번 프로젝트는 그 프로젝트를 기반으로 쉽게 완성할 수 있다.
프로세싱을 사용하면 쉽게 마우스의 좌표를 받아와서 서보모터를 제어할 수 있다.





얼굴로 제어하는 것과 달리 마우스 커서를 자신이 보고 싶은 위치로 움직이면 서보모터가 움직여 그 쪽을 볼 수 있다.

웹캠을 무선으로 사용한다면 아두이노를 블루투스로 제어하여 원격으로 웹캠을 제어하여 그 주위를 볼 수 있는 CCTV와 같은 시스템을 구축할 수도 있다.


동영상




필요한 사전 지식

서보모터
Processing
시리얼 통신


부품 목록

NO 부품명 수량 상세정보
1 아두이노 보드 1 UNO, Mega2560, MegaADK
2 브레드 보드 1  
3 서보 모터 2  
4 웹캠 1  
5 케이블 6~10  


부품명 아두이노 보드 브레드 보드 서보 모터 2개 웹캠 케이블
부품 사진

하드웨어 making

브레드보드


전자회로도






서보모터끼리 연결할 때는 사진과 같이 하나는 수평으로 움직이게(아래쪽), 하나는 수직으로 움직이게(위쪽)연결해 준다.
서보모터끼리 연결할 수 있는 프레임이 존재한다면 쉽게 연결할 수 있다.



소프트웨어 coding

프로세싱

import processing.serial.*;

// Combining GSVideo capture with the OpenCV library for face detection
// http://ubaa.net/shared/processing/opencv/
import hypermedia.video.*;
import java.awt.Rectangle;
import codeanticode.gsvideo.*;

OpenCV opencv;
GSCapture cam;
//서보모터를 구분하는 값
char verticalSignal = 1;
char horizonSignal = 0;

//시리얼을 초기화하고 초기각도를 90도로 지정 Serial myport; int x = 90; int y = 90; void setup(){
//창의 크기와 캠 영상크기를 (640x480)로 지정 size(640, 480); cam = new GSCapture(this, 640, 480); cam.start(); opencv = new OpenCV(this); opencv.allocate(640,480);
//시리얼 통신 초기화 myport = new Serial(this,Serial.list()[0],9600); } void captureEvent(GSCapture c) { c.read(); } public void stop() { opencv.stop(); super.stop(); } void draw(){ opencv.copy(cam); opencv.convert(GRAY); image(cam, 0, 0); //창크기 640x480을 180도로 맞추기 위해 나누기3과 나누기2를 각각 해준다 print("mouseX = "); println(mouseX/3); print("mouseY = "); println(mouseY/2); x = mouseX/3; y = mouseY/2; //시리얼통신을 통해 각도값 전송 myport.write(horizonSignal); myport.write(x); myport.write(verticalSignal); myport.write(y); delay(1); }
프로세싱에서는 현재 마우스커서의 좌표를 시리얼 통신을 통해 아두이노로 전송한다.
마우스의 좌표는 프로세싱내에서 mouseX, mouseY를 쓰게되면 쉽게 현재 커서의 좌표를 알아낼 수 있다.

마우스의 좌표는 실행창 안에 커서가 존재할 때만 읽어올 수 있으며,
창의 크기가 640x480이기 때문에 최대로 구할 수 있는 마우스 좌표 또한 (640, 480)이다. 이 때 좌표위치는 곧 서보모터의 각도값이 되는데 서보모터는 0부터 180도까지 움직이기 떄문에 640과 480을 180도로 맞춰주어야 한다. 그래야 창의 끝에서 반대쪽 끝으로 움직일때 0부터 180도 까지 움직이게 된다.
//창크기 640x480을 180도로 맞추기 위해 나누기3과 나누기2를 각각 해준다
  print("mouseX = ");
  println(mouseX/3);
  print("mouseY = ");
  println(mouseY/2);
  
  x = mouseX/3;
  y = mouseY/2;
비슷하게 맞춰주기 위해 640을 3으로 나누어서 180부근으로 맞추고 480을 2로 나누어서 180와 비슷하게 맞춘다.(소수점으로 나누어서 180으로 딱 떨어지지 않게 하는 이유는 각 마우스좌표(mouseX와 mouseY)의 데이터형과 소수점으로 나누었을때의 데이터형이 불일치 하기 때문에 오류가 뜬다.)

이렇게 구한 값을 시리얼통신을 통해 아두이노로 전송한다. 
myport.write(horizonSignal);      
  myport.write(x); 
  myport.write(verticalSignal);        
  myport.write(y);  
  delay(1);   
수직모터에 보내는 값과 수평모터에 보내는 값을 구별하기 위해 신호값을 먼저 보내 어느모터에 보내는 값인지 알리고 보내게 된다.
1을 보내고 다음에 오는 값을 수직으로 움직이는 서보모터의 각도값이고, 0을 보내고 그 다음에 오는 값은 수평으로 움직이는 서보모터의 각도값이 된다.
delay(1)은 쉴틈없이 프로그램이 돌게 되면 오류가 발생할 수 있기 때문에 프로그램의 안정성을 위해 약간의 텀을 준다. 


스케치

#include <Servo.h>   // 서보 라이브러리 사용

int x ;
int y ;

char verticalSignal=1, horizonSignal=0;
char serialChar=0;

Servo servoA;   // 서보 선언
Servo servoB;   // 서보 선언

void setup(){
  Serial.begin(9600);   //시리얼 통신 시작
  servoA.attach(10);    // 서보 신호핀 10번
  servoB.attach(9);    // 서보 신호핀 10번
  servoA.write(90);
  servoB.write(90);
}

void loop(){  
  while(Serial.available() <=0);  
  serialChar = Serial.read();    
  if(serialChar == horizonSignal){  
    while(Serial.available() <=0); 
    x = Serial.read();
    servoA.write(x);  
  }
  else if(serialChar == verticalSignal){ 
    while(Serial.available() <= 0);  
    y=Serial.read();
    servoB.write(y);  
  }
}
소스를 보면 얼굴을 인식하여 추적하는 카메라와 비슷하다.
아두이노에서는 프로세싱에서 전송한 값을 서보모터에게 보내는 역할만 하기 때문에 서보모터를 구분하는 신호값을 읽고 0이 왔을 경우 수평으로 움직이는 서보모터에게 각도값을 전송하고 1이 왔을 경우에는 수직으로 움직이는 서보모터에게 각도값을 전송하는 역할을 하게 된다.

수박쨈

아두이노, 서보모터, 프로세싱, 웹캠, OpenCV