ArduinoでESP8266(ESP-01)を制御+通信する #6

こんにちは、ばいろんです。

今回は長い前置きを経てついにESP8266同士で通信をしてみたいと思います。

ESP8266をつないだArduinoを2台用意して片方をサーバー、片方をクライアントにして実装していきます。

 

とりあえず動作してる様子はこんな感じ

CoYdko6VUAA9m_m

それでは行きましょう!

 

設計図はこんな感じで

ESP8266単体だと通信距離が心もとないので間にルーターを入れて距離を稼いでいます。

それでは各々の役割について説明します

  • サーバー(Arduino+ESP8266)

クライアントとなるArduino+ESP8266のモジュールから文字列を受け取ります。今回はサーバーが文字列を受け取ったことをクライアントに伝えるため、受け取った文字列をもとのクライアントに送り返します。

1台のサーバーにつき5台のクライアントと接続することができます。データをクライアントから収集する親機のイメージです

  • クライアント(Arduino+ESP8266)

サーバーにセンサーなどの値(今回はダミーの文字列)を送信します。

データを収集し、サーバーに送信する子機のイメージです。

  • ルーター

ルーターはESP8266だけだと心もとない通信距離を稼ぐために利用します。後々の汎用性を考えるとルーターを介した方がいいかも

ということで実装についてみていきます。

今回利用しているライブラリESP8266.h

 

  • サーバー

まずソースコードから

/**
   @example TCPServer.ino
   @brief The TCPServer demo of library WeeESP8266.
   @author Wu Pengfei<pengfei.wu@itead.cc>
   @date 2015.02

   @par Copyright:
   Copyright (c) 2015 ITEAD Intelligent Systems Co., Ltd. \n\n
   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of
   the License, or (at your option) any later version. \n\n
   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   THE SOFTWARE.
*/

#include "ESP8266.h"

#define SSID        "yourSSID"//今回はルーターのSSID
#define PASSWORD    "yourPASS"//ルーターのパスワード
#define BAUD_RATE   9600
#define HOST_PORT (8090)

SoftwareSerial mySerial(2, 3); /* RX:D3, TX:D2 自分が使うピンに合わせて設定*/
ESP8266 wifi(mySerial);

void setupESP8266()
{
  while (1) {
    Serial.print("restaring esp8266...");
    if (wifi.restart()) {
      Serial.print("ok\r\n");
      break;
    }
    else {
      Serial.print("not ok...\r\n");
      Serial.print("Trying to kick...");
      while (1) {
        if (wifi.kick()) {
          Serial.print("ok\r\n");
          break;
        }
        else {
          Serial.print("not ok... Wait 5 sec and retry...\r\n");
          delay(5000);
        }
      }
    }
  }

  Serial.print("setup begin\r\n");
  Serial.print("FW Version:");
  Serial.println(wifi.getVersion().c_str());

  while (1) {
    if (wifi.setOprToStation()) {
      Serial.print("to station ok\r\n");
      break;
    }
    else {
      Serial.print("to station err\r\n");
      Serial.println("Wait 5 seconds and try again...");
      delay(5000);
    }
  }

  while (1) {
    if (wifi.joinAP(SSID, PASSWORD)) {
      Serial.print("Join AP success\r\n");
      break;
    }
    else {
      Serial.print("Join AP failure\r\n");
      Serial.println("Wait 5 seconds and try again...");
      delay(5000);
    }
  }
  Serial.print("setup end\r\n");
}

void setup(void)
{
  Serial.begin(BAUD_RATE);
  setupESP8266();
  
  if (wifi.enableMUX()) {
    Serial.print("multiple ok\r\n");
  } else {
    Serial.print("multiple err\r\n");
  }

  if (wifi.startTCPServer(HOST_PORT)) {
    Serial.print("start tcp server ok\r\n");
  } else {
    Serial.print("start tcp server err\r\n");
  }

  if (wifi.setTCPServerTimeout(600)) {
    Serial.print("set tcp server timout 10 seconds\r\n");
  } else {
    Serial.print("set tcp server timout err\r\n");
  }

  Serial.print("setup end\r\n");
}

void loop(void)
{
  uint8_t buffer[128] = {0};
  uint8_t mux_id;
  uint32_t len;
  len = wifi.recv(&mux_id, buffer, sizeof(buffer), 100);
  if (len > 0) {
    Serial.print("Status:[");
    Serial.print(wifi.getIPStatus().c_str());
    Serial.println("]");

    Serial.print("Received from :");
    Serial.print(mux_id);
    Serial.print("[");
    for (uint32_t i = 0; i < len; i++) {
      Serial.print((char)buffer[i]);
    }
    Serial.print("]\r\n");

    if (wifi.send(mux_id, buffer, len)) {
      delay(3000);
      Serial.print("send back ok\r\n");
    } else {
      delay(3000);
      Serial.print("send back err\r\n");
    }

    if (wifi.releaseTCP(mux_id)) {
      Serial.print("release tcp ");
      Serial.print(mux_id);
      Serial.println(" ok");
    } else {
      Serial.print("release tcp");
      Serial.print(mux_id);
      Serial.println(" err");
    }

    Serial.print("Status:[");
    Serial.print(wifi.getIPStatus().c_str());
    Serial.println("]");
  }
}

基本的にサーバーの設定に必要なのは次の要素

  1. 無線LANルーターのSSID
  2. 無線LANルーターのパスワード
  3. TCPサーバーの通信に利用するポート番号(デフォルトでは8090)
  4. (ボーレート、今回は9600bps)

一応#defineの部分で最低限の部分は設定できるようにしておきました。

#include "ESP8266.h"

#define SSID        "yourSSID"//今回はルーターのSSID
#define PASSWORD    "yourPASS"//ルーターのパスワード
#define BAUD_RATE   9600
#define HOST_PORT (8090)

SoftwareSerial mySerial(2, 3); /* RX:D3, TX:D2 自分が使うピンに合わせて設定*/
ESP8266 wifi(mySerial);

 

setupESP8266()関数

WiFiとESP8266との接続を確立する関数です。おまじないだと思ってください。

void setupESP8266()
{
  while (1) {
    Serial.print("restaring esp8266...");
    if (wifi.restart()) {
      Serial.print("ok\r\n");
      break;
    }
    else {
      Serial.print("not ok...\r\n");
      Serial.print("Trying to kick...");
      while (1) {
        if (wifi.kick()) {
          Serial.print("ok\r\n");
          break;
        }
        else {
          Serial.print("not ok... Wait 5 sec and retry...\r\n");
          delay(5000);
        }
      }
    }
  }

  Serial.print("setup begin\r\n");
  Serial.print("FW Version:");
  Serial.println(wifi.getVersion().c_str());

  while (1) {
    if (wifi.setOprToStation()) {
      Serial.print("to station ok\r\n");
      break;
    }
    else {
      Serial.print("to station err\r\n");
      Serial.println("Wait 5 seconds and try again...");
      delay(5000);
    }
  }

  while (1) {
    if (wifi.joinAP(SSID, PASSWORD)) {
      Serial.print("Join AP success\r\n");
      break;
    }
    else {
      Serial.print("Join AP failure\r\n");
      Serial.println("Wait 5 seconds and try again...");
      delay(5000);
    }
  }
  Serial.print("setup end\r\n");
}

 

setup()関数

setup()関数は次のようになっています。WiFi(無線ルータ)と接続を確立する役割はsetupESP8266()関数が担っています。これもおまじないだと思ってください。

void setup(void)
{
  Serial.begin(BAUD_RATE);
  setupESP8266();
  
  if (wifi.enableMUX()) {
    Serial.print("multiple ok\r\n");
  } else {
    Serial.print("multiple err\r\n");
  }

  if (wifi.startTCPServer(HOST_PORT)) {
    Serial.print("start tcp server ok\r\n");
  } else {
    Serial.print("start tcp server err\r\n");
  }

  if (wifi.setTCPServerTimeout(600)) {
    Serial.print("set tcp server timout 10 seconds\r\n");
  } else {
    Serial.print("set tcp server timout err\r\n");
  }

  Serial.print("setup end\r\n");
}

 

データの送受信に使う関数

wifi.recv()関数:TCP通信を使って文字列を受け取る関数

wifi.send()関数:TCP通信を使って文字列を送信する関数

利用している変数

buffer:受け取った文字列を格納する配列

len:bufferで受け取った文字列の長さ

loop()関数

loop()関数内で実際の通信の処理を行っています。動作はクライアントから受け取ったデータをそのまま投げ返すというものです。コツとしては適切な箇所にdelay()関数を入れることでデータの送受信が円滑に進みます。

void loop(void)
{
  uint8_t buffer[128] = {0};
  uint8_t mux_id;
  uint32_t len;
  len = wifi.recv(&mux_id, buffer, sizeof(buffer), 100);
  if (len > 0) {
    Serial.print("Status:[");
    Serial.print(wifi.getIPStatus().c_str());
    Serial.println("]");

    Serial.print("Received from :");
    Serial.print(mux_id);
    Serial.print("[");
    for (uint32_t i = 0; i < len; i++) {
      Serial.print((char)buffer[i]);
    }
    Serial.print("]\r\n");

    if (wifi.send(mux_id, buffer, len)) {
      delay(3000);
      Serial.print("send back ok\r\n");
    } else {
      delay(3000);
      Serial.print("send back err\r\n");
    }

    if (wifi.releaseTCP(mux_id)) {
      Serial.print("release tcp ");
      Serial.print(mux_id);
      Serial.println(" ok");
    } else {
      Serial.print("release tcp");
      Serial.print(mux_id);
      Serial.println(" err");
    }

    Serial.print("Status:[");
    Serial.print(wifi.getIPStatus().c_str());
    Serial.println("]");
  }
}

デバッグ用のメッセージがたくさんありますが通信に必要なコアの部分は少ないです。動作確認はしてないですが以下のスケッチで一応は動くと思います。(ですが、上のスケッチと見比べる程度にしておいてください)

void loop(void)
{
  uint8_t buffer[128] = {0};
  uint8_t mux_id;
  uint32_t len;
  len = wifi.recv(&mux_id, buffer, sizeof(buffer), 100);
  if (len > 0) {
    for (uint32_t i = 0; i < len; i++) {
      Serial.print((char)buffer[i]);
    }
    wifi.send(mux_id, buffer, len);
    delay(3000);
    wifi.releaseTCP(mux_id);
   delay(3000);
  }
}

 

サーバーの動作の様子

setup()関数

cap16_07_28_01

実際の動作

cap16_07_28_02

クライアントからメッセージを受け取っていることが分かります。


クライアント

クライアント側のソースコードを見ていきましょう。

/**
   @example TCPClientMultiple.ino
   @brief The TCPClientMultiple demo of library WeeESP8266.
   @author Wu Pengfei<pengfei.wu@itead.cc>
   @date 2015.02

   @par Copyright:
   Copyright (c) 2015 ITEAD Intelligent Systems Co., Ltd. \n\n
   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of
   the License, or (at your option) any later version. \n\n
   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   THE SOFTWARE.
*/
#include "ESP8266.h"
#include <SoftwareSerial.h>

#define SSID        "yourSSID"
#define PASSWORD    "yourPASS"
#define HOST_NAME   "yourHOSTIP"
#define HOST_PORT   (8090)
#define BAUD_RATE   9600

SoftwareSerial mySerial(2, 3); /* RX:D3, TX:D2 */
ESP8266 wifi(mySerial,BAUD_RATE);

void setupESP8266()
{
  while (1) {
    Serial.print("restaring esp8266...");
    if (wifi.restart()) {
      Serial.print("ok\r\n");
      break;
    }
    else {
      Serial.print("not ok...\r\n");
      Serial.print("Trying to kick...");
      while (1) {
        if (wifi.kick()) {
          Serial.print("ok\r\n");
          break;
        }
        else {
          Serial.print("not ok... Wait 5 sec and retry...\r\n");
          delay(5000);
        }
      }
    }
  }

  Serial.print("setup begin\r\n");
  Serial.print("FW Version:");
  Serial.println(wifi.getVersion().c_str());

  while (1) {
    if (wifi.setOprToStation()) {
      Serial.print("to station ok\r\n");
      break;
    }
    else {
      Serial.print("to station err\r\n");
      Serial.println("Wait 5 seconds and try again...");
      delay(5000);
    }
  }

  while (1) {
    if (wifi.joinAP(SSID, PASSWORD)) {
      Serial.print("Join AP success\r\n");
      break;
    }
    else {
      Serial.print("Join AP failure\r\n");
      Serial.println("Wait 5 seconds and try again...");
      delay(5000);
    }
  }
  Serial.print("setup end\r\n");
}

void setup(void)
{

  Serial.begin(BAUD_RATE);
  setupESP8266();
  if (wifi.enableMUX()) {
    Serial.print("multiple ok\r\n");
  } else {
    Serial.print("multiple err\r\n");
  }

  Serial.print("setup end\r\n");
}

void loop(void)
{
  uint8_t buffer[128] = {0};
  static uint8_t mux_id = 0;

  if (wifi.createTCP(mux_id, HOST_NAME, HOST_PORT)) {
    Serial.print("create tcp ");
    Serial.print(mux_id);
    Serial.println(" ok");
  } else {
    Serial.print("create tcp ");
    Serial.print(mux_id);
    Serial.println(" err");
  }


  char *hello = "Hello, this is client!";
  if (wifi.send(mux_id, (const uint8_t*)hello, strlen(hello))) {
    delay(1000);
    Serial.println("send ok");
  } else {
    delay(1000);
    Serial.println("send err");
  }

  uint32_t len = wifi.recv(mux_id, buffer, sizeof(buffer), 10000);
  if (len > 0) {
    Serial.print("Received:[");
    for (uint32_t i = 0; i < len; i++) {
      Serial.print((char)buffer[i]);
    }
    Serial.print("]\r\n");
  }

  if (wifi.releaseTCP(mux_id)) {
    Serial.print("release tcp ");
    Serial.print(mux_id);
    Serial.println(" ok");
  } else {
    Serial.print("release tcp ");
    Serial.print(mux_id);
    Serial.println(" err");
  }

  delay(3000);
  mux_id++;
  if (mux_id >= 1) {
    mux_id = 0;
  }
}

クライアントの設定に必要なのは次の要素

  1. 無線LANルーターのSSID
  2. 無線LANルーターのパスワード
  3. サーバーのIPアドレス
  4. TCPサーバーの通信に利用するポート番号(デフォルトでは8090)
  5. (ボーレート、今回は9600bps)

こちらも#defineの部分で最低限の部分は設定できるようにしておきました。

 

setup()関数

setup()関数は次のようになっています。WiFi(無線ルータ)と接続を確立する役割はサーバーのソースコードと同様にsetupESP8266()関数が担っています。これもいわゆるおまじないだと思ってコピペしてみてください。

void setup(void)
{

  Serial.begin(BAUD_RATE);
  setupESP8266();
  if (wifi.enableMUX()) {
    Serial.print("multiple ok\r\n");
  } else {
    Serial.print("multiple err\r\n");
  }

  Serial.print("setup end\r\n");
}

 

データの送受信に使う関数

wifi.recv()関数:TCP通信を使って文字列を受け取る関数

wifi.send()関数:TCP通信を使って文字列を送信する関数

利用している変数

buffer:受け取った文字列を格納する配列

len:bufferで受け取った文字列の長さ

hello:送受信するメッセージの文字列。この文字列がやり取りされる

mux_id:クライアントを識別するID。元のソースコードでは5台まで接続ができるようになっている。(今回は1台になるように設定)

loop()関数

void loop(void)
{
  uint8_t buffer[128] = {0};
  static uint8_t mux_id = 0;

  if (wifi.createTCP(mux_id, HOST_NAME, HOST_PORT)) {
    Serial.print("create tcp ");
    Serial.print(mux_id);
    Serial.println(" ok");
  } else {
    Serial.print("create tcp ");
    Serial.print(mux_id);
    Serial.println(" err");
  }


  char *hello = "Hello, this is client!";
  if (wifi.send(mux_id, (const uint8_t*)hello, strlen(hello))) {
    delay(1000);
    Serial.println("send ok");
  } else {
    delay(1000);
    Serial.println("send err");
  }

  uint32_t len = wifi.recv(mux_id, buffer, sizeof(buffer), 10000);
  if (len > 0) {
    Serial.print("Received:[");
    for (uint32_t i = 0; i < len; i++) {
      Serial.print((char)buffer[i]);
    }
    Serial.print("]\r\n");
  }

  if (wifi.releaseTCP(mux_id)) {
    Serial.print("release tcp ");
    Serial.print(mux_id);
    Serial.println(" ok");
  } else {
    Serial.print("release tcp ");
    Serial.print(mux_id);
    Serial.println(" err");
  }

  delay(3000);
  mux_id++;
  if (mux_id >= 1) {//ここの値を変えることで同時接続数を変えられる
    mux_id = 0;
  }
}

クライアント側のloop()関数も見通しをよくするためにデバッグ用のメッセージを以下のスケッチで取り除いてみました。

通信に最低限必要な部分はこれくらいです。(例のごとく動作確認はしていませんが、もとのloop()関数と見比べて理解を深めるために利用してみてください。とりあえずいじってみることが大切です。)

void loop(void)
{
  uint8_t buffer[128] = {0};
  static uint8_t mux_id = 0;

  wifi.createTCP(mux_id, HOST_NAME, HOST_PORT);

  char *hello = "Hello, this is client!";
  wifi.send(mux_id, (const uint8_t*)hello, strlen(hello));
  delay(1000);

  uint32_t len = wifi.recv(mux_id, buffer, sizeof(buffer), 10000);
  if (len > 0) {
    for (uint32_t i = 0; i < len; i++) {
      Serial.print((char)buffer[i]);
    }
  }

  wifi.releaseTCP(mux_id);
  delay(3000);
  mux_id++;
  if (mux_id >= 1) {//ここの値を変えることで同時接続数を変えられる
  mux_id = 0;
  }
}

クライアントの動作の様子

setup()関数

cap16_07_28_0

実際の動作

cap16_07_28_04

 


 

ルーター

ルーターに関してはメーカーにより設定方法が異なるので詳しい説明はしませんが、私はルーターの設定画面でそれぞれのESP8266に固定のIPアドレスを与えました。(IPアドレスが自動で割り振られると、その都度IPを調べてソースコードを書き直す必要があるため)

固定のIPを設定するにはMACアドレスが必要となるので、ATコマンドの AT+CIFSRを使ってESP8266のMACアドレスを取得します。

その後、ルータの設定画面でMACアドレスとIPアドレスの対応付けをします。

ちなみに私が使ったルーターはこれです

ですが、このルーターの設定がだいぶめんどうくさかったので、皆さんは別のものを購入することをお勧めします…(ルーターの設定に関してはあとで補足記事作るかもしれません)

ということで長くなりましたがESP8266(ESP-01) + Arduinoで通信する際の初心者向け?チュートリアルでした!

内容が稚拙なところもありますが、ESP8266というおもしろモジュールを試すきっかけになれば幸いです。

ぜひ、ESP8266とArduinoを使って様々なものを無線化しましょう!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Scroll to top