최근에 무선통신 기술중 지그비 통신을 활용하게 되어 관련된 자료를 찾아보았는데 괜찮은 정보를 찾기가 매우 어려웠다. 제대로 검색하지 못한 필자의 탓일 수도 있지만 찾아본 대부분의 자료들은 대체 핵심은 어디 갖다 팔아먹었는지 그저 이러저러 해라 식의 단순 지식만 늘어놓고 있었으며 중복되는 내용 또한 심심찮게 발견할 수 있었다. 이러한 글을 읽고 제대로 이해될리 만무하다. 물론 구글을 활용해 해외 사이트에서 검색한다면 원하는 정보를 쉽게 찾을 수 있겠지만 국내에서 지그비와 관련된 간단한 설정법조차 찾기 힘들다는 사실은 매우 안타까울 뿐이다.


때문에 답답한 나머지 지그비 통신에 대해서 필자가 찾아보고 공부한 내용을 정리하여 공유하고자 한다. 순서는 네트워크와 지그비에 대한 개념부터 시작해서 지그비 모듈 종류 및 설정 방법, 아두이노를 활용한 무선 통신 실습 순으로 포스팅할 생각이며 부디 처음으로 지그비 통신을 공부하고 활용하고자 하는 사람들에게 도움이 되길 바란다.



1. 네트워크 이해


지그비에 대한 개념을 설명하기 앞서 네트워크에 대한 이야기를 잠시 해볼까 한다. 워낙 방대한 주제인 만큼 여기서는 간단하게 개념만 짚고 넘어가도록 하자. 네트워크란 Net + Work의 합성어로 컴퓨터들이 통신기술을 이용하여 그물망처럼 연결된 형태를 의미한다. 쉽게 말해 여러 대의 컴퓨터들이 서로 통신하는 것을 말하는 것으로 여기서 통신기술이란 프로토콜(Protocol)을 뜻하며 사전적으로 '규약', '약속'등을 의미한다. 컴퓨터 네트워크에서 서로 통신하기 위한 사전의 약속같은 것으로 해석할 수 있다. 예를 들어 식당에서 음식을 주문하는 상황을 가정해보자. 한 손님이 메뉴판에서 자신이 먹을 음식을 결정했고 바로 주문하려고한다. 하지만 웨이터는 다른 손님의 주문을 받고 있으며 다른 웨이터들 또한 보이지 않는다. 당신이라면 이 상황에서 어떻게 하겠는가? 아마도 당신이 조금의 기다림을 참지 못하는 몰상식한 사람이 아니라면 웨이터가 주문을 다 받을때 까지 기다린 후에야 자신의 주문 내용을 말할 것이다. 


그렇다. 방금 당신은 훌륭하게 사람들 간에 지켜야 할 프로토콜을 잘 지킨 셈이다. 만약 프로토콜을 지키지 않고 웨이터를 억지로 불렀다면 자신과 웨이터 뿐만 아니라 다른 손님과의 소통 또한 제대로 될리가 없다. 이렇듯 사람들이 말을 할 차례를 지켜 주는 것이 중요한데 이러한 개념은 네트워크 통신에서도 똑같이 적용된다. 네트워크 측면에서 위와 같이 통신의 순서를 정해주는 것을 미디어 접근(Media Access)라고 하며 동시에 여러 통신이 발생하는 상황을 다중 접근(Multi Access)라고 한다. 그리고 이러한 상황과 유사한 프로토콜이 바로 CSMA/CD 이다.


   · CSMA/CD (Carrier Sense Multi Access / Collision Detection)

   LAN(이더넷)에서 각 단말기 간 자료를 전송하고 있는 동안 회선을 감시하여 충돌이 감지되면 즉각 전송을 멈

   추고 재전송을 위해 기다렸다가 다시 시도하는 방식


위 방식은 여러 단말기가 통신을 시도했을 때의 충돌 상황을 완화시키는 역할을 한다. 쉽게 말해 앞서 언급한 웨이터의 일이 끝날때 까지 기다려 서로의 통신이 끊어지지 않도록 도와주는 것이다.


또한 네트워크 통신에서 단말기간 특정 주소를 가지는 개념은 매우 중요하다. 각 컴퓨터가 자신의 고유 주소인 IP를 할당받는 이유는 다른 컴퓨터와 구별되기 위해서임을 우리는 이미 알고있다. 따라서 각 단말기간 어떤 통신이 진행되기 위해서는 특정한 수신자의 주소가 지정되 있어야 데이터 보내기가 가능하다. 이러한 주소는 네트워크상에서 숫자로 할당받게 된다.



2. 네트워크 토폴로지(Network Topology)


네트워크 토폴로지란 단말기 상호 간에 데이터를 전송할 수 있도록 연결된 형태를 말한다. 이는 데이터가 잘 보내지고 받을 수 있도록 어떻게 네트워크를 구축할 것인가 라는 네트워크 전략과도 일맥상통하며 어떤 형태를 구축하느냐에 따라서 데이터의 흐름이 결정되게 된다. 따라서 다양한 형태와 방법이 존재하지만 여기서는 지그비 통신과 관련된 몇가지만 소개하고자 한다.


일대일 통신 (Peer to Peer)

일대일 네트워킹은 두 노드 (여기서 노드는 연결점을 의미하며 단말 장치나 통신 처리 장치 등을 뜻한다.) 사이에 데이터를 전송하기 위한 가장 간단한 형태이다. 다양한 채널을 사용할 수 있으며 서로 다른 주파수에 작동하는 무선조종자동자가 좋은 예이며 또한 개인과 개인이 직접 연결되어 파일을 공유하는 P2P도 이러한 개념의 연장선이라고 이해할 수 있다.



스타형 토폴로지 (Star Topology)

스타형은 이더넷 LAN에 가장 널리 사용되는 물리적 네트워크 구조로 중앙의 연결 지점에 허브나 라우터 같은 중심 노드(Coordinator)가 배치되어 모든 노드들을 관리하게 된다. 모든 데이터가 중앙 지점으로 모여지는 중앙 제어 방식이기 때문에 관리가 편하고 확장이 용이하지만 그만큼 부하가 많이 걸리게 되며 중앙 노드에 장애가 발생하면 전체 네트워크 사용이 불가능하게 되는 단점이 있다.


 메쉬형 토폴로지 (Mesh Topology)

메쉬형은 모든 노드가 네트워크상에서 혹은 개별적으로 현결된 그물망 형태로 다수의 노드 쌍이 동시에 통신할 수 있다. 이는 특정 노드의 장애가 다른 노드에 영향을 주지 않기 때문에 장애에 유연한 대처가 가능해지고 가용성이 극대화 되는 장점으로 작용한다. 하지만 그만큼 회선구축 비용이 많이 들게 되며, 새로운 노드를 추가할 시에 선로 구성이 복잡해지고 비용부담이 발생한다.

                        


토폴로지는 상황에 맞게 적절한 방식을 선택하는 것이므로 좋고 나쁨을 떠나 자신이 구축할 네트워크 환경에 적합한 것을 써야 한다.


3. ZigBee 통신


서론이 생각보다 길었다. 그럼 이제 본격적으로 지그비 통신이 무엇인지 알아보도록 하자. 지그비는 근거리 저전력 무선 통신을 위한 프로토콜을 일컫는다. 앞서 프로토콜의 개념을 제대로 이해하였다면 지그비 통신 또한 여러 개의 노드가 서로 통신하기 위해 만들어진 통신 규약이라는 것을 알 수 있을 것이다. 그럼 다른 무선 통신 방법과 비교하여 지그비의 특징을 살펴보자.


 

Zigbee

 Bluetooth

Wi-Fi 

NFC 

전송거리

 ~100m

~10m 

~100m 

~20cm

 전송속도

~250Kbps 

~24Mbps 

 11M / 54Mbps

106~848Kbps 

최대 채널 수

 32000

 14

 1

 소비전력

Very Low

Medium

High

Low

복잡성

Low

Low

High

Low

 비용

Low

Low

High

Low


위 표를 통해 지그비 통신은 복잡하지 않은 시스템 구조로 구성되어 있으며 적은 소비전력으로 인해 소형화가 가능함을 알 수 있다. 비록 전송 속도면에서 블루투스나 와이파이 통신이 우수하긴 하지만 가격이 비싸기 때문에 상대적으로 저렴하고 간단한 무선 네트워크를 구축할 수 있다. 또한 네트워크 규모도 방대하기 때문에 다수의 센서를 활용하거나 모듈을 사용하는 시스템에 적합한 형태를 보인다.


지그비 통신 모듈은 시중에서 다양한 형태로 판매되고 있으나 여기서는 가장 대중적인 제품인 Digi 사의 XBee모듈에 대해서 설명하겠다.  Xbee란 지그비 프로토콜을 바탕으로 보다 쉬운 설정과 사용을 위해 개발된 별개의 프로토콜이다. 따라서 지그비 통신을 기반으로 하고는 있지만 XBee 전용의 프로토콜을 따로 제공하고 있다는 점을 염두해 두어야 한다. 이러한 XBee 모듈의 설명은 다음 포스팅에서 이어서 설명하도록 하겠다.


'Electronic > Arduino' 카테고리의 다른 글

지그비 무선 통신하기  (13) 2016.01.26
XBee 모듈 정보 및 종류  (0) 2016.01.17
[Galileo] 초음파센서 사용하기  (0) 2016.01.08

게임 개발에 입문한지 얼마 되지는 않았지만 현재 도움받고 있는 사이트나 참고하고 있는 커뮤니티들을 공유하기 위해 포스팅해보았다. 개인적인으로 심심할 때마다 이런 사이트들을 방문하여 필요 기술이나 정보들을 알아가는 것이 개발하는데 있어서 큰 도움이 된다고 생각한다. 그럼 유니티 게임 개발과 관련된 사이트가 무엇이 있는지 살펴보자. 




1. 유니티 공식 홈페이지 - http://unity3d.com/kr

정말 유니티 게임 개발을 시작하기로 마음먹었다면 필수로 즐겨찾기 해야하는 1순위 사이트이다. 개발하는데 필요한 모든 자료가 있다고 보면 된다. 커뮤니티 또한 매우 잘 구축되어 있기 때문에 본인이 영어에 자신있다면 온갖 자료와 예제들을 섭렵할 수 있을 것이고 영어에 자신 없다고 해도 공식적으로 지원하는 한국 커뮤니티에서 정보를 찾을 수 있을 것이다. 또한 추가적으로 필자가 제일 추천하는 부분은 동영상 강좌 부분인데 한국어 자막도 잘 되어있고 무엇보다도 초보자가 보면서 따라하기 적합하게 잘 만들어 놓았다. 만약 유니티를 처음 다뤄 본다면 꼭 한번 보면서 따라해보길 추천한다.



2. 유니티 네이버 카페 - http://cafe.naver.com/unityhub

유니티코리아 공식 카페로 개발 관련 질의응답이나 기타 여러 정보를 얻을 수 있는 커뮤니티이다. 



3. 유니티 개발자 커뮤니티 페이스북 -  https://www.facebook.com/groups/unitykorea

SNS를 유용하게 사용할 수있는 하나의 방법. 가입해두면 주기적으로 다양한 정보를 얻을 수 있다.



4. 똘망 앱 스튜디오 - http://www.ibatstudio.com/unity5/

유니티 유료 강의 사이트. 유니티 사용법과 C# 강의 등을 제공하며 비록 유료이지만 강의 질은 훌륭하다. 하지만 초보자를 위한 강의이기 때문에 어느정도 유니티를 다뤄보았거나 공식 홈페이지의 동영상 강좌를 대략 이해하는 수준이라면 꼭 들을 필요는 없어보인다. 필자는 Unity 3D 강의를 들어보았으며 처음 공부할 때 어느정도 도움을 받을 수 있었다.



5. 게임코디 - http://www.gamecodi.com/

개발 관련 실무에 필요한 다양한 정보를 얻을 수 있다. 다만 게임 개발을 직접 해보았던 경험이 있는 실무자만 가입할 수 있다는 점은 아쉬운 부분. 쉽게 얻기 힘든 정보들이 많으니 참고해보자.



6. 게임소스 - http://gamesos.co.kr/?fromuid=54 

최근에 개설된 게임소스 공유 커뮤니티. 미션을 수행하거나 자신의 리소스를 공유하여 얻은 포인트로 다른 사람의 리소스를 구매할 수 있다. 아직 운영된지 얼마 되지 않아 자료가 부족하긴 하지만 컨셉도 좋고 기대되는 사이트 중 하나이다. 



7. 데브코리아 - http://devkorea.co.kr/

사이트소개의 내용을 빌려 표현하자면 한국 게임 개발자들의 정보 공유가 있는 진솔한 나눔의 공간이라고 한다. 개발과 관련된 여러 리소스나 오프라인 교육 정보, 질의응답 등의 정보를 얻을 수 있다.



8. 유니티3d스터디 - http://www.unity3dstudy.com/

유니티 절대강좌 책을 집필하신 이재현님의 사이트. 기초 강의 자료와 책에서 설명하지 못했던 보충 자료 등 참고할만한 부분들이 많다. 이 책으로 공부하고 있다면 이해하는데 있어서 도움이 많이 될 것이다.


앞서 wiringPi 라이브러리를 활용하여 라즈베리파이에서 실행할 수 있는 프로그램을 간단히 코딩해 보았는데 그렇다면 이렇게 개발한 프로그램을 부팅할 때 마다 자동으로 실행시켜 주려면 어떻게 해야할까? 이 문제는 의외로 코드 몇줄 추가하는 것 만으로 간단히 해결할 수 있다. 리눅스 환경에서는 프로그램을 자동으로 실행시켜 줄 수 있는 다양한 방법을 지원하므로 각기 알맞는 방법을 알아보고 사용해보자.



1. rc.local


자동실행 방법 중에 간단하면서도 효과적인 방법 중 하나로서 여기에 명령을 적어주게 되면 라즈베리파이가 부팅시에 자동으로 root 권한을 가지고 프로그램을 실행시켜준다. 주의해야할 점으로는 시스템과 관련된 명령을 입력할 경우에 rc.local의 실행이 더 빠르기 때문에 실행되지 않을 수 있으며 프로그램에 에러가 있는 상태에서 명령어 뒤에 & 문자를 입력하지 않을 경우에는 부팅이 완료되지 않을 수 있으므로 유의해야 한다. 


  $ sudo nano /etc/rc.local


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will “exit 0” on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.
# Print the IP address
_IP=$(hostname -I) || true
if [ “$_IP” ]; then
printf “My IP address is %sn” “$_IP”
fi
/home/pi/Desktop/Work/usbSerial & 
exit 0
cs


파일을 열면 다음과 같은 내용이 보일 것이다. 여기서 추가하고 싶은 명령어를 'fi' 와 'exit 0' 사이에 입력하면 된다. 앞서 언급했던것 처럼 rc.local은 root권한을 가지기때문에 sudo 나 su를 입력할 필요가 없다.(여기서 sudo가 쓰이는 경우는 다른 사용자로 프로그램을 실행시킬 경우에만 사용됨) 따라서 실행할 프로그램의 경로만 적어준 뒤에 &기호를 추가하면 자동실행 등록이 완료된다. &는 등록한 프로그램과 시스템 부팅이 별개의 프로세스로 진행되도록 분리해주는 역할을 한다.



2. LXDE


LXDE란 리눅스 환경에서 사용할 수 있는 오픈소스 데스크탑 환경을 의미하며 쉽게 말해 라즈비안에서 startx 명령어를 통해 나타나는 GUI환경을 의미한다. 이 방법은 라즈베리파이가 부팅되면서 xwindow 실행시 자동으로 실행하도록 설정해주는 방식이며 앞서 언급한 rc.local 자동실행보다 한 박자 느리게 실행된다. 설정 방법은 매우 간단하며 다음과 같은 명령어를 통해 파일을 읽어온 뒤 @문자를 붙인상태에서 실행할 프로그램의 경로를 지정해주면 된다. 경로를 설정할 때는 밑의 @xscreensaver 라인 전에 적어야 한다.


  $ sudo nano /etc/xdg/lxsession/LXDE-pi/autostart


1
2
3
@lxpanel --profile LXDE-pi
@pcmanfm --desktop --profile LXDE-pi
@xscreensaver -no-splash
cs




3. 스크립트 파일


보통 특정 프로그램을 가동할때 많이 사용하는 방식이며 부팅시에 스크립트가 자동으로 실행되는 폴더인 profile.d 경로에 원하는 파일을 만들어서 사용할 수 있다. 활용 방법은 2가지가 있으며 직접 /etc/profile.d 경로에 들어가 스크립트 파일을 넣어 자동으로 실행하게 하거나 profile 파일을 편집하여 스크립트 파일을 직접 실행시키게 할 수 있다. 


  $ sudo nano /etc/profile


해당 파일의 맨 마지막 라인에 .을 찍고 한칸 띄어쓰기 한 후 실행할 스크립트 파일의 경로를 적어주면 된다.

ex) . /home/pi/Desktop/Work/usbSerial.sh


이전에 아두이노에서 설정한 문자열을 라즈베리파이를 통해 Serial로 연결하여 수신받는 예제를 확인해 보았다. 이번에는 반대로 라즈베리파이에서 텍스트파일을 읽어와 아두이노에 뿌려줄 수 있는 통신을 구축해보도록 하자. 필자의 경우에는 라즈베리파이에 있는 파일을 아두이노 SD카드에 전송하고자하는 특수한 목적 때문에 본 예제를 활용했을뿐 실상 잘 쓰이는 방법이 아니기 때문에 그냥 이렇게도 가능하구나 정도만 이해하고 넘어가도 될 듯 하다.


예제의 경우 이전과 같은 예제를 활용하였으며 파일을 읽어 아두이노에 전송하기 위해 약간의 수정을 가했다. 따라서 수정된 부분에 대한 설명을 위해 C언어 파일 입출력에 대한 간단한 개념을 기술하였고 이를 통해 아두이노와 직접 통신하는 부분까지 진행해보자.



1. 파일 문자열 송신 예제


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
#ifdef RaspberryPi 
#include <stdio.h> //for printf
#include <stdint.h> //uint8_t definitions
#include <stdlib.h> //for exit(int);
#include <string.h> //for errno
#include <errno.h> //error output
#include <wiringPi.h>
#include <wiringSerial.h>
 
char device[]= "/dev/ttyACM0";
int fd;
unsigned long baud = 9600;
unsigned long time=0;
 
char strHello[] = "HELLO";
char cTemp[512= {0};
int ch;
char Endc;
 
//prototypes
int main(void);
void loop(void);
void setup(void);
 
void setup(){
 
  printf("%s \n""Raspberry Startup!");
  fflush(stdout);
 
  //get filedescriptor
  if ((fd = serialOpen (device, baud)) < 0){
    fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ;
    exit(1); //error
  }
 
  //setup GPIO in wiringPi mode
  if (wiringPiSetup () == -1){
    fprintf (stdout, "Unable to start wiringPi: %s\n", strerror (errno)) ;
    exit(1); //error
  }
}
 
// main function for normal c++ programs on Raspberry
int main(){
  setup();
  FILE * fp=fopen("/home/pi/Desktop/Work/transfer.txt","rt");
  if(fp==NULL){
    printf("file open fail\n");
    return -1;
}else{  
   printf("file open success\n"); 
   while(fgets(cTemp, sizeof(cTemp),fp) != NULL){
      serialPuts (fd, cTemp);
      printf(cTemp);
}
  
if(feof(fp) != 0){
    printf("file upload success\n");
}
 else
    printf("file upload fail\n");
 fclose(fp);
}
 
  return 0;
}
 
#endif //#ifdef RaspberryPi
 
 
cs

예제를 보면 아래 int main() 부분만 다르다는 것을 알 수 있다. 동작 순서를 간단히 언급하자면 설정된 경로의 텍스트 파일을 읽어와 각 줄단위로 읽고 이를 아두이노로 전송하며 만약 파일의 끝부분에 도달했을 경우 통신을 마치게 되는 구조이다. 그럼 각 함수에 대해 간단하게 설명하도록 하겠다.


2. 코드 설명


  FILE * fp=fopen("transfer.txt","rt")


C언어 프로그램상에서 파일에 저장되어 있는 데이터를 읽기 위해서는 데이터가 이동할 수 있는 다리 역할을 할 수 있는 스트림을 형성해야 한다. 쉽게 말해 파일로부터 데이터를 읽을 수 있는 최소한의 준비를 해주는 과정이라고 생각하면 된다.  따라서 위 fopen 함수는 스트림 형성을 요청하는 호출문 역할을 하며 괄호 안에 첫번째 인자의 경우 읽어들일 파일의 경로를 뜻하고 두번째 인자는 형성할 스트림의 종류를 뜻하며 입력스트림과 출력스트림 이렇게 2가지 형태가 존재한다. 위 코드는 "rt" 로 설정하였으므로 입력스트림을 뜻하며 파일의 데이터를 읽을 수 있는 반면에 쓰지는 못하기 때문에 만약 데이터를 쓰기 원한다면 별도로 출력스트림을 다시 형성해야 한다. C언어에서는 이러한 개념을 바탕으로 총 6가지 스트림으로 세분화 할 수 있다.


 

내용

   오직 읽기만 가능

w

   오직 쓰기만 가능

   만약 파일이 존재하지 않으면 새로운 파일을 생성해서 데이터 쓰기

   만약 파일이 존재하면 기존의 데이터를 지우고 데이터 쓰기 

a

   w 모드와 달리 파일이 존재하면 파일 끝에 덧붙여 데이터 추가

r+ 

   읽기와 쓰기 가능

   만약 파일이 존재하면 기존의 데이터를 지우지 않고 데이터 덮어 쓰기

w+

   읽기와 쓰기 가능

   만약 파일이 존재하면 기존의 데이터를 지우고 데이터 쓰기

a+

   읽기와 쓰기 가능 (쓰기의 경우 a 모드와 특징이 같다.)


 "rt" 에서 뒤의 t는 텍스트모드를 뜻하며 t의 텍스트모드와 b의 바이너리모드가 있다고만 이해하고 넘어가자. 


  char *fgets(char *string, sizeof(*string), File *stream)


위 함수는 텍스트 파일에 저장된 문자를 줄 단위로 읽어들어와 반환하는 함수로서 첫번째 인자인 *string은 입력 받은 문자열을 저장할 포인터(읽은 데이터를 잠시 저장하는 공간이라고만 생각하자)를 뜻하고 두번째 인자인 sizeof()는 입력 받을 문자의 수를 설정하는 것이며 세번째 인자인 파일 포인터는 형성한 스트림의 이름을 뜻한다.  이 함수는 읽어드린 문자열에 대한 포인터를 반환하며 파일의 끝에 도달하거나 오류가 발생할 경우 NULL을 반환한다.


  void serialPuts (int fd, char *s) 


위 함수는 wiringPi의 입출력 함수중 하나로 쉽게 설명하자면 fgets로 저장한 문자열을 fd(여기서 fd는 시리얼 통신할 디바이스라고 생각해두자)로 전송하게 된다. 사실 위 함수만 제대로 활용해도 아두이노로 문자열을 송신할 수 있지만 여기서는 파일입출력까지 같이 응용하여 예제를 만들어 보았다. wiringPi가 지원하는 함수에 대해 보다 자세히 알고싶다면 공식 홈페이지를 참고하도록 하자.


http://wiringpi.com/reference/serial-library 


마지막으로 fopen을 통해 파일을 개방하였다면 fclose 함수를 통해 파일을 꼭 닫아주어야 한다. 그 이유는 스트림을 형성하기 위해서는 시스템에서 메모리를 할당해야 하는데 파일을 닫아주지 않으면 메모리가 할당된 채로 유지되면서 손실이 일어나기 때문이다. 쉽게 말해 메모리가 유출되는 것을 막기 위한 것으로 이해하면 된다.



3. 아두이노 코드


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
char cTemp;
String sReal = "";
 
void setup()
{
  Serial.begin(9600);
}
void loop()
{
    while(Serial.available()){
      cTemp = Serial.read();
      sReal.concat(cTemp);
      if(cTemp=='\n')
      {
        Serial.print(sReal);
        sReal="";
      }
    }
}
 
cs


아두이노 소스코드는 간단하게 구현해보았는데 여기서 유의해야할 것이 Serial.read() 함수이다. 라즈베리파이의 경우 문자를 한 줄로 읽거나 쓰는 것이 가능한데 아두이노는 한 글자씩 밖에 읽기가 불가능하다. 때문에 이러한 문제점을 해결하기위해 필자의 경우에는 while문을 활용하여 라즈베리파이를 통해 송신된 문자열을 각 문자 단위로 읽고 이를 concat 함수 (문자와 문자를 이어주는 역할을 한다.)를 사용하여 한 문장으로 만든 뒤에 해당 문자열의 끝을 나타내는 개행문자가 입력으로 들어올 시 문자열을 출력하고 문자열 변수를 초기화 하는 형태로 코드를 구현해보았다. 나름대로 구현이 잘 되긴 했지만 완성도면에서 미흡하다고 생각하기 때문에 후에 더 나은 방향으로 수정이 필요해 보인다.



4. 결과 확인


컴파일 방법은 기존과 동일하며 읽어올 파일을 형성하고 그 경로를 지정하여 예제 코드에 반영해주자.



아두이노와 라즈베리파이 기초 강좌 교재이다.


시소드림이라는 회사에서 코딩키트라는 제품을 출시하면서 무료로 배포한 강의 교재인데 기초개념과 함께 전자회로적 지식까지 같이 서술하고 있어서 라즈베리파이를 처음 다루는 초보자에게 적합하다. 예제소스의 경우에는 코딩키트 제품 없이도 아두이노나 라즈베리파이와 기타 센서만으로 실습해볼 수 있으며 한번 정도 읽어보는 것을 추천한다. 


필자의 경우 이 회사에서 주최하는 라즈베리파이 강의를 실제로 들어본 경험이 있으며 도움이 되었던 걸로 기억한다. 물론 무료 강의가 아니어서 가격이 조금 비싼감이 있었지만...


기초 개념잡는데 도움이되길 바란다.



Codingbook_Part1_ARD_1_V10_20150828.pdf


Codingbook_Part2_RASPI_1_V10_20150828.pdf


1. 초음파센서란?

 

초음파란 사람의 귀에 들리지 않을 정도로 높은 주파수 (20 kHz 이상)의 소리를 말한다. 이와 같은 특성을 이용한 것이 초음파센서로 음파를 쏘아올리고 반사되어 오는 음파까지의 시간차를 거리로 계산하여 측정하는 방식으로 동작된다. 이번에 실습해볼 예제는 HC-SR04라는 초음파센서를 활용하여 거리를 측정하는 것이며 이를 통해 초음파센서의 기초 원리를 이해하고 갈릴레오보드의 활용법을 숙달한다.


동작 전압

5V

동작 전류

15mA

동작 주파수

40Hz

발생 주파수

40kHz

측정 거리

최대 4m

측정 각도

15

 

 

2. 동작 원리

 

초음파센서는 두 개의 눈으로 구성되어 있으며, 하나는 초음파를 발생시켜 송신(Trig)하는 기능을 수행하고, 나머지 하나는 송신된 초음파의 신호를 수신(Echo)하는 기능을 수행하게 된다. 따라서 두 개의 눈이 서로 송신하고 수신되는 시간의 차이에 따라 물체와의 거리를 계산하는 방식으로 동작하며 주파수가 높은 만큼 파장이 매우 짧기 때문에 거리 방향의 분해력이 우수하고 정밀도가 높은 계측을 할 수 있다. 이러한 센서의 원리 때문에 거리감지센서나 레인지센서라고도 불린다HC-SR04 초음파센서의 경우에는 4개의 핀으로 구성되어 있으며 각각 순서대로 Vcc, Trig, Echo, Gnd 이다.

 


 

3. 준비물

 

갈릴레오보드, HC-SR04, 브레드보드, 점퍼선



4. 회로도


Vcc부분에 5V의 전원을 인가하고 Gnd끼리 연결해준다. 그리고 D2D3를 각각 echotrig순으로 연결하면 기본적인 회로 구성이 완료된다.

 

 

5. 동작 방법

 

동작 설명에 앞서 어떤 보드를 사용하여 회로를 구성할 것인가가 중요하다. 필자는 초기의 갈릴레오보드1을 사용하였는데 처음에 초음파센서를 활용한 결과값이 제대로 나오지 않아 많은 시간을 허비했다. 분명 센서는 문제가 없었으며 코드 부분도 이상이 없음에도 불구하고 결과가 0m를 보여주는 현상이 일어났다. 때문에 보드에 무엇인가 문제가 있다고 판단하여 갈릴레오보드의 데이터시트를 확인해 보았는데 여기서 문제를 발견할 수 있었다. 바로 갈릴레오보드의 초기 모델은 GPIO핀의 동작주파수 범위가 매우 낮기 때문에 초음파센서에 나오는 출력 주파수 40kHz를 보드 자체에서 읽지 못하여 0m가 계속해서 나타나는 것이었다.

이러한 문제는 의외로 단순하게 해결할 수 있는데 갈릴레오보드에서는 동작주파수 범위가 큰 Fast I/O 핀이 따로 설정할 수 있다. 여기서는 D2D3핀이 해당되며 해당 핀을 사용하고 pinMode()함수를 사용하여 기존의 입력이나 출력을 INPUT_FASTOUTPUT_FAST로 설정하면 큰 주파수 범위의 출력에서도 무리없이 사용할 수 있다. 위 문제는 갈릴레오보드 초기모델에서만 나타나며 갈릴레오보드2나 아두이노보드에서는 동작주파수 범위가 넓기 때문에 문제없이 동작하여 굳이 Fast I/O를 사용할 필요가 없다.



동작 방법은 앞에서 설명했던 초음파의 원리를 응용한 것으로 센서에서 음파를 발생시키고 물체에 반사되어 되돌아오기까지의 시간을 측정하여 거리로 표시해주는 방식이다. 여기에서 중요한 역할을 하는 것이 바로 pulseIn() 함수이다. 이 함수는 해당 출력이 HIGHLOW가 되는 순간까지의 시간을 계산해주는 함수로서 초음파센서의 음파가 되돌아오는 시간을 계산해주는 역할을 한다. 또한 밑의 소스코드에서 pulseIn()함수로 측정된 값을 58로 나누어주고 있음을 알 수 있는데 그 이유는 소리의 속도가 대략 340m/s 이기 때문에 1cm를 이동하는데 걸리는 시간이 29.155 마이크로초가 된다. 따라서 측정된 시간 값은 음파가 갔다가 되돌아오는 시간이기 때문에 2로 나누어주고 여기에 방금 계산한 29.155를 다시 나눠주게 되면 우리가 원하는 거리의 값을 나타낼 수 있다.




6. 소스 코드


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#define trig 3 // trig 단자를 Digital 3번 단자에 연결
#define echo 2 // echo 단자를 Digital 2번 단자에 연결
long duration, distance;
 
void setup() {
  Serial.begin (9600); // Serial 통신
  pinMode(trig, OUTPUT_FAST); // trig 단자를 빠른 출력모드로 설정
  pinMode(echo, INPUT_FAST); // echo 단자를 빠른 출력모드로 설정
}
 
void loop() {
  digitalWrite(trig, LOW); // Trig 단자 LOW로 설정
  delayMicroseconds(2);
  digitalWrite(trig, HIGH); // Trig 단자 HIGH로 설정
  delayMicroseconds(10);
  digitalWrite(trig, LOW); // Trig 단자 LOW로 설정
 
  duration = pulseIn(echo, HIGH); // pulseIn 함수 호출
  distance = duration / 58// 반환값을 cm로 단위 변환
  Serial.print(distance); // 거리 표시
  Serial.println(" cm");
  delay(1000);
}
 
cs



6. 결과 화면


  


 

 

'Electronic > Arduino' 카테고리의 다른 글

지그비 무선 통신하기  (13) 2016.01.26
XBee 모듈 정보 및 종류  (0) 2016.01.17
지그비 통신의 개념 (네트워크의 이해)  (8) 2016.01.16

라즈베리파이와 아두이노 사이에는 SPI, I2C, UART 등 다양한 통신 방법들을 적용할 수 있다. 하지만 아두이노의 입출력 핀 전압이 5V인 반면에 라즈베리파이의 GPIO 입출력 핀 전압은 3.3V이기 때문에 직접적으로 결선할 경우 문제가 발생하게 된다. 따라서 여기서는 가장 간편하게 사용할 수 있는 Serial(UART) 통신을 활용해보자. 


시리얼통신은 라즈베리파이와 아두이노를 USB케이블로 연결하는 것으로 간단하게 구현할 수 있으며 전압에 따른 문제 또한 발생하지 않는다.



1. 아두이노 Idle 설치하기


  $ sudo apt-get install arduino


패키지 설치를 위해 라즈베리파이에 update 명령어를 통해 업데이트 시켜주고 위 명령어를 입력하여 아두이노 패키지를 설치한다. 이때 설치된 패키지는 권한을 아직 가지고 있지 않은 상태이므로 바로 실행시키지 말고 아래 명령어를 입력하여 아두이노 패키지가 시리얼 포트에 엑세스 할 수 있는 권한을 얻도록 한다.


  $ sudo usermod -a -G tty pi

  $ sudo usermod -a -G dialout pi


위 과정을 완료하였다면 아두이노 패키지가 성공적으로 라즈베리파이에 설치되었다. 이제 아두이노를 실행시키고 라즈베리파이에 아두이노를 연결한 후에 포트를 설정하고 ("/dev/ttyACM0" 일 것이다.) blink 예제를 업로드하여 제대로 동작하는지 확인해본다.




2. 시리얼 통신하기


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/*
 Pi_Serial_test.cpp - SerialProtocol library - demo
 Copyright (c) 2014 NicoHood.  All right reserved.
 Program to test serial communication
 
 Compile with:
 sudo gcc -o Pi_Serial_Test.o Pi_Serial_Test.cpp -lwiringPi -DRaspberryPi -pedantic -Wall
 sudo ./Pi_Serial_Test.o
 */
 
// just that the Arduino IDE doesnt compile these files.
#ifdef RaspberryPi 
 
//include system librarys
#include <stdio.h> //for printf
#include <stdint.h> //uint8_t definitions
#include <stdlib.h> //for exit(int);
#include <string.h> //for errno
#include <errno.h> //error output
 
//wiring Pi
#include <wiringPi.h>
#include <wiringSerial.h>
 
// Find Serial device on Raspberry with ~ls /dev/tty*
// ARDUINO_UNO "/dev/ttyACM0"
// FTDI_PROGRAMMER "/dev/ttyUSB0"
// HARDWARE_UART "/dev/ttyAMA0"
char device[]= "/dev/ttyACM0";
// filedescriptor
int fd;
unsigned long baud = 9600;
unsigned long time=0;
 
//prototypes
int main(void);
void loop(void);
void setup(void);
 
void setup(){
 
  printf("%s \n""Raspberry Startup!");
  fflush(stdout);
 
  //get filedescriptor
  if ((fd = serialOpen (device, baud)) < 0){
    fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ;
    exit(1); //error
  }
 
  //setup GPIO in wiringPi mode
  if (wiringPiSetup () == -1){
    fprintf (stdout, "Unable to start wiringPi: %s\n", strerror (errno)) ;
    exit(1); //error
  }
 
}
 
void loop(){
  // Pong every 3 seconds
  if(millis()-time>=3000){
    serialPuts (fd, "Pong!\n");
    // you can also write data from 0-255
    // 65 is in ASCII 'A'
    serialPutchar (fd, 65);
    time=millis();
  }
 
  // read signal
  if(serialDataAvail (fd)){
    char newChar = serialGetchar (fd);
    printf("%c", newChar);
    fflush(stdout);
  }
 
}
 
// main function for normal c++ programs on Raspberry
int main(){
  setup();
  while(1) loop();
  return 0;
}
 
#endif //#ifdef RaspberryPi
cs

위 코드는 wiringPi 라이브러리를 활용하여 아두이노와 통신할 수 있는 예제 코드이다. 여기서 "/dev/ttyACM0" 부분은 아두이노가 연결된 장치의 포트명을 말하는 것으로 가끔씩 에러가 발생할 경우 ACM1, ACM2 이렇게 순차적으로 증가할 수 있으니 유의하도록 한다. 라즈베리파이의 USB포트 구성 목록을 확인하려면 다음 과 같은 명령어를 입력하면 된다.

  $ dmesg|tail



그럼 이제 위 소스코드를 컴파일한다. 필자는 소스코드의 파일명을 test.c로 하였으며 hello라는 이름으로 컴파일했다. 컴파일할 때는 파일이 저장된 디렉토리로 들어간 후에 하도록 한다.


  $ sudo gcc test.c -o hello -l wiringPi -DRaspberryPi

  $ sudo ./hello


아래는 간단하게 구현한 아두이노 소스코드이며 1초마다 라즈베리파이로 Hello World 문자를 송신할 것이다.


1
2
3
4
5
6
7
8
void setup(){  
  Serial.begin(9600);
 
void loop(){
  Serial.println("Hello World");
  delay(1000);
}
cs


3. 결과 확인


위와 같은 결과가 나오면 성공이다. 여기서 실행된 프로그램을 종료하려면 Ctrl + C를 눌러주면 된다. 만약 종료를 하지 않을경우 터미널을 종료해도 계속해서 프로그램이 동작하며 아두이노를 다시 연결시 ttyACM0 포트는 사용하지 못하기 때문에 테스트 종료시에 유의하도록 한다.


라즈베리파이의 대표적인 운영체제인 라즈비안은 리눅스를 기반으로 하며 사용자가 손쉽게 프로그래밍 할 수 있도록 파이썬 언어를 지원한다. 하지만 여기에서는 기존 임베디드 환경에서 익숙한 언어인 C를 통해 개발할 수 있도록 wiringPi라는 라이브러리를 활용하여 라즈베리파이를 제어해보도록 하자. wiringPi 라이브러리는 I2C, SPI, UART 등의 통신을 제어할 수 있는 함수를 제공하며 GPIO포트에 대한 설정이나 프로그래밍을 가능하게 해준다.



1. 패키지 설치 준비


  $ sudo apt-get update

  $ sudo apt-get upgrade


새로운 패키지를 설치하기 전에 꼭 해야하는 부분이 바로 업데이트이다. 위 명령은 패키지 관리 서버로부터 이용 가능한 프로그램 패키지의 목록을 최신버전으로 업데이트 해주며 갱신된 패키지 목록을 통해 새로운 버전으로 설치해준다.



2. wiringPi 설치하기


  $ sudo apt-get install git-core

  $ git clone git://git.drogon.net/wiringPi


wiringPi 설치를 위해 소스 관리 툴인 git을 다운로드하고 git을 이용하여 wiringPi 라이브러리를 다운로드 한다. 위 주소는 실제 git주소를 통해 다운로드하기 때문에 대소문자에 주의해서 입력하도록 한다.

또한 위 명령어는 해당 폴터를 통째로 복사해오기 때문에 홈디렉토리에 wiringPi 폴터가 생성된다. 따라서 해당 디렉토리 이동 후에 사용자가 직접 설치하도록 하자.


  $ cd wiringPi

  $ ./build



3. wiringPi 설치 확인


  $ gpio -v

  $ gpio readall


제대로 설치가 되었는지 확인하기 위해 위 명령어를 입력하여 확인해본다.