본문 바로가기

Arduino

Arduino + Wifly (WiFi shield) (1-소개)










Arduino 로 무선 환경을 구성하는 가장 쉬운 방법은
역시 제품으로 나온 Shield를 구입해서 꽂는것입니다.

대부분의 Shield가 예제 스케치를 함께 제공하기 때문에 사용법에 대한 부담도 적습니다.
제 경험에 의하면 아두이노의 이.. 꽂고 구동시키는 행위는 레고의 마인드 스톰을 조작하는것 보다 더 쉬웠습니다.



Wifly shield


Arduino 무선을 위해서 이미 Zigbee, Bluetooth, Wifi 등의 쉴드가 나와 있습니다.
저는 그중에 지구에서는 어디든 컨트롤이 가능한 Wifi 를 구동시켜보고픈 마음에 Wifi실드를 찾아봤는데요
국내에서 구매할 수 있는 WiFi Shield는 사실상 Wifly 라는 이름은 가진 제품이 유일합니다.
아트로봇 에서 Shield치고는 13만원 이라는 거금을 주고 구입.
전자공학 지식이 있으면 wifi 모듈만 사다가 시리얼 컨트롤이 가능하게 구성할텐데 아쉬울 따름입니다.
참고로 쉴드에 포함되어 있는 RN-131C 모듈만 별도로 구매하면 디바이스마트에서 48,400원 이군요.


RN-131C


Wifly 소개

Wifly는 Sparkfun 이라는 해외 유명 전자부품 판매처에서 팔고 있는 제품입니다.
($89.95 라니 현지에서 사더라도 비싸군요 ㅎㅎ)

Wifly 소개 페이지
- Wifly Shield는 아두이노와 연결해서 802.11b/g 무선네트워크를 가능하게 합니다.
- Roving Network 사의 RN-131C 무선 모듈과 SC161S750 SPI-to-UART 칩을 사용합니다.
- 아두이노의 digital pin 10-13 번을 사용해서 SPI 통신을 합니다. (CS, MOSI, MISO, SCLK)
- 전원은 아두이노의 3.3V핀으로 공급받습니다.
- 프로토타입을 만들 수 있는 공간을 제공합니다.
- 원제품은 구입시 핀헤더는 포함되어 있지 않습니다. 6-8pin 재적층 가능한 핀헤더를 장착하면 됩니다.
   아트로봇에서 구입시에는 핀헤더를 같이 제공해줍니다.


 핀헤더를 납땜한후(망칠까바 ㅎㄷㄷㄷ) 아두이노와 결합



Wifly설치하기

Sparkfun에서 제공하는 관련 문서 링크입니다.

위 링크중 Experimental WiFly Arduino Library 를 누르면 Wifly library를 다운받을 수 있는 링크 페이지로 이동합니다. 현재 alpha 2 release 까지 나왔습니다.

git 도 공개되어 있네요. https://github.com/sparkfun/WiFly-Shield

해당 라이브러리는 다운 받은후 Arduino 의 library 디렉토리 아래에 풀어줍니다.

복사한후 Arduino 를 다시 실행시키면 File - Example 메뉴 아래에 Wifly를 테스트 해볼 수 있는 몇가지 샘플이 나타납니다.

 



웹서버, 클라이언트 예제. 자동접속, 공장초기화, 터미널통신 예제가 있습니다.



Wifly 동작시키기

그중에 SpiUartTerminal 가 Wifly의 전반적인 기능을 확인해 볼 수 있는 스케치입니다.
해당 스케치를 열어보면 아시겠지만. 단순히 RN-131C칩과 시리얼을 통해서 명령을 주고 받는 내용밖에 없습니다.

스케치를 업로드 한후 터미널을 열어보면 다음과 같은 문구를 볼 수 있습니다.

SPI UART on WiFly Shield terminal tool                                                                    
--------------------------------------                                      
                                                                            
This is a tool to help you troubleshoot problems with the WiFly shield.
For consistent results unplug & replug power to your Arduino and WiFly shield.
(Ensure the serial monitor is not open when you remove power.)
                                                           
Attempting to connect to SPI UART...                       
Connected to SPI UART.                                     
 * Use $$$ (with no line ending) to enter WiFly command mode. ("CMD")
 * Then send each command followed by a carriage return.
Waiting for input.


명령을 대기중인 상태이며 $$$을 입력하면 자동으로 명령을 입력할 수 있는 상태로 들어갑니다.

여기서부터는 데이터시트를 참고하여 필요한 명령어들을 처야 합니다.
몇가지 기본 명령어만 요약하면 다음과 같습니다.

명령어는 총 다섯개의 카테고리로 나눠집니다.
SET : 설정하는 명령어인데 바로 저장되고 효과가 나타납니다.
GET : 설정된 상태를 읽어서 보여줍니다.
STATUS : network interface 와 IP 등의 상태를 보여줍니다.
ACTION : scan, connect, disconnect등을 수행합니다.
FILE IO : Upgrade, 설저의 load save 등을 수행합니다.

좀더 자세한 내용은 위에 링크된 데이터시트를 살펴보시기 바랍니다.

실제로 ap에 접속하기 위해 제가 사용한 명령은 다음과 같습니다.
<2.23> show net //현재 Wifly상태를 보여줍니다.
SSid=AndroidAP
Chan=1
Assoc=OK
Rate=12, 24Mb
Auth=OK
Mode=OPEN
DHCP=OK,renew=269981
Boot=1779470
Time=FAIL
Links=1

<2.23> scan //주변AP검색
<2.23>
SCAN:Found 12
Num            SSID   Ch  RSSI   Sec    MAC Address     Suites
 1           AndroidAP 01 -45    Open 00:26:66:48:36:96   2104    0
 2            dell2 02 -56 WPA_Mix 10:12:e7:ef:69:51 AES/TKIPM-TKIP  3104    0
 3             dell1 06 -60     WEP 10:3e:e8:d3:20:fd   1104    4
 4                 ms 06 -61    Open 01:14:a0:c8:1a:12 AESM-AES  3104    0
 5               iptime 11 -78    Open 00:21:62:2d:f2:34    104    4
 6                   3i 11 -81 WPA2PSK 01:24:66:2e:e4:32 AESM-AES  1104    4

<2.23> join AndroidAP //AndroidAP에 접속합니다. 혹은 join #1이라고 해도 됨.
Auto-Assoc AndroidAP2 chan=1 mode=OPEN SCAN OK
Joining AndroidAP2 now..
<2.23> Associated!
DHCP: Start
DHCP in 127ms, lease=360000s
IF=UP
DHCP=ON
IP=192.168.159.2:2000
NM=255.255.255.0
GW=192.168.159.1
Listen on 2000

 

간단히 AndroidAP에 접속하고 ip를 받아온것을 확인 할 수 있습니다.



WiFly 웹서버예제
WiFly를 간단한 웹서버로 구동시켜보고 접속한 클라이언트에게 아날로그값을을 보여주는 예제.
WiFly에서 제공해주는 Arduino 용 Api들로 만들어진 예제입니다.
(API가 간단해도 너무 심하게 간단합니다.)

wifly 예제에서 WiFly_WebServer 스케치를 불러옵니다.
불러오면 Credentials.h 라는 헤더파일도 함께 열리는 것을 볼 수 있습니다.

#ifndef __CREDENTIALS_H__
#define __CREDENTIALS_H__
// Wifi parameters
char passphrase[] = "passphrase";
char ssid[] = "ssid";
#endif


여기에 접속할 AP의 ssid값과 암호가 설정되어 있을 경우 암호를 passphrase에 수정해서 적어줍니다.
암호가 없을경우 저 글자를 지워줘야 합니다.

해당 스케치를 Arduino 에 올린후 시리얼창을 열어보면
AP에 접속된후에 할당받은 IP 주소가 뜨게 됩니다.

약간 문제점이 있다면 서버에 접속하는 스케치부분은 함수 하나로 간단히 접속할 수 있도록 간편화 되어 있지만. 접속이 실패할 경우 무한히 대기한다는 점입니다. 타임아웃이나 retry값으로 조절을 해야할 것 같네요.
WiFly.join() 이 함수자체도 라이브러리를 살펴보면 그다지 똑똑한 함수는 아닙니다.
나중에 한번 고쳐봐야겠습니다.

  if (!WiFly.join(ssid, passphrase)) {
    while (1) {
      // Hang on failure.
    }
  }




응용
Wifly까지 장착했으니 아두이노에 날개는 달아준 셈인데...
아직 그럴싸한 아이디어가 떠오르지 않습니다.
간단히 Arduino Twitter 라이브러리를 활용해서 실내 온도를 트위터로 포스팅 해주는걸 구성해보았습니다.
(아트로봇 홈페이지를 참고했습니다)

다음 트위터 계정을 보시면 그 결과를 보실 수 있습니다.
http://twitter.com/watcher_bot1 (얘는 사람이 아니에요 ㅎㅎ)

 

 

Wifi로 온도를 포스팅하는
트위터봇!














 

  • 공대생 2011.12.13 15:12

    좋은가이드 감사합니다~

    혹시 질문도 받으시는지..
    전 지금 페이스북 app랑 아두이노랑 데이터를 주고받는걸 만들려고 하는데요
    datasheet보고 간단히 명령 설정만 해보다가.. 여기서 Wifly라이브러리를 보고 사용해볼려고 하는데요

    Wifly 라이브러리를 받아서 예제를 실행해봤는데 에러가 장난 아니게 뜨더라구요

    WProgram.h를 찾을수 없다고 하고.. boolean이 없다 print가 없다.. byte가 없다..

    WIfly 라이브러리 말고도 더 추가해야될게 있나요??

    아니면 스케치는 1.0 버젼인데 혹시 버젼문제인가요.. 꼭좀 알려주세요 . ㅜㅜ

    • Favicon of https://printk.tistory.com BlogIcon Pulse@ 2011.12.13 17:11 신고

      전 아직 Android 1.0 을 설치만 해놓고 쓰고있진않습니다. 몇가지 라이브러리가 말씀하신것 처럼 오류가 나서요.
      아마 이전버전 쓰시면 이상 없으실거구요. 혹시 1.0 에서 꼭 써야 한다면 아래와 같이 수정하시면 됩니다.
      그냥 컴파일되서 돌아가게만 고친것이므로 좋은 수정 방법은 아닙니다.
      diff --git a/libraries/WiFly/Client.cpp b/libraries/WiFly/Client.cpp
      index 6023199..e7b6d23 100644
      --- a/libraries/WiFly/Client.cpp
      +++ b/libraries/WiFly/Client.cpp
      @@ -36,10 +36,10 @@ Client::Client(const char* domain, uint16_t port) :
      }


      -void Client::write(byte value) {
      +size_t Client::write(byte value) {
      /*
      */
      - _WiFly.uart.write(value);
      + return _WiFly.uart.write(value);
      }


      @@ -50,10 +50,10 @@ void Client::write(const char *str) {
      }


      -void Client::write(const uint8_t *buffer, size_t size) {
      +size_t Client::write(const uint8_t *buffer, size_t size) {
      /*
      */
      - _WiFly.uart.write(buffer, size);
      + return _WiFly.uart.write(buffer, size);
      }


      diff --git a/libraries/WiFly/Client.h b/libraries/WiFly/Client.h
      index 898532e..69b7ae7 100644
      --- a/libraries/WiFly/Client.h
      +++ b/libraries/WiFly/Client.h
      @@ -18,9 +18,9 @@ class Client : public Print {

      boolean connect();

      - void write(byte value);
      + size_t write(byte value);
      void write(const char *str);
      - void write(const uint8_t *buffer, size_t size);
      + size_t write(const uint8_t *buffer, size_t size);

      int available();
      int read();
      diff --git a/libraries/WiFly/SpiUart.cpp b/libraries/WiFly/SpiUart.cpp
      index bcdacc9..3b0c70b 100644
      --- a/libraries/WiFly/SpiUart.cpp
      +++ b/libraries/WiFly/SpiUart.cpp
      @@ -189,7 +189,7 @@ int SpiUartDevice::read() {
      }


      -void SpiUartDevice::write(byte value) {
      +size_t SpiUartDevice::write(byte value) {
      /*

      Write byte to UART.
      diff --git a/libraries/WiFly/SpiUart.h b/libraries/WiFly/SpiUart.h
      index bd91382..40d12f0 100644
      --- a/libraries/WiFly/SpiUart.h
      +++ b/libraries/WiFly/SpiUart.h
      @@ -59,7 +59,7 @@ class SpiUartDevice : public SpiDevice, public Print {
      void begin(unsigned long baudrate = BAUD_RATE_DEFAULT);
      byte available();
      int read();
      - void write(byte value);
      + size_t write(byte value);
      void write(const char *str);
      #if ENABLE_BULK_TRANSFERS
      void write(const uint8_t *buffer, size_t size);
      diff --git a/libraries/WiFly/_Spi.h b/libraries/WiFly/_Spi.h
      index 82eac05..b28bf47 100644
      --- a/libraries/WiFly/_Spi.h
      +++ b/libraries/WiFly/_Spi.h
      @@ -5,7 +5,8 @@
      #ifndef ___SPI_H__
      #define ___SPI_H__

      -#include <WProgram.h>
      +//#include <WProgram.h>
      +#include <Arduino.h>

      #include <pins_arduino.h>

  • 공대생 2011.12.16 17:23

    ssid를 AndroidAP로 설정해놓고

    set wlan join 1
    set ip dhcp 1

    이렇게 설정해놓으면
    ssid와 일치하는 AP를 찾아서 접속 하는거 맞나요??

    이랬더니


    <2.21>
    ÿ*Reboot*WiFly Ver 2.21, 07-11-2010
    MAC Addr=00:06:66:14:a2:59
    Auto-Assoc AndroidAP chan=13 mode=NONE FAILED
    *READY*

    이렇게 NONE FAILED가 뜨는 이유는 뭘까요..
    아예 AndroidAP가 안잡히는거 같은데 혹시 이유를 아시나요??

  • 초보에영 2012.06.13 21:46

    지금 아두이노 mega와 wifly 쉴드를 이용하여(spiuartTerminal 예제를 이용하여) 무선 인터넷 접속후 웹 서버와 연결하여 데이터를 주고 받는 것을 하고 있어요.. 매뉴얼을 보면서 하고 있는데 웹 서버와 연결까지는 되었는데 데이터를 주고 받는 방법을 모르겠어요 어떤식으로 진행을 해야 할지 방법을 상세히 알려 주시면 정말 정말 감사할께요.. 이쪽 분야도 아닌데 도전하는게 이리 힘들줄은 코딩도 모르겠구 에휴.. 살려주세욤 ㅠ

    • Favicon of https://printk.tistory.com BlogIcon Pulse@ 2012.06.14 11:29 신고

      웹서버를 구동시켜서 데이터를 주고 받으려면
      html로 입력 폼을 만들면 가능합니다.

      예전에 제가 테스트 해본건데 아래 스케치 수정해서
      한번 돌려보세요. 지금은 제가 테스트할 환경이 안되어서 정확한 코드인지 모르겠습니만..

      /*
      * Web Server
      *
      * (Based on Ethernet's WebServer Example)
      *
      * A simple web server that shows the value of the analog input pins.
      */

      #include "WiFly.h"
      #include "Credentials.h"

      String readString = String(100); // string for fetching data from address
      boolean Pin3ON = false; // Status flag
      boolean Pin4ON = false;


      Server server(80);

      void setup() {
      WiFly.begin();

      if (!WiFly.join("AndroidAP2")) {
      while (1) {
      // Hang on failure.
      }
      }

      Serial.begin(9600);
      Serial.print("IP: ");
      Serial.println(WiFly.ip());

      server.begin();
      }

      void loop() {
      Client client = server.available();
      if (client) {
      // an http request ends with a blank line
      boolean current_line_is_blank = true;
      while (client.connected()) {
      if (client.available()) {
      char c = client.read();
      // if we've gotten to the end of the line (received a newline
      // character) and the line is blank, the http request has ended,
      // so we can send a reply
      if (c == '\n' && current_line_is_blank) {
      // send a standard http response header

      client.println("HTTP/1.1 200 OK");

      client.println("Content-Type: text/html");

      client.println();

      client.print("<html><head>");

      client.print("<title>Arduino Webserver Poldi</title>");

      client.println("</head>");

      client.print("<body bgcolor='#444444'>");

      //---Überschrift---
      client.println("<br><hr />");

      client.println("<h1><div align='center'><font color='#2076CD'>Arduino Webserver 1.0 by Poldi</font color></div></h1>");

      client.println("<hr /><br>");
      //---Überschrift---

      //---Ausgänge schalten---
      client.println("<div align='left'><font face='Verdana' color='#FFFFFF'>Ausg&auml;nge schalten:</font></div>");

      client.println("<br>");

      client.println("<table border='1' width='500' cellpadding='5'>");

      client.println("<tr bgColor='#222222'>");

      client.println("<td bgcolor='#222222'><font face='Verdana' color='#CFCFCF' size='2'>Ausgang 3<br></font></td>");

      client.println("<td align='center' bgcolor='#222222'><form method=get><input type=submit name=3 value='einschalten'></form></td>");

      client.println("<td align='center' bgcolor='#222222'><form method=get><input type=submit name=3 value='ausschalten'></form></td>");

      if (Pin3ON)
      client.println("<td align='center'><font color='green' size='5'>ON");
      else
      client.println("<td align='center'><font color='#CFCFCF' size='5'>OFF");

      client.println("</tr>");

      client.println("<tr bgColor='#222222'>");

      client.println("<td bgcolor='#222222'><font face='Verdana' color='#CFCFCF' size='2'>Ausgang 4<br></font></td>");

      client.println("<td align='center' bgcolor='#222222'><form method=get><input type=submit name=4 value='einschalten'></form></td>");

      client.println("<td align='center' bgcolor='#222222'><form method=get><input type=submit name=4 value='ausschalten'></form></td>");

      if (Pin4ON)
      client.println("<td align='center'><font color='green' size='5'>ON");
      else
      client.println("<td align='center'><font color='#CFCFCF' size='5'>OFF");

      client.println("</tr>");


      client.println("</tr>");

      client.println("</table>");


      client.println("<br>");

      client.println("<form method=get><input type=submit name=all value='Alles aus'></form>");

      client.println("</body></html>");
      // output the value of each analog input pin
      for (int i = 0; i < 6; i++) {
      client.print("analog input ");
      client.print(i);
      client.print(" is ");
      client.print(analogRead(i));
      client.println("<br />");
      }
      break;
      }
      if (c == '\n') {
      // we're starting a new line
      current_line_is_blank = true;
      } else if (c != '\r') {
      // we've gotten a character on the current line
      current_line_is_blank = false;
      }
      }
      }
      // give the web browser time to receive the data
      delay(100);
      client.stop();
      }
      }

  • 이승태 2012.07.26 12:41

    안녕하세요.
    아두이노와 wifi 결합을 통해 app을 제어할수 있도록 하고싶은데요
    wifly와 결합시키려면 어떤 아두이노 보드를 사야 하나요?
    또 만약 wifly를 결합시켜 무선통신이 가능한 상태로 PC의 웹이 아닌
    스마트폰의 App과 연동시킬수 있나요??
    초보라서 엉뚱한 질문이더라도 답변해주시면 감사하겠습니다..ㅜ

    • Favicon of https://printk.tistory.com BlogIcon Pulse@ 2012.08.03 19:03 신고

      아두이노는 두에밀라노브나 우노 사시면 문제 없을겁니다.
      스마트폰에서 http로 접속하는건 별다를게 없으니 잘 될거구요. 다른 프로토콜 같은건 저도 안해봐서 잘 모르겠네요.

  • NIck 2013.05.03 18:47

    안녕하세요
    아두이노 개발을 처음 시작한 학생입니다

    다름아니라 저는 스케치 버전을 1.0이상을 사용해야만 하는 상황인데요,
    해당 쉴드는 모든 코드가 0023 이하 버전이라 도저히 뭐가 뭔지 모르는 상황입니다

    마이그레이션이라는걸 해야 한다고 하는데

    제가 목표로 하는것은
    웹페이지를 만들어서 거기에 10분 간격으로
    센서가 측정한 값을 적는 것 뿐입니다

    그런데 어느 예제를 마이그레이션해서 진행해야 하는지
    (마이그레이션을 하는 방법은 둘째 치고)
    모르겠습니다
    도움을 간절히 바라고 있습니다..