知的好奇心 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)

 

ゆっくりと説明を追加していきます。つづく...