知的好奇心 for IoT

IoT関連の知的好奇心を探求するブログです

cm精度を実現できるRTK測位用に基準局(Base)から移動局(Rover)へシリアルデータを伝送する装置をESP8266で作ってみた

トランジスタ技術の2018年1月号にcm精度で位置を測位できるGPS(GNSS)を使ったRTK測位の記事が出ています。

たまたまこの記事と、基準局(Base)のデータを移動局(Rover)へ送る手段がネックになっているという事を知ったので、基準局で受信したGPS(GNSS)データを複数の移動局で受信できるプログラムをESP8266用に作ってみました。

今回はいきなり掟破りのスケッチの公開からです!

 

Serial2WiFi1NBridge.ino

/*
 * Serial2WiFi1NBridge
 * May 31, 2018
 * By Hiroyuki ITO
 * http://intellectualcuriosity.hatenablog.com/  
 * MIT Licensed.
 */

#include <ESP8266WiFi.h>

#define SERVER 1
#define CLIENT 2

/*
 *===== Change below =====
 */
const char *WIFI_SSID = "Your Wi-Fi SSID"; 
const char *WIFI_PASS = "Your Wi-Fi password";
#define SERVER_ADDRESS  "xxx.xxx.xxx.xxx" // IP address or FQDN

// Remove comment of function you want to use
//int run_mode = SERVER;                  // Server (Base station)
int run_mode = CLIENT;                  // Client (Rover)

#define MAX_CLIENT      8               // Maximum of client connection
#define SERVER_PORT     5555            // TCP port number of Server
#define SERIAL_SPEED    115200          // Serial port speed
#define TIMEOUT_SEC     1000L           // 1 second (timeout for clinet)
#define PIN_LED         2               // Builtin LED (Wio Node & WeMos D1 mini)
/*
 *===== Change above =====
 */

// Global object & valiable
WiFiServer server(SERVER_PORT);
WiFiClient client[MAX_CLIENT];
bool connection[MAX_CLIENT];
long timeout;                          // for connection check (client)

void setup() {
  Serial.begin(SERIAL_SPEED); 
  pinMode(PIN_LED, OUTPUT);
  digitalWrite(PIN_LED, LOW);
  
  // Print program mode
  if (run_mode == SERVER) {
    Serial.println("\r\nThis is server program.");
  } else {
    Serial.println("\r\nThis is client program.");
  }

  // Wi-Fi Setup
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  Serial.print("Connecting to " + String(WIFI_SSID) + " ");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("\r\nConnected!");
  digitalWrite(PIN_LED, HIGH);

  // Print IP address
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // Initialize
  if (run_mode == SERVER) {
    server.begin();
  }
  for (int i=0; i<MAX_CLIENT; i++) {
    connection[i] = false;
  }
}

void loopServer() {
  // Confirm connection
  for (int i=0; i<MAX_CLIENT; i++) {
    if (!connection[i]) {             // Before connection
      client[i] = server.available();
      if (client[i].connected()) {
        Serial.print("Connected!:");
        Serial.println(i);
        connection[i] = true;
      }
    } else {                          // After connection
      if (client[i].connected()) {
        client[i].read();             // connection check
      } else {
        Serial.print("Disconnected!:");
        Serial.println(i);
        connection[i] = false;
      }
    }
  }
  // Send data to client
  if (Serial.available()) {
    char ch = Serial.read();
    for (int i=0; i<MAX_CLIENT; i++) {
      if (connection[i]) {
        digitalWrite(PIN_LED, LOW);
        client[i].write(ch);
        digitalWrite(PIN_LED, HIGH);
      }
    }
  }
}

void loopClient() {
  // Confirm connection
  if (!connection[0]) {               // Before connection
    if (!client[0].connect(SERVER_ADDRESS, SERVER_PORT)) {
      Serial.println("Please check server infomation!");
      digitalWrite(PIN_LED, LOW);
      delay(60000);                   // 60 second
      while(1);                       // Hung up!
    } else {
      client[0].flush();
      Serial.println("connected!");
      connection[0] = true;
      timeout = millis();
    }
  } else {                            // After connection
    if (client[0].connected()) {
      // Receive data from server
      if (client[0].available() > 0) {
        digitalWrite(PIN_LED, LOW);
        char ch = client[0].read();
        Serial.write(ch);
        timeout = millis();
        digitalWrite(PIN_LED, HIGH);
      }
      if (millis() - timeout > TIMEOUT_SEC) {
        client[0].write('.');         // Send connection check data
        timeout = millis();
      }
    } else {
      Serial.println("Disconnected!");
      client[0].stop();
      connection[0] = false;
    }
  }
}

void loop() {
  // Indicate Wi-Fi connection
  switch (WiFi.status()) {
    case WL_NO_SSID_AVAIL :
    case WL_CONNECT_FAILED :
      digitalWrite(PIN_LED, LOW);
      break;
    default :
      digitalWrite(PIN_LED, HIGH);
  }

  if (run_mode == SERVER) {
    loopServer();
  } else {
    loopClient();
  }
}

 

工夫したところ

  1. Wio NodeWeMos D1 miniの内蔵LEDを動作インディケーターとして使った
  2. 基準局用と移動局用のプログラムを1ファイルにした
  3. 基準局用のプログラムをマルチコネクションに対応した
  4. コネクション切れの検知方法

1.Wio NodeとWeMos D1 miniの内蔵LEDを動作インディケーターとして使った

それぞれのボードの写真とLEDの位置です。

左からWio Node、WeMos D1 mini V3.0、Wemos D1 miniです。

f:id:IntellectualCuriosity:20180614225432j:plainf:id:IntellectualCuriosity:20180614225451j:plainf:id:IntellectualCuriosity:20180614225500j:plain

どのボードもGPIO2をLOWにすると青色のLEDが点灯します。

この動作を利用して、WiFiが繋がっていないとLEDが点灯するのと、データ転送中にLEDが点滅するようにしました。

 

2.基準局用と移動局用のプログラムを1ファイルにした

基準局と移動局のプログラムの違いは、基準局用のプログラムがマルチコネクションに対応しているのと、コネクション切れの判断ぐらいでそれ程違いがないんです。

それで、基準局と移動局用のメイン関数だけを分け、コメントによる動作モードの切り替えだけで同じファイルで動作できるようにしました。

22行目をコメントにすれば移動局、23行目をコメントにすれば基準局用のプログラムとして動作します。

22: //int run_mode = SERVER;                  // Server (Base station)
23: int run_mode = CLIENT;                  // Client (Rover)

 

3. 基準局用のプログラムをマルチコネクションに対応した

はじめは基準局と移動局で1対1の通信を行うように作っていたのですが、ESP8266のパワーが余っている感じがあったので、基準局のプログラムをマルチコネクションに対応するように書き換えました。

コネクション数は#defineで定義しているので、ESP8266のクロックを160MHzにすればもっと行ける気がします。

25: #define MAX_CLIENT      8               // Maximum of client connection

WiFiClientオブジェクトの配列とコネクションを管理している配列をMAX_CLIENTで定義した数だけ作っています。

36: WiFiClient client[MAX_CLIENT];
37: bool connection[MAX_CLIENT];

 

4.コネクション切れの検知方法

コネクションが有効活用できるように接続後はコネクション切れをチェックするようにしています。

サーバー側では何もしないとコネクション切れがわからないっぽいので、client.read()を実行してコネクション切れがわかるようにしています。

87:      if (client[i].connected()) {
88:        client[i].read();             // connection check

 

おしまい