昔、中学生だった時に
昔、中学の技術の授業で”ラジオ”か”インターフォン”のどちらかを作ると言うのが有りました。キットになっていて動作の仕組みは分からなくても、基板に間違い無く部品を差し込んでハンダ付けすれば動作するやつです。住んでいた家は狭くその気になれば家の隅々まで声が通ったのでラジオを選択した覚えが有ります。でもインターフォンには興味が有りいつかは作ってみたいと思っていました。最近ESP32で遊んでいるのですが、これ使ったら簡単にインターフォンが出来るのでは無いかと思い作ってみる事にしました。
ハードの準備
インターフォンなのでESP32が最低でも2つ必要です。1つは、”ESP32 開発ボード WiFi + Bluetooth 超低消費 電力 デュアル コア ESP-32 ESP-32S ボード”(下図左)Banggoodで買いました。もう一つは、”Wi-Fiモジュール ESP-WROOM-32 DIP化キット”(下図右)秋月電子で買いました。両者共に約800円位でした。
Banggoodの方はUSBコネクタを繋げば即プログラムを書き込めます。秋月の方は追加で、
- ヘッダーピンのハンダ付け
- リセット、Boot用ボタンの配線
- 更にプログラム書き込み用のUSBシリアル変換基板
が必要になります。2つ共Banggoodで良かったのですが、一度秋月のこのキットを使って見たかったので買って見ました。
両者の通信はもちろんWiFiを使用します。互いにデータをやり取りするだけなら追加の配線は必要無いので、すぐプログラムの開発に入れます。開発環境は、”Arduino IDE”を使います。
UDPで通信してみる
ネット通信と言うと、”Socket”通信 、”UDP”、”TCP”通信、”Internet”通信 が有名です。今回は、”UDP”を使用する事にしました。作りたいのがインターフォンなので通信の信頼性より速度を重視したからです。
“ESP32 UDP”でWeb検索をかけると、幾つかのサンプルプログラムを見つける事が出来ます。それらは、一方がサーバー。もう一方をクライアントにして通信しています。大体こんな感じです。
サーバー側プログラム。クライアントからデータが送られて来たらそれをシリアルモニタに表示するプログラムです。
#include <WiFiUdp.h>
#include "WiFi.h"
const char * ssid = "ESP32UDP"; // SSID
const char * password = "12345678"; // password
static const int Remote_Port = 9000; // Destination port
static const int Org_Port = 9000; // Source port
WiFiUDP UDP;
void setup()
{
Serial.begin(115200);
WiFi.softAP(ssid, password);
delay(1000);
Serial.print("AP IP address: "); // 192.168.4.1
Serial.println(WiFi.softAPIP());
UDP.begin(Org_Port);
Serial.println("Server OK");
}
void loop()
{
char rv_data[2] = {0,0};
if (UDP.parsePacket() > 0)
{
UDP.read(rv_data , 1);
Serial.print("Recieve : ");
Serial.println(rv_data);
UDP.flush();
}
}
- 4,5行
- こちらのESP32はサーバーとするので、SSIDとPASSWORDを指定します。
- 7行:送信先ポートの指定
- 8行:送信元ポートの指定
- UDPでは通信用のポートが必要になります。
- 自分で使用するポート。今回は8行目で指定。
- 相手先のポート。今回は7行目で指定。
- 今回は各ポートに9000を使用しています。
- 送信元と先で同じ番号のポートを使用していますが、ESP32自体が別ものですので番号は同じですが別のポートです。
- UDPでは通信用のポートが必要になります。
- 10行 WiFiUDP型のインスタンスを宣言
- これを用いてUDP通信を行う。
- 16行 softAPの開始
- こちらのESP32はサーバーとして機能させます。
- 20行 IP アドレスの表示
- シリアルモニタにIPアドレスを表示します。
- softAPの場合、特別は事をしなければIPアドレスは,”192.168.4.1″
- 22行 UDP通信の開始
- UDP.begin(Org_Port);で通信を開始します。
- 引数は、自分で使用するポート番号です。
- 31行 if (UDP.parsePacket() > 0)
- UDP.parsePacket()は、自分のポートにデータが来たらそのデータの数を返す関数です。データが無い場合は、0を返します。
- データが来たらIf以下を実行
- 33行 UDP.read(rv_data , 1);
- ポートに来たデータを読み込む関数。
- 第一引数は、データ格納先のアドレス。次は読み込むデータ数。
- データは1バイト毎の扱いです。
- 今回はクライアント側から、1バイトのデータ送信を想定。
- 34,35行 受信したデータをシリアルモニタに表示します。
- 36行 UDP.flush();
- この関数、ポートの受信バッファーをリセットする様です。
- データの受信が終わったら必ず実行して下さい。
クライアント側。サーバーに1文字を送るプログラムです。
#include "WiFi.h"
#include <WiFiUdp.h>
const char * ssid = "ESP32UDP"; // SSID
const char * password = "12345678"; // password
IPAddress ip(192, 168, 4, 2); // IP Address
IPAddress gateway(192,168, 4, 1); // Gateway Address
IPAddress subnet(255, 255, 255, 0); // Subnet Address
IPAddress sv_ip(192, 168, 4, 1); // Server IP Address
static const int Remote_Port = 9000; // Destination port
static const int Org_Port = 9000; // Source port
WiFiUDP UDP;
void setup()
{
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.config(ip, gateway, subnet);
WiFi.begin(ssid, password);
// Try forever
while (WiFi.status() != WL_CONNECTED) {
Serial.println("...Connecting to WiFi");
delay(1000);
}
Serial.println("Connected");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
UDP.begin(Org_Port);
Serial.println("Client OK");
}
char a = 'A';
void loop()
{
Serial.println("Send : " + String(a));
UDP.beginPacket(sv_ip, Remote_Port);
UDP.write(a);
UDP.endPacket();
a ++;
if(a > 'F') a = 'A';
delay(3000);
}
- 4,5行 サーバーに接続する時に使用します。
- 7,8,9行 自分のIPアドレスを指定します。
- 指定しないとサーバが自動でIPアドレスを指定するので、意図的に指定しました。
- 11行 通信を行うサーバーのアドレス。
- 13,14行 送信元、先の使用ポート番号。
- 22,23,24行 IPアドレスを指定してサーバーに接続。
- 37行 UDP開始
- 47行 UDP.beginPacket(sv_ip, Remote_Port);
- 通信先のIPアドレス、ポートを引数に通信の開始を宣言
- 48行 UDP.write(a);
- 通信先にデータを送信
- 今回は1バイトのデータを送信
- 49行 UDP.endPacket();
- 通信完了
- プログラムは、”A”から”F”までを一文字づつ3秒間隔で送信しています。
実行結果
下記は、左がクライアント、右がサーバ側のシリアルモニタの表示です。サーバー側は、IPアドレスが、”192.168.4.1″にクライアント側は、”192.168.4.2”と設定通りです。クライアント側で送ったデータをサーバー側が正しく受け取っている事が分かります。
ここまでは、順調に進んでいます。次回はUDPに付いてもう少しいじってみたいと思います。