トランジスタ技術の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();
}
}
工夫したところ
- Wio NodeとWeMos D1 miniの内蔵LEDを動作インディケーターとして使った
- 基準局用と移動局用のプログラムを1ファイルにした
- 基準局用のプログラムをマルチコネクションに対応した
- コネクション切れの検知方法
1.Wio NodeとWeMos D1 miniの内蔵LEDを動作インディケーターとして使った
それぞれのボードの写真とLEDの位置です。
左からWio Node、WeMos D1 mini V3.0、Wemos D1 miniです。
どのボードも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
おしまい