오늘은 울트라 하이테크놀로지의 결합체인 디지탈 카메라를 만들어봤습니다.  "정말 피눈물나는 노력을 통해 완성한 나만의 아두이노 호환 똑딱이입니다." 라고 말씀드리면 거짓말이고요,  사실 제가 한 일이라곤 촬영된 이미지를 JPEG 포멧으로 시리얼통신을 통해 전송해주는 카메라와 이값을 수신하여 microSD메모리에 저장해주는 역활을 해주는 JPEG Trigger 아두이노 호환보드를 단순히 조립해주고 버튼한개 달랑 단것이 전부입니다.  아, 그리고 휴대용 카메라의 역활을 다할 수 있도록 3.7V Lipo충전지도 장착해줬습니다.  성능은 최신 카메라에 비길수 없겠지만 그래도 좋은건 센서연동 및 자유로운 제어가 가능한 아두이노 호환형 디지탈 카메라 시스템이라는 점입니다. 

시리얼통신 JPEG 카메라가 무엇인가?
시중에서 많이 구경할 수 있는 카메라들과 달리 촬영된 이미지를 JPEG 이미지 포멧으로 압축하여 시리얼 통신(TTL 레벨)으로 전송해주는 특수 카메라입니다.  즉, 시리얼 통신이 가능한 모든 기기에서 압축된 디지탈 이미지 데이타를 수신할 수 있습니다.(일반적인 video 신호 출력도 지원)  PC의 경우엔 FTDI USB시리얼 변환보드를 경유하여 카메라를 제어하고 이미지를 수신해 볼 수 있습니다. (

관련글 - 시리얼통신 카메라 PC연결하기 

)
그리고 무엇보다도 아두이노같은 8bit 저속 MCU 보드들에서도 시리얼통신으로 촬영된 이미지를 수신할 수 있게 되어 유용한 카메라입니다. 물론 압축된 이미지(JPG) 데이타라도 아두이노에서 실시간 처리를하는 것은 무리가 있습니다.  하지만 데이타를 SD메모리에 저장하고 참고하는 형태의 응용이라면 충분히 제 역활을 할수 있게되는데요,  이 역활을 하는 전용 보드(JPEG Trigger)가 있어 함께 사용하면 손쉽게 디지탈 카메라 기능 구현이 가능해집니다.

JPEG Trigger 보드
본 제품은 JPEG Camera와 짝을 이뤄 사용하도록 최적화된 아두이노 호환 보드이지만 몇가지 특수 기능을 갖쳐서 프로그램을 바꿔서 다른 용도로 사용하는것도 좋을 것 같습니다.   JPEG 이미지 저장용 microSD 메모리 인터페이스와   1V~ 5V 사이의 전원을 입력해주면 내장된 승압회로를 통해 5V전원으로 작동되도록 설계되어 건전지(1.5V or 3V)나 Lipo(3.7V) 충전지 하나만으로 작동이 가능합니다.  야호!  더불어 총 6개의 범용 IO핀( 아두이노 D2,D3,D4,A0,A1,A2) 홀이 제공되어 트리거(Trigger, 셔터눌러주기) 용도 및 기타 IO기능으로 사용이 가능합니다. 


오픈 소스 하드웨어
공개된 소스코드와 라이브러리를 설치해주면(이미 프로그램되어 있음) 원하는 방식으로 카메라 구현이 가능하므로 응용범위가 무궁무진해 집니다.



사진. 초간단 디지탈 카메라 구현 연결이미지
카메라 + 보드 + Lipo충전지 + 버튼 을 연결해주기만 하면 프로그래밍 없이도 바로 작동합니다.



동영상. 결합상태 확인 및 사진촬영 테스트

동영상 내용 소개
보드, 카메라, 충전지, 버튼이 연결된게 보입니다. 스위치를 켜주면 상태점검 후 상태 LED가 켜집니다.  이게 안켜지거나 깜빡거리면 카메라나 메모리에 문제가 있는것입니다.   초기상태의 경우  D2,D3,D4 버튼중의 하나를 GND에 연결하는 순간 카메라 셔터가 작동(촬영)되고 JPEG으로 압축된 이미지가 시리얼 통신으로 보드에 전달되고 이 정보가 SD메모리에 저장됩니다. 마침 네모로봇 군이 옆에 있어 버튼을 눌러 촬영을 해봤습니다.  이미지가 저장되는 중에 상태 LED가 깜빡거리는게 보입니다.  저장이 완료되면 상태 LED가 다시 켜집니다.  저장된 이미지는 PC에 연결하여 (변환과정 없이) 볼 수 있습니다.  (단, 초기 프로그램된 상태에선 확장자가 txt로 저장이되는 문제가 있어서 이를 PC에서 jpg 확장자로 변환해야 볼 수 있습니다. 신규 소스로 업로드하시면 이문제는 해결됩니다.)

사진. 촬영된 이미지 예



카메라와 보드 연결
JPEG카메라 <-> JPEG트리거보드
VCC -- 5V
GND -- GND
TXD -- D5(Rx)   주의. 카메라측 송신(Tx)단자가 트리거보드 측 수신(Rx)에 (교차)연결됩니다.
RXD -- D6(Tx)   주의. 카메라측 수신(Rx)단자와 트리거보드 측 송신(Tx)에 (교차)연결됩니다.
TV(미연결)  일반적인 video 신호출력선입니다. 본 예제에서는 사용안함.

전원
배터리 단자에 3.7V 정도의 Lipo충전지를 연결하여 사용하거나,
배터리 단자 옆에있는  GND와 1~5V 핀에   1~5V 전원을 연결해줍니다.
(입력된 전원은 5V승압회로를 통해 5V로 승압되어 공급되게됩니다.)
(FTDI USB시리얼 보드 연결시엔 usb 전원이 상시 연결됩니다.)

보드테스트
(카메라 및 메모리)아무것도 장착하지 않은상태에서
스위치 off상태에서 Lipo단자에 Lipo배터리 연결후, 스위치 on하고 몇초후 LED가 깜빡거려야함.


스위치 기능
배터리 입력전원을 승압회로에 연결여부를 선택해준다.(회로도를 꼭 참고하세요)
배터리 사용시 보드 ON/OFF 기능으로 사용됩니다.
(FTDI USB시리얼 보드 연결시엔 usb 전원이 상시 연결됩니다.)

사용법
카메라와 FAT 포멧된 메모리를 장착후 전원을 켜주면 LED가 ON된다.
메모리가 없거나 포멧상태 문제등으로 초기화가 안되면 LED는 깜빡인다.
카메라가 연결되지않은경우 LED가 안켜진다.
(단, 상태LED 모드는 펌웨어에 따라 다를수있으므로 해당 소스 상단 주석을 확인바랍니다.)

입출력핀
카메라 촬영신호를 받거나 I/O용으로 아래의 6개핀을 사용할 수 있습니다.
아두이노 디지탈핀 D2,D3,D4와
아두이노 아날로그핀 A0,A1,A2를 입출력
보드에는 손쉽게 전원활용을 할수있도록 각 입출력핀마다 GND,5V 홀(구멍)이 함께 있어서
총 18개의 구멍이 있습니다. 이때 GND, 5V 구멍이 안쪽에 있고 바깥쪽이 D2,D3,D4,A0,A1,A2 핀이므로 주의바랍니다.



카메라 촬영법
초기 제공되는 펌웨어(소스참조)의 경우
D2,D3,D4 핀을 GND에 연결하거나 (내부 Pullup되므로 별도 저항없어도 됩니다)
A0,A1,A2 핀을 5V에 연결하는 순간 카메라 촬영이 되고,이미지가 메모리에 저장됩니다.
이때 LED가 깜빡거리고, 저장이 끝날때까지는 재촬영이 안됩니다.


저장된 JPEG이미지
초기 제공되는 펌웨어의 경우,
저장된 이미지는 001.TXT 와 같이 확장자가 TXT로 저장되는 문제가있으며 이를 PC에서 JPG로 변경하셔야 이미지 확인이 가능합니다. 하지만 새로 제공되는 소스코드로 재프로그래밍 하시면 JPG확장자로 저장되므로 꼭 업그레이드 하시기 바랍니다.


주의사항:
보드가 켜있는 상태에서 메모리카드를 뽑지 마세요! 메모리 상태 및 보드 펌웨어 상태가 손상될 수 있습니다.
이경우 보드 펌웨어를 재프로그래밍하고 메모리를 재 포맷해야할 수 있습니다.


 

 

 

오늘은 귀가 즐거운 녀석을 소개해드리겠습니다.
이녀석을 아두이노 호환보드들에 장착하면 MP3 player 기능 구현이 가능하며, wma, wav, midi 포멧도 지원합니다.

완성도 높은 하드웨어
휴대용 mp3와 같은  조그셔틀 버튼과 음량버튼이 내장되어있고 ipod dock에 장착할수있는 포트도 내장되어있습니다.   게다가 헤드폰단자외에 마이크입력단자도 제공됩니다.
오호~ 녹음도 되냐고요???  네, 가능합니다. 하지만 ATmega1280이나 2560 급 보드에서만 가능하답니다.  즉, 일반 아두이노 UNO보드는 안되고 Mega2560 보드에서 가능합니다.
그리고, DIY 창작을 하는 여러분들에게는 하드웨어만 좋아서는 안되겠죠! 

오픈소스(Open Source)
본 제품을 위한 player 구현 소스코드가 공개되어 있으므로 마음대로 모든 기능을 계량 or 해킹이 가능하다는것이 가장 마음에 드는 점입니다.

 

 

 

 

 

첨부파일
제조사 wiki 페이지 링크가 문제일경우 첨부된 소스코드 파일을 참고하시기 바랍니다.

music_v1_13.zip
다운로드
Music_v1_14.zip
다운로드
NewSoftSerial.rar
다운로드
portpins.h
다운로드

이번엔 기상측정기구와 이더넷 쉴드가 장착된 아두이노(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 케이블을 이용하시면 전원과 이더넷케이블을 하나로 줄일 수 있어 더욱편리합니다. 가령 위의 시스템을 아래의 이미지와 같이 간소화 시킬 수 있습니다.

안녕하세요 재밌는 창작재료가 너무 많아 무엇부터 갖고 놀아야 할지 고민이 됩니다.  ^^.  즐거운 고민이죠;;
오늘은 기상측정용 기구를 소개해 드리겠습니다.

참고로,

다음글

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

일단은 기상측정기구에 대해 좀더 알아봅시다! 

 

 

Weather Meter (기상 관측기구 , Weather Sensor Assembly)
본 장비는 3가지 기상 관측 기초 자료를 측정할 수 있습니다.


1. Rain Gauge (강수량계)
입수되는 수량에 비례하여 스위칭을 해주는 특수 기구를 이용하여 1회 스위치시마다 0.2794mm 의 강수량에 대응되게 됩니다. 물시계 작동원리를 응용한것인데 아이디어가 참 좋네요

사진에는 안나왔네요;;  일단, 동영상을 참고하시길~

2. Anemometer (풍속계)
회전시마다 일정수의 스위칭이 이뤄지며 기준 시간당 스위칭 수를 측정하여 풍속 계산이 가능합니다. 1초 동안 1회 스위칭시 2.4km/h ( 0.6666m/s)의 속력에 대응합니다.

 

 

 

 

 

3. Wind Vane ( 풍향계)
바람의 방향을 16방위로 측정 가능한 센서입니다. 내장된 저항들과 회전각에 따라 작동되는 스위치에 의해 내부저항 값이 변화하며, 이 값을 10k옴 저항 한개와 기준전압 5V를 통해 아두이노 아나로그 입력 핀으로 감지하게 됩니다.  회전각에 따른 출력 전압 값은 데이타시트에 나와 있습니다.  ( 회로연결법은 매우 간단합니다.  광센서나 온도센서의 저항 변화를 전압변화로 출력해주는 회로와 동일)

 

 

 

 

 

 

 

그림1. 풍속계의 내부 회로도( 저항과 스위치 들이 보입니다. 스위치가 눌려지면 내부저항이 변화함)

 

 

 

그림2. 풍향계 연결법( 5V와 10k저항을 사용하면 아래의 테이블에 있는 전압값이 Output핀에 출력됩니다.)

가령 0도(North,정북)을 향할 경우 내부저항은 약 33k옴이고  이때 10k옴 저항과 5V에 연결시 약 3.84V 가 측정됩니다.

Direction esistance Voltage
(Degrees) (Ohms) (V=5v, R=10k)
0 33k 3.84v
22.5 6.57k 1.98v
45 8.2k 2.25v
67.5 891 0.41v
90 1k 0.45v
112.5 688 0.32v
135 2.2k 0.90v
157.5 1.41k 0.62v
180 3.9k 1.40v
202.5 3.14k 1.19v
225 16k 3.08v
247.5 14.12k 2.93v
270 120k 4.62v
292.5 42.12k 4.04v
315 64.9k 4.78v(4.34v)
337.5 21.88k 3.43v

          
테이블1. 회전각/저항/전압 관계

참고. 제 경우 실측결과 315도 경우의 측정전압이 데이타시트와 달랐습니다. 참고하시기 바랍니다.


측정기의 비밀
본 장치를 회전시켜보면 풍향계와 풍속계 모두 매우 매끄럽게 회전됩니다. 센싱을 위해 스위치를 눌러주는 방식이라면 회전을 조금이라도 방해를 하게 될 테지만 이 기구는 그렇지 않습니다.  왜 그런지는 속을 들여다보면 나옵니다.  바로 마그네틱 센서입니다. 초소형 고강도 자석을 회전부에 설치해두고 회전시마다 자력으로 자석스위치를 일시적으로 단락시키는 방식을 사용하네요.  단순하고도 사용하기 편리한 메카니즘입니다.

연결 방법
풍향/풍속/강우량계 모두 각각의 케이블이 있으므로 총 3개의 케이블이 있습니다. 하지만 이중 풍속계 케이블을 풍향계 하단의 단자에 결합하게 되어 있으므로 2개의 케이블만 사용하면 됩니다.  케이블 전선은 일반 전화선과 유사하고 단자는 인터넷 케이블에 사용되는 것과 동일한 RJ45-8pin 단자입니다. 즉, 인터넷 케이블과 결합소켓을 이용하여 원하는 길이로 늘려줄 수 있게됩니다.  이더넷 케이블을 절단하여 라인을 브레드 보드에 결합하면 손쉽게 센서 스위치와 연결할 수 있습니다.(사진참조)
풍향계+풍속계 케이블 한곳에서 4개의 라인,  강수량계 케이블에서 2라인만 뽑아서 사용하면 됩니다.

 

 

측정 방법
풍속계와 강수량계는 스위치가 ON되는 횟수를 카운팅하면 되며 아두이노(Arduino)나 MCU를 이용하여 디지탈 입력핀으로 버튼이 눌려진 횟수를 카운팅하는 방법으로 측정이 가능합니다.  단, 스위칭시 노이즈로인해 1회 스위칭이 수~수십회 단락된 것으로 인지되므로 적절한 샘플링 주기(가령 20ms)마다 측정을 하여 스위치의 상태가 변이하는 순간에만 카운팅을 하도록 프로그램해줘야 합니다.  또한 강수량은 일정기간(가령 1시간)동안 그 값을 누적하여 결과로 사용하고,  풍속계도 일정 시간동안의 스위칭 횟수를 카운트하여 속력을 계산할 필요가 있습니다.
풍향 측정시엔 1개의 아날로그 입력핀이 필요하며, if else 구문으로 16 구간의 범위 조건으로 나눠서 각도를 구분해주면 됩니다. 


예제 소스
막상 어떻게 측정이 가능한지 궁굼하신 분들을 위해 참고용 소스코드를 함께 수록합니다.
정확성은 보장 못드리지만 참고하시기 바랍니다.

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


#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


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

const int windVanePin = A0;  // 아날로그 0번핀에 연결
int winVaneValue = 0;        //
float windSpeed = 0;
float rainGauge = 0;
float windDirection = 0;
char windName[4];  // N (North)  S South,   NS(north south)   NNS(north north south)

  unsigned long windSpeedTimer;
  int windSpeedState = true;
  int windSpeedPin = 2;
  int windSpeedCounter = 0;
  unsigned long rainGaugeTimer;
  int rainGaugeState = true;
  int rainGaugePin = 3;
  int rainGaugeCounter = 0;


void setup()
{

  Serial.begin(9600);
 
  //wind speed sensor
  pinMode(windSpeedPin, INPUT);
  digitalWrite( windSpeedPin, HIGH);
 
  //rain gauge sensor
  pinMode(rainGaugePin, INPUT);
  digitalWrite( rainGaugePin, HIGH);
 
}

/*
* char 배열의 문자열정보를 Serial통해 문자로 전송 ,  PC에서 참고용
* char 배열을 사용한것은 차후 인터넷통신(트위터전송)을 위한 것입니다.
*/
void printChars(char *msg, int len){
  if(len == 0) return;
  for(int i=0; i<len ; i++)
    Serial.print( msg[i]);
  Serial.println();
}

/*
* f2h와 f2p는  float형의 정수부와 소수부를 위한 것입니다.
* sprintf에서 float형 사용에 문제가 있어서 땜빵으로 사용된 함수입니다.
*/
int f2h( float num){
  return int(num);
}

int f2p( float num){
  return (num - int(num)) * 100;
}


void loop()
{
  // 10초마다 측정결과를 PC에 전달

  windSpeedTimer = millis() + 10000; // 10초를 주기로 반복됩니다.
  windSpeedCounter = 0;
  while( millis() < windSpeedTimer ){
    delay(20); //20ms 주기로 센서의 스위칭을 감지합니다.
    //wind speed  풍속계 센서 감지부
    if( (windSpeedState == true ) && !digitalRead( windSpeedPin) ){
        windSpeedCounter++;     //스위치 상태가 high에서 low로 떨어지는 순간을 감지합니다.
        windSpeedState = false;
    }else if( (windSpeedState == false) && digitalRead(windSpeedPin) ){
        windSpeedState = true;
    }   
    //rain gauge
    if( (rainGaugeState == true ) && !digitalRead( rainGaugePin) ){
        rainGaugeCounter++;     //스위치 상태가 high에서 low로 떨어지는 순간을 감지합니다.
        rainGaugeState = false;
    }else if( (rainGaugeState == false) && digitalRead(rainGaugePin) ){
        rainGaugeState = true;
    }       
  }
 
  rainGaugeTimer++;
 
  if( rainGaugeTimer > 360){// 10초 * 360 = 3600초(1시간)  지난 1시간동안 누적한 강수계 카운터로 강수량 계산
    rainGauge = rainGaugeCounter * 0.2794;
    rainGaugeCounter = 0;
    rainGaugeTimer = 0;
  }
  
    windSpeed = windSpeedCounter * 0.24 ;   // 1초당 1회 스위칭시 2.4km/h 속력이며 10초 기간이므로 0.24가 됨
    getWindDirection();  // 풍향은 발표시점에 1회만 측정
   
    //char 배열에 정보를 취합(인터넷 전송에 적합한 자료형)
    sprintf( msg, "ArtRobot's Weather Bot said => Wind: %s/%d.%d, %d.%d(km/h) Rain %d.%d(mm/h).", windName, f2h(windDirection), f2p(windDirection), f2h(windSpeed), f2p(windSpeed),  f2h(rainGauge), f2p(rainGauge) );
    printChars( msg, sizeof(msg) ); //PC에서 참고용으로 시리얼전송
    //이후 소개할 예제에서 위 자료를 이더넷을 통해 트위터에 포스팅하게됨
 
}


/*
* 풍향측정: 아날로그핀입력되는 전압값으로 16가지 방향중 하나로 계산됨.
*
*/
float getWindDirection(void){
  int readValue = analogRead(windVanePin);           
  // 0~1023 사이의 입력값을 0~5V 기준 값으로 비례변경함.
  winVaneValue = map(readValue, 0, 1023, 0, 500);   
  //이제 winVaneValue는 데이타 시트정보상의 방위별 전압치와 유사한 값이 됩니다.
 
  if( winVaneValue < 35){
    //0~0.35V를 동동서 로 인식함
    //   112.5  0.32v (31 32)    0~35
    windDirection = WIND_ESE;
    strcpy(windName ,"ESE");       
  }else if( winVaneValue < 43 ){
    //   67.5  0.41v(40 41)    ~42   
    windDirection = WIND_ENE;
    strcpy(windName , "ENE");       
  }else if( winVaneValue < 50 ){
    //   90  0.45v(44 45)      ~50   
    windDirection = WIND_E;
    strcpy(windName , "E");       
  }else if( winVaneValue < 70 ){
    //   157.5  0.62v(60 62)   ~70
    windDirection = WIND_SSE;
    strcpy(windName , "SSE");       
  }else if( winVaneValue < 100 ){
    //   135  0.90v(89 90)      ~100
    windDirection = WIND_SE; 
    strcpy(windName , "SE");       
  }else if( winVaneValue < 130 ){
    //   202.5  1.19v(119 120)  ~130
    windDirection = WIND_SSW; 
    strcpy(windName , "SSW");       
  }else if( winVaneValue < 170 ){
    //   180  1.40v(140 141)   ~170
    windDirection = WIND_S; 
    strcpy(windName , "S");       
  }else if( winVaneValue < 210 ){
    //   22.5  1.98v(198 199)  ~210
    windDirection = WIND_NNE; 
    strcpy(windName , "NNE");           
  }else if( winVaneValue < 250 ){
    //   45  2.25v(226 227)    ~250
    windDirection = WIND_NE; 
    strcpy(windName , "NE");           
  }else if( winVaneValue < 300 ){
    //  247.5  2.93v(293 294)  ~300
    windDirection = WIND_WSW; 
    strcpy(windName , "WSW");       
  }else if( winVaneValue < 320 ){
    //  225  3.08v(308 310)   ~320
    windDirection = WIND_SW; 
    strcpy(windName , "SW");       
  }else if( winVaneValue < 360 ){
    //  337.5  3.43 (343 345)  ~360
    windDirection = WIND_NNW; 
    strcpy(windName , "NNW");       
  }else if( winVaneValue < 395 ){
    //   0  3.84v(384~385)    ~395
    windDirection = WIND_N; 
    strcpy(windName , "N");
  }else if( winVaneValue < 415 ){
    //  292.5  4.04v(405 406)  ~415
    windDirection = WIND_WNW; 
    strcpy(windName , "WNW");   
  }else if( winVaneValue < 450 ){
    //  315  4.34(433 434)  ~450
    windDirection = WIND_NW; 
    strcpy(windName , "NW");       
  }else if( winVaneValue < 490 ){
    //  270  4.62v(461 463)    ~490
    windDirection = WIND_W; 
    strcpy(windName , "W");       
  }else{
   //error  알수없는 값범위
  }

}


결과 출력예
위 예제의 경우 10초마다 아래와 같은 결과가 PC로 전송됩니다.
ArtRobot's Weather Bot said => Wind: N/0.0, 3.83(km/h) Rain 0.0(mm/h).
ArtRobot's Weather Bot said => Wind: W/270.0, 4.79(km/h) Rain 0.0(mm/h).
...



관련제품 링크
 

기상측정기구(Weather Meter)

 

아두이노 UNO(Arduino)

연관글 보러 바로가기
 

트위터(Twitter)에 기상측정 자료 올려주는 로봇 만들기

여러분이 획기적인 아이디어와 훌륭한 기술로 안드로이드용 앱을 개발하고 계시다면 아마도 최근 구글 IOIO행사에서 발표된 Open ADK (공개형 안드로이드용 엑세서리 개발킷)에 대해 들어보셨을 겁니다.

안드로이드용 오픈 엑세서리 개발 보드는 PC에 각종 USB 장치를 연결하여 확장된 기능을 사용할 수 있는것 처럼 안드로이드와 결합하여 사용가능한 하드웨어 장치를 개발하기위해 사용됩니다. 이미 많은 안드로이드 기기가 GPS, 가속센서, 자기 센서등을 내장한채 보급되고 있습니다만, Open ADK와 호환 개발 보드를 사용하면 그밖에 특화된 센서를 연결하거나 좀더 고급의 유저 인터페이스를 결합시킬 수 있게됩니다.  그렇다고 새로운 기기의 개발에만 필요한것이 아닙니다. 표준화된 규칙을 이용하여 기존에 개발되어 있는 제품들과도 손쉽게 연동이 가능해 지므로 큰 노력 없이도 안드로이드와 많은 엑세서리와 연동할 수 있게되어 하드웨어 개발자와 안드로이드 디바이스 및 앱 개발자 모두에게 효과적인 환경이 제공되는것 같습니다.

Open ADK 관련 정보는 공개되어 있으므로 관련 개발보드는 직접 개발하실 수도 있습니다. 하지만 많은 분들에겐 이미 상용화된 제품을 이용하시는것이 효율적일겁니다.  이번에 소개해 드릴 제품도 그중의 하나입니다.

 

 



안드로이드 요요  ( IOIO for Android )

해당제품에 있는 실크 이미지를 잘 보시면 안드로이드 로봇이 한손에 요요를 갖고 노는것이 보입니다.  IOIO를 yo-yo 라고 발음한다고 하는데 안드로이드와 함께 연결되어 IO(Input Output) 기능을 수행하는 녀석을 요요로 표현한것은 매우 적절한 비유인것 같습니다.  서두가 길었습니다.  이제 본격적으로 요요 보드를 소개해 드리겠습니다.

아래의 정보들은 http://codaset.com/ytai/ioio/wiki 에 있는 요요 Wiki 정보와 요요 제조사의 튜토리얼 정보를 참고로 하였습니다.   (변경안내:  위 codaset 링크를 비롯한 모든 자료가  https://github.com/ytai/ioio/wiki 로 이전되었으니 신규 사이트 정보를 이용해주시기 바랍니다.)

1부. 둘러보기

요요,  너의 정체가 무엇이냐?

제품에 떡 하니 자리를 차지하고있는 녀석은 MICROCHIP사의 PIC24FJ256 MCU입니다.   보드 둘레로 총 48개의 IO핀이 있고 VIN , GND, 5V, 3.3V 전원 연결핀이 있으며 USB 기기를 연결 할 수 있는 커넥터가 있습니다. 

어짜피 요요 보드의 펌웨어를 직접 변경하지 않으시고 사용하셔도 되므로 내장 MCU 칩이 AVR이건 PIC이건 상관없습니다.


요요 사용법

1. 전원
요요는 USB 호스트 역활을 수행하는 보드이며 연결된 안드로이드기기에 전원을 공급하여 충전할 수 있게 개발되어 있습니다.  즉, 자신뿐 아니라 연결된 안드로이드까지 커버할 정도의 충분한 전력이 필수적으로 요구됩니다.

VIN과 GND 단자에  전압이 7~12V정도의  *1A이상 전류 공급이 가능한 전원을 사용해야합니다.
정전압 5V 전원의 경우엔  VIN 단자 대신 5V 단자와 GND 사이에 직접 정전압 전원을 연결하셔도됩니다.  3.3V 단자에서는 레귤레이터로 감압된 3.3V 전원을 출력하여 활용할 수 있습니다.  (단, 3.3V단자에 3.3V 전원을 입력하는건 안됩니다)
관련 정보를 꼭 읽어보시고 연결하시기 바랍니다.

보드에 전원을 입력하면 POWER LED에 불이 들어옵니다.

2. Charge 전류량 조정용 트리머
요요에 전원을 연결후 안드로이드 기기와 연결해주면 안드로이드 기기의 충전이 시작되는 것을 확인할 수 있습니다.
하지만, 기기의 배터리 상태와 기기특성에 따라 충전과 요요 기기 인식이 안되는 경우가 있습니다. 이는 요요가 적절한 전력을 공급하지 못하는 경우인데요, 이때는 USB단자 옆에 있는 트리머를 시계방향으로 회전하여 전류공급량을 늘려주면됩니다. 기기마다 특성이 다른점에 대처하기 위해 본 트리머 설정기능을 제공하는것 같습니다.


3. 안드로이드 기기 설정

안드로이드 앱을 개발해오신 분들이라면 다 알고계신 내용입니다.

설정 > 응용프로그램 > 개발 > USB 디버깅  설정을 켜주셔야 합니다.


4. 프로그래밍

요요 보드 자체는 별도의 프로그래밍 작업이 필요없습니다.
안드로이드 기기에서 요요 보드에 있는 48개의 IO핀을  범용 디지털 입력,출력,아날로그입력(ADC),TWI, SPI,UART,PWM 등의 용도로 설정하고 값을 IO할 수 있는 라이브러리가 제공되기 때문입니다.   즉, 요요를 연결하면 안드로이드 기기에서 제어가능한 48개의 IO핀이 생겼다고 보시고 안드로이드 디바이스를 프로그래밍을 하시면 됩니다.

5. 케이블 연결 방법

케이블은 기존에 안드로이드 개발에 사용하셨던 기기용 USB 케이블을 그대로 사용하시면 됩니다.
PC와 안드로이드 디바이스를 USB 케이블로 연결 후 요요 연동용을 위한 프로그래밍을 하신 후,
PC쪽 단자를 뽑아서 요요에 연결하시면 됩니다.


6. 요요 보드 사용법

본래 요요보드는 Android 1.5 부터 지원되는 MicroBridge (ADB의 구현)를 활용하도록 개발되었으며 이는 구형 안드로이드OS(1.5이상) 에서도 활용이 가능한 장점이 있습니다.  하지만 최근에 새롭게 발표된 Open ADK (Android 2.3.4 이상 지원)의 지원도 가능하도록 새로움 펌웨어가 제공되고 있습니다. IOIO의 ADK 펌웨어는 현재 beta버젼이며 필요하신 경우 요요보드의 펌웨어를 변경후 사용가능한 방법입니다.

본 글에서는 펌웨어 변경없이 요요의 기본 연동방식을 이용합니다. 제가 갖고있는 안드로이드 기기가 1.5~2.2 정도만 지원되므로 당장 Open ADK 방식의 테스트는 어려울것 같습니다;;

7. ADB?  MicroBridge? 
개발시 디버그 용도로 사용되는 통신방법 및 툴 정도로 생각하면 될 것 같습니다. 이를 활용하여 안드로이드에 연결된 장치와 통신을 할 수 있습니다.  여러분도 보유하신 MCU보드에 USB호스트 기능만 추가하고 본 프로토콜 구현만 해주시면 안드로이드 연동 보드 개발이 가능합니다.  사실 Open ADK도 이것에서 파생되었다고 볼 수 있습니다.


8. 요요 IO 핀맵

요요 보드 뒷면에는 동그라미와 네모, 알바벳 P 등으로 각 핀의 기능을 간략히 표현하고 있습니다.  가령 네모 박스된 핀들은 모두 아날로그 입력핀으로 사용할 수 있으며,  동그라미 표시된 핀은 5V 입력이 허용되는 핀입니다.  요요의 기본 입출력 전압 레벨은 3.3V이지만 일부 핀의 경우 5V 입력이 허용되는 것 입니다. 자세한 핀별 용도는 별도의 상세페이지로 소개되고 있습니다. (IOIO핀맵 핀별 기능소개)


2부. 실습

이제는 직접 요요보드에 프로그래밍 후  기초적인 IO를 수행해 보도록 하겠습니다.
아래에 소개된 예제들은 안드로이드 프로그래밍이 처음인 분들을 위한 튜토리얼에 포함되 기본 예제와 아래의 IOIO 기본 공개 예제들을 그대로 사용하거나 몇 줄만 수정한 것입니다. 직접 해당 소스를 보시고 응용해보시기 바랍니다.
http://codaset.com/ytai/ioio/source/master/tree/software/applications

안드로이드 프로그래밍 자체가 처음이신 분들은 요요를 사용하시기 전에 우선 안드로이드 프로그래밍 기본예제를 꼭 실습 후 진행하시길 권장드립니다.  안드로이드  개발환경 설치 및 디바이스 인식 등이 마무리 되어야 요요 보드 응용 개발이 가능합니다.  거꾸로 마이크로 콘트롤러 보드와 같은 전자회로에 대한 경험이 없으신 분들은 Open ADK 보드의 기준 플래폼인 아두이노로 기초 학습을 진행하실것을 추천드립니다.


예제1-1. 상태 LED 제어하기

안드로이드 프로그래밍이 처음인 분들을 위한 튜토리얼에 포함된 기본 예제입니다.
보드에 내장된 stat(상태) LED를 On/Off 하는 예제이므로 별도의 전자회로를 연결할 필요가 없이 요요 보드에 전원만 공급해주면 테스트 해볼 수 있는 간단한 예제입니다. 


동영상1. 요요 기본사용방법과 예제1-1 수행 장면입니다.



예제1-2. 디지탈 출력으로 SSR제어하여 220V 전등 On/Off하기

예제1-1.의 소스에서 상태 LED를 제어하는 소스를 그대로 한줄 더 복사하여 특정 디지탈 출력핀을 On/Off하고, 이 출력 값을

SSR(Solid State Relay)

에 연결하여 가전용 전등을 On/Off 하는 예제입니다.


동영상2. 안드로이드로 220V 전등 On/Off 제어



예제2-1. 아날로그 입력 및 PWM 출력

IOIOSimpleApp

예제가 사용되었습니다.

가변저항으로 0~3.3V 범위의 임의 전압을 만들고 요요 보드의 ADC(아날로그 입력) 기능으로 입력받은 전압값을 수치화 하여 보여주는 예입니다.  더불어  디지탈 출력핀을 통해 PWM 파형을 출력하는 예제입니다.  기본 예제에서는 스크롤바의 위치에 대응하여 0.5ms ~ 2.5ms duty의 파형을 출력하도록 되어있으며 정확한 출력이 나오는지 확인을 위해 오실로스코프로 관측해봤습니다.

동영상3. PWM 출력과 아날로그 입력

예제2-2. PWM 출력으로 서보모터 제어

예제2-1. 에서 사용한 소스를 그대로 활용하여 RC서보모터를 구동할 수 있습니다.  다만 일부 서보모터의 회전각 범위는 0.5~2.5 ms 범위를 지원하지 않으므로 서보모터의 안전을 위해 이값을 0.8~2.2ms 범위로 수정하여 테스트 하였습니다.
이를 위해 PWM duty 관련 소스를 아래와 같이 수정하였습니다.

      pwmOutput_.setPulseWidth(800 + (int)(seekBar_.getProgress() * 1.4));


예제2-3. PWM 출력으로 전압메터 변화보기

이번 예제도 예제2의 소스를 그대로 사용하였습니다.   0~5V 범위의 전압을 측정할 수 있는 아날로그 전압 메타를 PWM 출력 핀에 연결하여 PWM duty 변화에 따른 출력 전압변화로 눈금의 변화를 확인해 보는 예제입니다.  기본 소스는 duty를 0~100%로 수정하면 약 0~3.3V 출력 변화를 확인 하실 수 있습니다.  전압 메타는 보유하신 멀티테스터 전압계를 이용하셔도 됩니다. PWM 파형의 Duty 비율을 조절하는것으로 서보모터 제어나  LED의 밝기 제어, 색상 제어 등 을 하실 수 있습니다.


동영상4. PWM제어로 RC서보모터 제어 및 전압메터 변화 관측

제품 링크

 

추가사항

IOIO 공식 자료 링크 변경 안내
 글 내용중 codaset 사이트에 보관되었던  모든 자료가 

https://github.com/ytai/ioio/wiki

로 이전되었으니 신규 사이트 정보를 이용해주시기 바랍니다.)

 

+ Recent posts