이번엔 기상측정기구와 이더넷 쉴드가 장착된 아두이노(Arduino)로 기상관측 자료를 트위터(Twitter)에 자동으로 올려주는 기특한 녀석을 소개시켜 드리겠습니다. 제법 시스템이라 불릴 만한 구성입니다.  바람의 방향과 속도 및 강수량을 측정할 수 있는 기상관측 기구로 부터 측정된 값을 모니터링하고 이를 곧바로 인터넷을 통해 트위터(twitter)에 올리는 것입니다.  기상 데이타 측정용으로 사용된

가상 관측기기에 대해선 관련글 링크

를 참고하시기 바랍니다.

본 글을 이해하기위해 필요한 사전지식:  기본적인 아두이노 스케치 개발환경 사용법, 라이브러리 설치법, 이더넷쉴드 사용경험, 트위터의 기본적인 이해, 기상관측 기구 센싱방법 등


트위터?
트위터(Twitter)가 뭔지는 저보다 여러분이 더 잘 알고 계실것 같습니다.  제경우 트위터 사용법도 잘 모릅니다만 순서가 뒤바껴서 트위터 포스팅해주는 로봇을 먼저 만들게 되었습니다;;;   이글을 이해하시려면 일단 트위터에 가입하셔서 트위(Tweet) 하나를 올려보시면 됩니다.

아두이노 + 이더넷 쉴드
썰렁한 아두이노(Arduino) 보드에 이더넷 쉴드를 얹으면 인터넷을 통해 전세계와 의사소통이 가능합니다. 더불어 천재적이면서 친절하기까지 하신 분들이 아두이노로 트위터에 메시지를 보내는 예제와 라이브러리를 공개해 주셨으므로 저와 여러분들은 손쉽게 엄청난?;; 시스템 구현을 할 수 있는 상황입니다.  이더넷 쉴드 사용 경험이 없으신 분들은 우선 공개된 정보와 아두이노 스케치IDE에 포한된 기본 예제를 참고하시기 바랍니다.


아두이노 + 이더넷 쉴드의 한계
이더넷 쉴드를 장착하면 아두이노 보드로 정보서비스를 제공해주는 서버 역활을 할 수 있습니다.  외부 접속이 가능한 IP주소를 사용한다면 전세계의 인터넷 접속가능 기기를 통해 정보를 제공받을 수 있습니다.  하지만 동시 접속수 제한이나 퍼포먼스 문제로 원할한 서비스 제공에는 한계가 있습니다. 이때문에 아두이노를 데이타 센싱이 용이한 현장에 설치 후 취합한 데이타를 웹서비스를 담당하는 PC급 서버로 전달하여 제대로된 웹서비스 환경에 응용하는 것이 더 안정적인 방법일 수 있습니다.

이때 손쉽게 사용가능한 서비스가 HTTP Client입니다. 즉, 아두이노는 웹클라이언트로써 웹서버에 필요할 때만 접속하여 데이타를 송/수신 하는 방식입니다.    이더넷 라이브러리와 함께 제공되는 기본예제(WebClient)를 조금만 수정하면 활용이 가능합니다.  IP주소로 접속이 가능한 웹서버가 있는경우 추천할만한 방법입니다.  다만 문제는 기본 이더넷 쉴드 라이브러리를 이용한 Web Client 로는 domain name ( http://robobob.co.kr 같은) 을 통한 서버 접속이 안되고  123.123.123.123  같은 숫자형식의 ip를 이용한 접속만 가능하다는 점입니다.  예전에는 ip주로를 통한 접속 주소를 지원하는 웹호스팅 서비스가 있었지만 요즘엔 이를 지원하지 않는곳이 대부분인것 같습니다. 때문에 특정 웹호스팅 서비스나 단독 호스팅서비스를 사용하지 않으면 Web Client 사용한 접속이 불가한 상황입니다.  (일반적인 URL 주소를 통한 아두이노의 HTTP Client 접속 방법을 아시는 분은 안내 부탁드립니다.)

트위터 활용
HTTP Client 활용에 문제가 있으나 오히려 더 효과적일 수 있는 데이타 공유 방법이 있으니 바로 트위터입니다. 짧은 단문을 포스팅하면 수많은 팔로워에게 전달되는 효과적인 데이타 공유시스템을 활용하는 것입니다. 게다가 요즘 대세인 스마트폰에서도 손쉽게 접근이 가능한 최신병기입니다. 그런데 방법이 어렵냐고요???  제가 해보니 생각보다 매우 간단했습니다.   트위터 엡 개발을 위해 API니 뭐니 습득하고 복잡한 절차가 필요한지 알았는데요, 그게 아니고 그냥 사용만 하면 되네요...


트위터 포스팅 방법
방법은 요 사이트에 잘 요약되어있습니다.

http://arduino-tweet.appspot.com/

별 설명이 필요없습니다만, 정리하자면 아래와 같습니다.
1. 트위터 앱(O Auth)에 접속하여 승인을 해주면 복잡한 문자열로 된 토큰 정보가 생성됩니다. 이 값을 복사하여 잘 보관합니다.
2. 관련 라이브러리들을 설치해줍니다. 두군데 정도 접속하여 파일을 받아서 아두이노 library 폴더에 적절한 이름으로 복사합니다.
3. 예제소스를 실행해봅니다.
   위 라이브러리를 제대로 설치하면 스케치 IDE  Examples 리스트에 Twitter가 생깁니다.
   File menu > Examples > Twitter > SimplePost 예제를 선택해줍니다.

이더넷 쉴드 사용시 수정해주는  ip주소와 네트웍정보 몇개만 수정해주시고 추가로  "YOUR-TOKEN-HERE" 부분을  위에서 발급받은 토큰값으로 대체해 주면 준비 끝~ 입니다.
이젠 잘 전송되는지 확인을 위해 시리얼 모니터링 창을 열고 속도(9600)를 맞쳐줍니다.

SimplePost 예제 소스 내용보기

#if defined(ARDUINO) && ARDUINO > 18   // Arduino 0019 or later
#include <SPI.h>
#endif
#include <Ethernet.h>
#include <EthernetDNS.h>
#include <Twitter.h>

// Ethernet Shield Settings
// 쉴드 밑면에 있는 mac 정보를 적어줍니다. 쉴드가 하나인경우 안바꿔도 무방
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 


// substitute an address on your own network here
byte ip[] = { 192, 168, 2, 250 };   //공유기에서 사용되지않는 IP값을 지정

// Your Token to Tweet (get it from http://arduino-tweet.appspot.com/)
Twitter twitter("YOUR-TOKEN-HERE");   // 발급받은 토큰값을 이곳에 붙여넣으세요

// Message to post
char msg[] = "Hello, World! I'm Arduino!";   // 한글 전송도 가능합니다!

void setup()
{
  delay(1000);
  Ethernet.begin(mac, ip);
  Serial.begin(9600);
 
  Serial.println("connecting ...");
//부팅시 1회 포스팅 시도합니다.
  if (twitter.post(msg)) {
    // Specify &Serial to output received response to Serial.
    // If no output is required, you can just omit the argument, e.g.
    // int status = twitter.wait();
    int status = twitter.wait(&Serial);
    if (status == 200) {
      Serial.println("OK.");
    } else {
      Serial.print("failed : code ");
      Serial.println(status);
    }
  } else {
    Serial.println("connection failed.");
  }
}

void loop()
{ //아무것도 안합니다. 
}

SimplePost 예제 소개
예제로 사용된 소스에는 아두이노가 부팅할때마다 1회 포스팅을 하고, 포스팅 될때마다 결과 상태를 시리얼 통신으로 전달해 줍니다. (참고로 시리얼 창 새로 열거나 통신속도를 변경하여도 아두이노가 재부팅이되어 새로 포스팅을 시도합니다.)
결과가 Okay로 뜬다면 잠시 후 여러분의 트위터 페이지에 새 트윗이 올라온것이 보일 겁니다.
Okay 외의 오류 메시지를 잘 살펴보시면 디버깅에 도움이 됩니다.

포스팅 시도후 오류메시지가 뜨는 경우가 종종 있는데요  제가 발견한 주요 오류 내용은 아래와 같습니다.
1. 동일한 내용을 중복하여 전송한 경우: 이경우 중복 전송된 값은 무시됩니다.
2. 트윗 작성 한계치 초과 :  시스템 보호를 위해 일정 시간당 한정된 개수의 트윗만 허용됩니다.   이 수량을 초과시 일정기간 동안 트위 작성이 불가하며 일정 시간이 지난뒤에 다시 작성이 가능해집니다.   가령  수십초에 한번씩 계속 트윗을 하신다면 얼마지나지 않아 트윗 등록이 거부될 겁니다.   아래의 예제에서는 1시간에 1회 트윗을 발신하게됩니다.




드디어 트위터 기상로봇

이제 포스팅될 정보를 여러분의 용도에 맞게 잘 구성해주시면 여러분만의 활용도 만빵인 트위터 포스팅 봇이 완성됩니다.
제 경우 이미 소개드렸었던 기상측정기기를 활용하여 1시간마다 기상데이타를 측정하여 전송해주는 예제를 만들어봤습니다.
실제 포스팅된 내용들을 아래의 페이지에서 확인 가능합니다.

로보밥 기상측정 로봇 트위터 메시지 보러가기 :  

http://twitter.com/artrobot_bot1

한동안 실내 테스트만 하다가 2012년 1월 29일 현재,  옥외 설치하여 운영중입니다.  위 링크에 가보시면 실제 기상자료를 참고하실 수 있습니다. (경기도 수원시 오목천동)

위에서 트윗된 메시지의 포스팅 시간을 보시면 (오차가 1분도 안되네요^^.)1시간 간격으로 전송이 된것을 보실 수 있습니다. 하지만 가끔씩  몇 시간에 한번만 트윗된 것도 보이실 겁니다. 이때는 테스트를 위해 실내에서 측정된 풍량/풍속/강수량 수치의 변화가 없어서 동일한 내용을 반복 포스팅한것으로 인지되어 무시된 경우입니다.  (계속 변화하는 시간값이나 랜덤숫자를 함께 전송하시면 이문제가 해결됩니다.)

사진. 기상측정 기구

+

사진. 아두이노로 만든 트위터 포스팅해주는 로봇

사용된 예제 소스 소개
값의 정밀도나 완성도를 무시하고 필요하신 분들에게 참고가 될 수 있도록 예제소스를 공개합니다.  풍향, 풍속, 강수량의 측정치 산정의 기준은 기상측정기기 제조사에서 제공한 데이타 시트를 참고하여 계산된 값입니다. 센서 연결 방법 및 기본 사용법 소개는 관련글 링크에 있는 글을 참고하시기 바랍니다.


/*
* 풍향, 풍속, 강수량을 Twitter에 포스팅하는 예제
  수정일시:  (2011.09.08a)  디버깅 및 기능개선을 위해 수시로 변경될 수 있습니다.

 풍향: 포스팅시 1회 계산 (16방위 중 하나로 측정)
 풍속: 20ms 주기로 10초간 모니터링 후 풍속계산
 강수량: 20ms 주기로 모니터링하여 1시간동안 누적(1시간에 1회 공식 데이타로 사용)
 
 핀연결
 풍향계: A0   풍향센서 전선 2개 중 하나는 GND에 나머지선은 A0에 연결 및 10k저항 거쳐 5V에 연결
 풍속계: D2   풍속센서 전선 2개 중 하나는 D2에 나머지는 GND
 강수계: D3   강수센서 전선 2개 중 하나는 D3에 나머지는 GND

 기타 핀 연결 (없어도 무방)
 D7: 풍속계 상태 LED
 D8: 강수량계 상태 LED
 D9: 버튼 ( 버튼을 누르면 10초내로 즉시 포스팅)

* http://ArtRobot.co.kr
* http://RoboBob.co.kr
*/

#include <SPI.h>
#include <Ethernet.h>
#include <EthernetDNS.h>
#include <Twitter.h>
#include <stdio.h>

#define WIND_N    0
#define WIND_NNE  22.5
#define WIND_NE    45
#define WIND_ENE  67.5
#define WIND_E    90
#define WIND_ESE  112.5
#define WIND_SE    135
#define WIND_SSE  157.5
#define WIND_S    180
#define WIND_SSW  202.5
#define WIND_SW   225
#define WIND_WSW  247.5
#define WIND_W    270
#define WIND_WNW  292.5
#define WIND_NW   315
#define WIND_NNW  337.5

// Ethernet Shield Settings
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //바꿔주세요

// substitute an address on your own network here
byte ip[] = { 192, 168, 100, 55 }; //바꿔주세요

// Your Token to Tweet (get it from http://arduino-tweet.appspot.com/)
Twitter twitter("발급받으신 토큰값을 적어주세요");  //바꿔주세요

// Message to post
char msg[100] = "";

const int windVanePin = A0;  // 풍량계 센서 입력핀
int windVaneValue = 0;        //
float windSpeed = 0;
float rainGauge = 0;
float windDirection = 0;
char windName[4];  // N (North)  S South,   NS(north south)   NNS(north north south) etc

  unsigned long windSpeedTimer;
  int windSpeedState = true;
  int windSpeedPin = 2;
  int windSpeedCounter = 0;
  unsigned long rainGaugeTimer;
  int rainGaugeState = true;
  int rainGaugePin = 3;
  int rainGaugeCounter = 0;
  int buttonState = true;
  int buttonPin = 9;
  int postTrigger = false;
  int postingCounter = 0;

void setup()
{
  delay(1000);
  Ethernet.begin(mac, ip);
  Serial.begin(9600);
 
  //wind speed sensor
  pinMode(windSpeedPin, INPUT);
  digitalWrite( windSpeedPin, HIGH);
 
  //rain gauge sensor
  pinMode(rainGaugePin, INPUT);
  digitalWrite( rainGaugePin, HIGH);

  //button for postMessge
  pinMode(buttonPin, INPUT);
  digitalWrite(buttonPin, HIGH);
 
  //wind speed sensor status LED
  pinMode(7, OUTPUT);
  digitalWrite(8,HIGH);
 
  //rain gauge status LED
  pinMode(8, OUTPUT);
  digitalWrite(8,HIGH);
 
}

// 문자배열변수값을 시리얼로 확인할경우만 사용
void printChars(char *msg, int len){
  if(len == 0) return;
  for(int i=0; i<len ; i++)
    Serial.print( msg[i]);
  Serial.println();
}

// sprintf함수에서 float형 print문제 대체용 함수 , float의 정수부인쇄
int f2h( float num){
  return int(num);
}

// sprintf함수에서 float형 print문제 대체용 함수 , float의 소수부인쇄
int f2p( float num){
  return (num - int(num)) * 100;
}


void loop()
{
  // 10초마다 샘플링 반복
  windSpeedTimer = millis() + 10000;
  windSpeedCounter = 0;
  while( millis() < windSpeedTimer ){
    delay(20); // 20ms 주기로 버튼이나 센서 스위칭 감시
    //wind speed
    if( (windSpeedState == true ) && !digitalRead( windSpeedPin) ){
        windSpeedCounter++;
        windSpeedState = false;
    }else if( (windSpeedState == false) && digitalRead(windSpeedPin) ){
        windSpeedState = true;
    }   
    //rain gauge
    if( (rainGaugeState == true ) && !digitalRead( rainGaugePin) ){
        rainGaugeCounter++;
        rainGaugeState = false;
    }else if( (rainGaugeState == false) && digitalRead(rainGaugePin) ){
        rainGaugeState = true;
    }       
   
    //button
    if( (buttonState == true ) && !digitalRead( buttonPin) ){
        postTrigger = true;
        buttonState = false;
    }else if( (buttonState == false) && digitalRead(buttonPin) ){
        buttonState = true;
    }      
    digitalWrite(7, windSpeedState);  
    digitalWrite(8, rainGaugeState);      
  }

  windSpeed = windSpeedCounter * 0.24;   // 1초당 1회 스위칭시 2.4km/h
  //Serial.print( "winSpeed: ");
  //Serial.println( windSpeed);

  rainGaugeTimer++;
  if( rainGaugeTimer > 360){  //1시간( 10 * 360 sec) 마다 postTrigger On
    rainGauge = rainGaugeCounter * 0.2794;
    rainGaugeCounter = 0;

    rainGaugeTimer = 0;
    postTrigger = true;
  }
  getWindDirection(); 

// 1시간마다 or 버튼이 눌릴때마다 Trigger 가 true가 되고 이때 포스팅된다.
  if( postTrigger ){ //post Message
    postTrigger = false;
    sprintf( msg, "[%d]기상측정로봇: 풍향:%s/%d.%d 풍속:%d.%d(km/h) 1시간당 강수량 %d.%d(mm/h).",postingCounter++ , windName, f2h(windDirection), f2p(windDirection), f2h(windSpeed), f2p(windSpeed),  f2h(rainGauge), f2p(rainGauge) );

    printChars( msg, sizeof(msg) );  //시리얼창으로 확인용, 생략가능
    postMessage();
  }

}

void postMessage(){
  Serial.println("connecting ...");
  if (twitter.post(msg)) {
    // Specify &Serial to output received response to Serial.
    // If no output is required, you can just omit the argument, e.g.
    // int status = twitter.wait();
    int status = twitter.wait(&Serial);
    if (status == 200) {
      Serial.println("OK.");
    } else {
      Serial.print("failed : code ");
      Serial.println(status);
    }
  } else {
    Serial.println("connection failed.");
  }
}

float getWindDirection(void){
 // 풍향센서의 출력 전압을 아날로그 센서로 읽어옴
  int readValue = analogRead(windVanePin);           
  // ADC입력치를 0~5V 범위로 변환, 데이타시트 값과 대응이 쉽도록.
  windVaneValue = map(readValue, 0, 1023, 0, 500); 
 
  // 해당 전압치에 따라 16가지 방향 중 하나의 풍향을 결정
  if( windVaneValue < 35){
    // DIR5  112.5  0.32v (31 32)    0~35
    windDirection = WIND_ESE;
    strcpy(windName ,"ESE");       
  }else if( windVaneValue < 43 ){
    // DIR3  67.5  0.41v(40 41)    ~42   
    windDirection = WIND_ENE;
    strcpy(windName , "ENE");       
  }else if( windVaneValue < 50 ){
    // DIR4  90  0.45v(44 45)      ~50   
    windDirection = WIND_E;
    strcpy(windName , "E");       
  }else if( windVaneValue < 70 ){
    // DIR7  157.5  0.62v(60 62)   ~70
    windDirection = WIND_SSE;
    strcpy(windName , "SSE");       
  }else if( windVaneValue < 100 ){
    // DIR6  135  0.90v(89 90)      ~100
    windDirection = WIND_SE; 
    strcpy(windName , "SE");       
  }else if( windVaneValue < 130 ){
    // DIR9  202.5  1.19v(119 120)  ~130
    windDirection = WIND_SSW; 
    strcpy(windName , "SSW");       
  }else if( windVaneValue < 170 ){
    // DIR8  180  1.40v(140 141)   ~170
    windDirection = WIND_S; 
    strcpy(windName , "S");       
  }else if( windVaneValue < 210 ){
    // DIR1  22.5  1.98v(198 199)  ~210
    windDirection = WIND_NNE; 
    strcpy(windName , "NNE");           
  }else if( windVaneValue < 250 ){
    // DIR2  45  2.25v(226 227)    ~250
    windDirection = WIND_NE; 
    strcpy(windName , "NE");           
  }else if( windVaneValue < 300 ){
    // DIR11 247.5  2.93v(293 294)  ~300
    windDirection = WIND_WSW; 
    strcpy(windName , "WSW");       
  }else if( windVaneValue < 320 ){
    // DIR10 225  3.08v(308 310)   ~320
    windDirection = WIND_SW; 
    strcpy(windName , "SW");       
  }else if( windVaneValue < 360 ){
    // DIR15 337.5  3.43 (343 345)  ~360
    windDirection = WIND_NNW; 
    strcpy(windName , "NNW");       
  }else if( windVaneValue < 395 ){
    // DIR0  0  3.84v(384~385)    ~395
    windDirection = WIND_N; 
    strcpy(windName , "N");
  }else if( windVaneValue < 415 ){
    // DIR13 292.5  4.04v(405 406)  ~415
    windDirection = WIND_WNW; 
    strcpy(windName , "WNW");   
  }else if( windVaneValue < 450 ){
    // DIR14 315  4.34(433 434)  ~450
    windDirection = WIND_NW; 
    strcpy(windName , "NW");       
  }else if( windVaneValue < 490 ){
    // DIR12 270  4.62v(461 463)    ~490
    windDirection = WIND_W; 
    strcpy(windName , "W");       
  }else{
   //error  알수없는 값범위
  }

}





관련제품
아두이노 (Arduino)
표준 아두이노 이더넷 쉴드
이더넷 일체형 아두이노
기상측정용 기구

관련글 링크

  • 기상측정 기구 + 아두이노로 기상대 만들어요 (Arduino + Weather Sensor Assembly )
  • 트위터(Twitter)에 자동 포스팅하는 기상관측 로봇 (현재글)
  • 기상측정 트위터 로봇 - 실외 설치편
  • 이더넷쉴드 관련   링크1   링크2

추가사항 (2011.11.29)
아두이노와 이더넷 쉴드를 하나로 결합한 Ethernet Pro 보드로 기상측정 트위터 기능을 구현할 수도 있습니다. 특히 PoE 케이블을 이용하시면 전원과 이더넷케이블을 하나로 줄일 수 있어 더욱편리합니다. 가령 위의 시스템을 아래의 이미지와 같이 간소화 시킬 수 있습니다.

아두이노와 전자회로를 배울때 가장 먼저 해보는것이 LED ON/OFF 제어인데요, LED 대신 IRED(적외선 LED)를 장착하고  마치 모르스 부호같이 규칙에 맞쳐 ON/OFF를 해주면 복잡한 데이타도 송수신이 가능합니다.  여러분이 매일 사용하고 계신 TV같은 가전기기가 바로 이렇게 눈에 보이지 않는 빛을 통해 제어되고 있습니다.  이 기술을 잘 활용하면 여러분의 아두이노로 리모콘을 대체하거나 반대로 리모콘 명령에 따라 동작하는 아두이노 기기의 제작이 가능합니다.

본 글을 통해 아래의 적외선 송수신 기본회로를 소개해 드리고 실제로 리모콘으로 조정되는 로봇을 아두이노로 제어하는 방법도 안내해 드리겠습니다

1. 초간단 적외선 송신 회로
2. 고출력 적외선 송신 회로 ( 5미터 이상의 장거리? 전송가능)
3. 리모컨 신호 수신 회로



1. 초간단 적외선 송신 회로

그림1.의 회로를 보시면 바로 아시겠죠?  네,  일반적인 LED를 켤때 사용하는 회로와 동일하게 연결하면 됩니다.  차이점이라면 보통 IRED는 대부분의 LED보다 좀더 저 전압에서 구동된다는 점입니다.  따라서 일반 LED보다는 조금더 큰 저항을 사용하면 됩니다.  저항값이 작으면 좀더 IRED를 밝게 켤 수 있지만 대신 IRED와 아두이노에 무리가 갈 수 있으므로 적당한 저항값을 선정해주시면 됩니다. 하지만 정답은 없습니다.   예제에서는 560옴 저항을 사용하였습니다. 

예제에 사용된 IRED 규격:   정격 1.36V ,  최대 1.7V,  피크주파수 940nm, 화각+-20도

5V 전압을 가할 경우,  I= V/R 공식을 참고하시면  약, 9mA 전류가 흐를 수 있음을 계산으로 예상할 수 있습니다.
아두이노의 경우 핀 한개에서 출력할 수 있는 전류허용량은 20mA에 불과합니다.  초간단 회로로 광신호 도달 거리가 짧을 경우 그림2. 와 같은 고출력 전송회로를 사용하면 됩니다.  위 예제에선 아두이노 디지탈3번 핀을 통해 ON/OFF 제어를 하게됩니다. 참고로, 디지탈 3번핀은 PWM 출력을 지원해주는 핀중 하나입니다.



2. 고출력 적외선 송신 회로

본 회로는 보통의 가전기기 제어용 리모콘에서 사용되는 회로입니다. 수십에서 수백 mA의 고출력 송신이 가능하므로 비교적 원거리(5미터 이상)로 광신호를 전송할 수 있습니다. 이를 위해 트랜지스터를 사용하는데요 아두이노에서 저 전류 제어로 ON/OFF를 제어하고 실제로 IRED에 전류공급은 트랜지스터가 담당하여 비교적 큰 전류를 사용할 수 있게 됩니다.
그림2.를 참고하여 회로를 구성하시면 됩니다.  여기서 R1은 330옴  R2는 1옴을 사용하였습니다.  실제로 테스트 해본 결과 방이나 거실 전역에서 방향에 상관없이 신호전달이 되는것을 확인했습니다. 기본 제공되는 리모콘보다 더 고출력인것 같네요;; 
(사실 본 회로에 5V는 조금 과할 수 있습니다.  아두이노와 함께 사용하실 경우 5V 대신 3.3V 전압을 사용하면 좋습니다.)

예제 회로의 경우 일시적으로 매우 큰 전류가 흐르게되지만 매우 짧은 시간동안만 구동되므로 전체적인 전류소모율은 적은 편입니다.  참고로, 상용 리모콘의 경우 미작동중엔 sleep모드로 대기하다가 버튼이 눌리는 순간 깨어나서 IR송신 후 다시 잠에 들게 되므로 건전지 2개로 수개월씩 작동이 가능합니다.  회로도로 잘 이해가 가지 않으신 분들은 아래의 실제 연결된 사진을 참고하시기 바랍니다.

사진1. 고출력 IR 송신회로 실제 구성예

3. 적외선 수신 회로

적외선 송신측 IRED의 피크 주파수와 일치하는 파장의 포토트랜지스터나 포토다이오드를 이용하여 수신부 구현이 가능합니다. 하지만 우리주변엔 다양한 파장의 빛들이 가득차 있으므로 노이즈에 해당하는 빛신호를 차단하고 원하는 광신호만 추출해주는 필터회로가 있어야 실용이 가능해 집니다.  리모콘 수광 모듈은 이를 위한 소자와 필터회로가 일체화된 제품으로 매우 손쉽게 특정 파장 및 주파수의 빛 신호에 반응하는 수신기로 활용할 수 있습니다.

예제에 사용된 적외선 수광모듈 사양:   감응되는 빛의 파장: 940nm ,  빛 신호의 주파수: 38KHz

참고로, 적외선 송신시 사용된 IRED가  850nm 파장의 빛을 출력한다면,   수광모듈도 850nm 용으로 맞쳐줘야 수신률이 높아집니다.  마찬가지로 빛 신호의 캐리어 주파수(가령 38KHz)도 송/수신 모듈이 일치되어야 합니다.
예제에선  940nm 피크 파장의 IRED와  940nm형 수광모듈을 사용하였으며,  캐리어 주파수는 38KHz로 맞췄습니다.


IR 수광 모듈의 연결법도 매우 간단하며 (그림3을 참고) 전원만 공급해주고 VOUT단자로 출력되는 신호를 참고하기만 하면 됩니다. 다만,   전원 입력부에 노이즈가 있어 문제가 되는경우라면 전원 입력부에 저항과 콘덴서를 이용하여 노이즈를 감쇄시켜줘야 합니다.  (보통은 생략이 가능합니다. 필요한 경우 관련자료에서 IR수광모듈 데이타 시트를 참고하시기 바랍니다.)
위 회로에서는 VOUT 출력을 아두이노 디지탈11번 핀에 연결하여 신호를 감지하는 경우를 가정하였습니다.


아두이노로 적외선 신호 송신 및 수신하기 - 프로그래밍 편

위에서 소개해드린 방법으로 하드웨어 준비는 간단히 끝났습니다.
이제는 아두이노로 리모콘 제어 신호를 발신하기 위해선 전송규약에 맞쳐 ON/OFF제어가 필요한데 많은 분들에게 쉽지 않은 과제입니다. 따라서 전용 라이브러리를 활용하시면 좋은데요  공개된 아두이노 라이브러리들을 둘러보시고 적절한것을 선택하시면됩니다. 본 글에선 IR Remote 라는 라이브러리를 참고로 하였습니다. 
IR Remote 라이브러리의 경우  IR 송신을 위해서 D3핀을,  수신을 위해서 D11핀을 기본으로 사용하고 있습니다.


IR Remote 라이브러리로 적외선 리모콘 신호 발신하여 로봇 원격 제어하기

이제는 실제로 리모콘으로 제어되는 로봇을 아두이노로 제어해 보도록 하겠습니다.

제어대상: 원격제어 6족보행 로봇
전송프로토콜: 유사 NEC 코드
전송부 회로:  그림1. 또는 그림2 의 회로 모두 사용 가능

사전준비:
 .IR리모콘으로 조정되는 로봇 준비: 관련글 링크, 
 .IR Remote 라이브러리 설치:  라이브러리 제작자 홈페이지 링크,   라이브러리 다운로드 링크


소스코드 예제:

#include <IRremote.h>

IRsend irsend;

int incomingByte = 0;

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

void loop() {
 
    if (Serial.available() > 0) {
        // read the incoming byte:
        incomingByte = Serial.read();
        // say what you got:
        Serial.print("I received: ");
        Serial.println(incomingByte, DEC);
        Serial.flush();
    }
        switch( incomingByte){
         case 56: //forward
           irsend.sendNEC( 0xc5000000, 8); //전진
           break;
         case 50: //backward
            irsend.sendNEC( 0x45000000, 8); //후진
            break;
         case 52: // turn reft
            irsend.sendNEC( 0x25000000, 8); //좌회전
            break;
         case 54: // turn right
            irsend.sendNEC( 0x85000000, 8); //우회전
            break;
         case 53: //stop 정지 , 아무신호도 안 보내면 정지합니다.
          break;
        }
      delay(500);    // 0.5초를 주기로 반복
}

아두이노에 위 소스를 프로그래밍 하신 뒤 시리얼 모니터 창을 여시고,  send 입력란에 아래의 해당 숫자키를 입력한 뒤 엔터를 입력하여 전송해줍니다.

 전진 8
후진 2
 좌회전 4
 우회전 6
 정지 5 or 기타키 or 그냥 엔터

가령, 전진을 하려면 숫자 8을 누르고 엔터를 쳐주면됩니다. 중지하려면 5번을 누르고 엔터를 치면됩니다.

소스 해석:
시리얼 포트를 통해 값이 전송되면 첫번째 바이트 값을 읽고 이값에 따라 방향제어 변수값을 수정합니다. 또한 이값은 별도의 입력이 없는경우 그대로 유지되므로 매번 순환루프 마다 보관해둔 방향제어 변수값에 따라 리모콘 신호를 발신하게 됩니다.

방향 제어 명령을 유선 시리얼 통신으로 받는 대신, 무선으로 전송 하거나 조이스틱이나 버튼 또는 센서를 이용하여 변화시켜주면 전파를 이용한 로봇제어나 자율이동형 로봇의 제작도 가능합니다.


동영상1. 실행 예제 보기

키보드 숫자를 입력후 엔터를 치면 시리얼통신으로 아두이노에 전송되고 이 값에 따라 적절한 리모콘 신호를 보내어 로봇을 제어하게됩니다.  본래 적외선은 사람 눈으로는 보이지 않지만 대부분의 카메라로는 볼 수 있습니다. 동영상 후반부를 보시면 광신호가 약 0.5초에 한번씩 송출될때 로봇이 움직이고, 신호가 없으면 로봇이 멈추는것을 확인하 실 수 있습니다.

끝으로,
 온갖 가전기기들이 리모콘으로 제어되고 있습니다.  이는 아두이노로 제어할 수 있는 기기들이 많다는 뜻이기도 한데요 여러분은 어떤 기기를 제어해 보시겠습니까?  가령 저렴하게 구입이 가능한 리모컨 제어되는 MP3플레이어로 말하는 로봇 만들기도 가능합니다.  아래의 관련글에서 좀더 세부적인 리모콘 프로토콜 정보도 참고하시기 바랍니다.

즐거운 DIY 생활 보내시길!!


관련 제품 링크

 .무선제어 6족보행 로봇

 .아두이노 UNO

 .적외선 무선통신킷

 

 


기타정보 링크
 .아두이노로 무선제어 6족보행 로봇 제어하기  63
 .말하는 로봇 만들기( 적외선 리모콘 프로토콜 ) 31
 .IR수광모듈 데이타시트(첨부파일 참조)

IR수광모듈-datasheet.pdf
다운로드


아두이노로 제어하기 좋은 로봇을 찾아오다 얼마전 드디어 쓸만한 녀석을 발견했습니다.

바로 무선제어 6족보행 로봇이란 제품입니다.





6족 보행로봇으로 전진,후진,좌회전,우회전이 가능하며 제공되는 적외선 리모컨을 통해 무선 조정이 가능합니다.
여러대의 로봇을 동시에 조정할 수 있도록 점퍼세팅으로 총 6대의 로봇을 동시에 조정할 수 있게 제작되었습니다.
조립도 간단하고 접착제같은건 사용하지 않아 신속하고 깔끔하게 제작이 가능합니다.

왜 좋은가?

1. 저렴한 가격
2. 손쉬운 제작 ( 8세이상 조립가능, 납땜불필요)
3. 손쉬운 아두이노 연동 가능( 전선 결합 불필요, 적외선 통신으로 제어)


조립시 필요한 것:
1.5V 알카리인 건전지 4개( 조정기용 2개, 로봇본체용 2개,  1.2V 충전지로도 잘 작동됩니다.)
스크류 드라이버

아두이노로 제어할 경우 필요한 재료:
 아두이노, IRED(적외선 LED) 1개,  저항 1개
(5미터 이상의 장거리 제어를 원하면 트랜지스터 1개, 저항 1개가 추가로 필요합니다.  관련글 링크 참고)


동영상1. 로봇 기본동작 보기

리모컨 제어로 전진, 후진, 좌회전, 우회전이 가능합니다.


아두이노로 제어하기

1. 하드웨어 준비
적외선 리모컨 신호를 아두이노 디지털 출력을 통해 출력하면됩니다.  이를 위해서 IRED(적외선LED) 1개와 저항 1개가 전부입니다.   원거리에서 제어하려면 트랜지스터를 사용해야 합니다.  연결방법은 일반 LED와 동일하게 저항1개와 함께 직렬 연결해주시면 됩니다.  본 예제에서는 PWM출력을 지원하는 아두이노 디지털 3번핀을 사용합니다.

리모콘 신호 전송을 위해 아두이노에 IRED 연결


IRED연결은 일반 LED 연결과 유사합니다.



2. 라이브러리 준비
적외선 리모컨의 역활을 아두이노가 대신하려면 여러분이 직접 38KHz의 캐리어 주파수에 수신기의 코드부호를 실어서 출력해주면 됩니다.  하지만 많은분들에게 쉽지 않은 도전과제이므로 천재적이면서 친절하기까지 하신 분들이 미리 만들어둔 라이브러리를 활용하여 비교적 손쉽게 아두이노로 리모컨 신호를 발신할 수 있습니다. 

아래의 링크에 가셔서 해당 라이브러리를 아두이노 스케치 library 폴더안에 복사하여 라이브러리 설치를 완료합니다.


위에서 준비해놓은 라이브러리는  RC5, SONY, NEC 코드 등의 송신 및 수신을 위한 기능이 제공되며 여기서는 NEC코드 발신 함수만 사용하면 됩니다. 리모컨 신호를 이용해 가전기기를 제어하는 것에 대해 일전에 소개해 드린적이 있는데요  이번에도 마찬가지로 코드부호를 스캔하여 해독한 결과 이 로봇도 NEC코드와 유사한 전송방식을 사용하는것을 알게되었습니다.
차이점은 데이타 전송폭이 짧다는 점과 반복표시용 코드를 사용하지 않는다는 것입니다. 

하지만 로봇제어를 위해 복잡한 내용은 모르셔도 상관 없습니다.  단지, 아래와 같은 함수 하나만 사용하기 때문입니다.


  irsend.sendNEC( codedata , nbits );   // codedata에 수신기용 코드값과   nbits에 코드값의 비트 수를 적어주면 됩니다.

위와 같은 함수로 해당코드값을 전송하면,  아두이노의경우 디지탈 3번핀에 해당되는 코드신호가 출력되고 이곳에 연결된 IRED를 통해 빛신호로 변환되어 출력되고  로봇에 내장된 적외선 수신기에서 해당 코드를 수신한뒤 대응되는 모터의 작동이 이뤄지게 되는 것입니다.


아래의 소스는 1초에 한번씩 전진, 후진, 좌회전, 우회전 신호를 발신하는 예제입니다.


#include <IRremote.h>

IRsend irsend;  

void setup()
{
// 특별한 초기화 설정이 불필요합니다.
}

void loop() {
   irsend.sendNEC( 0xc5000000, 8); //전진
   delay(1000);
   irsend.sendNEC( 0x45000000, 8); //후진
   delay(1000);
   irsend.sendNEC( 0x25000000, 8); //좌회전
   delay(1000);
   irsend.sendNEC( 0x85000000, 8); //우회전
   delay(1000);
  
}


위의 소스는 1초에 한번씩만 코드를 발송하므로 지속적으로 작동상태가 유지되지 않습니다. 따라서 만약 전진을 지속적으로 하려면 1초에 수회 정도 전진에 해당되는 코드를 반복하여 전송해야합니다. 


동영상2. 위 소스로 로봇 제어되는 장면

보통 이동형 로봇을 제작시 아두이노같은 마이크로콘트롤러 보드에 모터 구동 회로를 장착하고 모터 2개를 제어할 경우 방향제어를 위해 최소 4개의 전선을 연결하여 제어하게 됩니다. 이에 반해 본 로봇킷의 경우 모터 회로 구현이 이미 되어있는데다 전선의 연결이 불필요하고 빛으로 연결되어 있으므로 비용도 절감되고 제어도 간단해 질 수 있으므로 기초 이동형 로봇 제어 학습시 효과적으로 응용할 수 있는 방법으로 판단됩니다.  (물론 전용 모터드라이버 연결법이 더 다양한 제어가 가능합니다. 가령 속도조절이 가능함)

거리센서 등을 통해 주변 물체를 감지하고 회피하는 로봇의 제작이나  전파(Zigbee, Bluetooth, Wifi 등 활용)를 통한 무선통신으로 신호를 수신 받고 이를 광통신으로 변환하여 원격제어되는 로봇의 구현도 가능합니다.

게다가 수신모듈+모터드라이버 역활을 하는 제어기만 활용할 수도  있습니다.


사진. 리모컨 수신기 및 모터구동 드라이버 보드: 
좌측에 전원연결(2핀)부, 우측에 모터2개 연결부(4핀), 상부에 ON/OFF스위치,  하부에 리모컨 채널 조정용 헤더핀(6핀)이 있으며 가운데에 IR수광모듈이 보입니다.


기타.  작동중 오동작이 계속되면 건전지를 교체해 보시기 바랍니다.  모터 구동시 전력소모가 큰 편이므로 배터리 소모가 빨리 됩니다.


관련 제품 링크

 무선제어 6족보행 로봇

 아두이노 UNO

 적외선 무선통신킷



내용추가
2011.July.26 
아래의 관련글 링크에 리모콘 신호 송수신 회로와  PC에서 키보드 입력으로 로봇을 제어하는 소스 예제를 포함한 글을 새로 등록하였습니다. 참고하세요


관련글 링크

 .IR무선 리모콘 송수신 회로로 로봇 제어하기



로봇 개발 및 교육용 시뮬레이터 Marilou와 URBI(로봇통합제어플랫폼)의 교육자료( 파워포인트 ppt문서)를 아래에 첨부하였습니다.  필요하신 분은 요청없이 바로 다운로드하셔서 참고하실 수 있습니다.  국내의 일부 연구소와 기업들을 대상으로 제품 교육시 사용했던 자료이며, 기본 개념을 파악하시거나 소프트웨어 사용 테스트를 하실 경우 도움이 되실거라 생각됩니다.

Marilou_URBI-기본교육v2010a.pdf



아래는 교육문서 일부 페이지 내용입니다.













플래시로 AR(증강현실)을 구현해 봤습니다.

3D Engine은 Sandy3D, 마커인식은 FlarToolKit  을 사용했습니다.

증강현실 개발 지원킷인 ARToolKit을 AS용으로 포팅한것이 FlarToolKit인 데요

플래시도 AS3.0 들어와서 속도도 꽤빨라지고, 거의 못하는게 없는것 같습니다.

FlarToolKit 내에 예제용 3D모델까지 포함되어있으니 여러분도 한번 시도해 보시죠~

시중에 돌고있는 Simson 종이인형을 3D모델링하고 관절 몇개 만들어 왕복운동 시켜본 것 입니다.





체험 서버 종료

무료 호스팅 서비스를 이용하던중 해당 회사 서비스가 종료되어  현재 체험이 불가합니다.  죄송합니다!!

동영상에서 보셨듯이 별다른 기능은 없고요, 그냥 목과 팔을 흔드는 심슨 3D 로봇이랍니다. 

차후 서버에 재등록하게되면 링크를 수정하도록하겠습니다.


준비물:

  1. 웹캠 : 플래시에서 인식되는 웹캠이면 됩니다.

  2. 마커(인식용 이미지가 인쇄된 종이) : 첨부파일을 다운로드 하셔서 가능한 두꺼운 종이에 인쇄하세요.


사용 방법:

접속 후 웹캠 사용 허락하기를 선택하신 후,  인쇄된 마커용지를 카메라에 비춰줍니다. 이후 마커의 위치와 방향에 맞쳐서 3D 로봇이 오버레이 되는것을 보실 수 있습니다. 조명이 중요하니 적절히 주변광을 맞춰주시면 인식이 더 잘됩니다.


어떻게 작동하는가?

웹캡으로 실시간 캡쳐한 영상에서 마커(특정 이미지 패턴이 인쇄된 종이)를 찾고, 그 위치와 방향을 계산해 냅니다. 여기까지가 FlarTooKkit(ARToolkit)이 하는 일이고요, 마커의 위치와 방향에 해당되는 영상이미지 위에 3D로 가상의 영상을 오버레이시켜서 실제화면과 가상화면을 동기화 시키게됩니다. 이때 3D 형상을 보여주는데 사용되는것이 Flash 3D 엔진입니다.  본 예에선 Flash 액션스크립트 개발환경을 이용하여 Flash Player상에서 작동되게되므로 별도의 프로그램 설치없이 웹카메라와 웹브라우져만으로 작동되는 장점이 있습니다.  다만 속도가 조금(많이?) 느립니다.  때문에 매우 빠르고 고화질을 원하는경우는 C/C++기반의 개발환경을 이용하곤 합니다. 다만 이경우엔 별도의 실행파일을 설치하여야 한다는 단점이 있습니다.


[]첨부파일: 증강현실FlarToolkit용 마커이미지(pdf파일)

flarlogo-marker.pdf


[]참고자료

FlarToolKitSandy3D  , Away3D

심슨종이로봇: http://cubeecraft.com/  직접인쇄해서 종이로봇 만들어보시면 로봇 장난감이 뚝딱~.


+ Recent posts