ESP-NOWを使ってみた【ESP32】
はじめに
Wi-Fi環境のない場所や電波環境が悪い場所でIoTシステムを構築する場合があります。
対策として、Wi-Fiルーターや中継器を設置する等で環境を改善する方法がありますが、Wi-Fiルーターを経由せずに機器同士で通信した方が良い場合もあります。
今回は、機器同士で直接通信する方法のESP-NOWという通信方法を使ってみることにしました。
ESP-NOWについて
Espressifが開発した通信方式で、Wi-Fiルーターを経由せず直接機器同士で通信を行います。
MACアドレスを指定しての1対1の通信やブロードキャストでの1対多の一斉送信も行えます。
参考:ESP-NOW – ESP32 – — ESP-IDF Programming Guide latest documentation
使ってみる
今回はESP32を2台使って、それぞれからメッセージを送受信するプログラムを動かします。
MACアドレスを指定せず、ブロードキャストでの送信を行うため、2台とも同じプログラムで動かしてみます。
Arduino IDEを使って以下のプログラムを書き込みます。
#include <esp_now.h>
#include <WiFi.h>
esp_now_peer_info_t slave;
// 送信コールバック
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
char macStr[18];
snprintf(macStr, sizeof(macStr), "%02X:%02X:%02X:%02X:%02X:%02X",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
Serial.print("Last Packet Sent to: ");
Serial.println(macStr);
Serial.print("Last Packet Send Status: ");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
// 受信コールバック
void OnDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len) {
char macStr[18];
char msg[1];
snprintf(macStr, sizeof(macStr), "%02X:%02X:%02X:%02X:%02X:%02X",
mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
Serial.printf("Last Packet Recv from: %s\n", macStr);
Serial.printf("Last Packet Recv Data(%d): ", data_len);
for ( int i = 0 ; i < data_len ; i++ ) {
msg[1] = data[i];
Serial.print(msg[1]);
}
Serial.println("");
}
void setup() {
Serial.begin(115200);
// ESP-NOW初期化
WiFi.mode(WIFI_STA);
WiFi.disconnect();
if (esp_now_init() == ESP_OK) {
Serial.println("ESPNow Init Success");
} else {
Serial.println("ESPNow Init Failed");
ESP.restart();
}
// マルチキャスト用Slave登録
memset(&slave, 0, sizeof(slave));
for (int i = 0; i < 6; ++i) {
slave.peer_addr[i] = (uint8_t)0xff;
}
esp_err_t addStatus = esp_now_add_peer(&slave);
if (addStatus == ESP_OK) {
// Pair success
Serial.println("Pair success");
}
// ESP-NOWコールバック登録
esp_now_register_send_cb(OnDataSent);
esp_now_register_recv_cb(OnDataRecv);
}
void loop() {
uint8_t data[13] = {72, 101, 108, 108, 111, 32, 69, 83, 80, 45, 78, 79, 87};
esp_err_t result = esp_now_send(slave.peer_addr, data, sizeof(data));
Serial.print("Send Status: ");
if (result == ESP_OK) {
Serial.println("Success");
} else if (result == ESP_ERR_ESPNOW_NOT_INIT) {
Serial.println("ESPNOW not Init.");
} else if (result == ESP_ERR_ESPNOW_ARG) {
Serial.println("Invalid Argument");
} else if (result == ESP_ERR_ESPNOW_INTERNAL) {
Serial.println("Internal Error");
} else if (result == ESP_ERR_ESPNOW_NO_MEM) {
Serial.println("ESP_ERR_ESPNOW_NO_MEM");
} else if (result == ESP_ERR_ESPNOW_NOT_FOUND) {
Serial.println("Peer not found.");
} else {
Serial.println("Not sure what happened");
}
delay(5000);
}
シリアルモニタで結果を確認します。
11:01:54.246 -> Send Status: Success
11:01:54.246 -> Last Packet Sent to: FF:FF:FF:FF:FF:FF
11:01:54.246 -> Last Packet Send Status: Delivery Success
11:01:57.594 -> Last Packet Recv from: ---MACアドレス---
11:01:57.594 -> Last Packet Recv Data(13): Hello ESP-NOW
以下の部分がブロードキャストで送信した結果のログです。
11:01:54.246 -> Send Status: Success
11:01:54.246 -> Last Packet Sent to: FF:FF:FF:FF:FF:FF
11:01:54.246 -> Last Packet Send Status: Delivery Success
MACアドレスを指定した場合、FF:FF:FF:FF:FF:FFの部分にMACアドレスが表示されます。
以下の部分が受信結果のログです。
11:01:57.594 -> Last Packet Recv from: ---MACアドレス---
11:01:57.594 -> Last Packet Recv Data(13): Hello ESP-NOW
送信機器のMACアドレスとメッセージ”Hello ESP-NOW”が表示されます。
所感
メリット
- Wi-Fi環境がない状態でも機器同士で通信ができること
- 通信のレスポンスが早い(今回の実験では最大50ms程度の遅延)
- ブロードキャストを使えば機器を事前に登録しなくても通信できる
懸念点
- Wi-Fiの通信帯域による通信への影響(Wi-Fiと同じ電波を使用するため)
低遅延で通信を行えるのが大きなメリットだと思います。
リアルタイムでセンサの値を取得したい場合等、活躍するタイミングは多いと考えます。
しかし、この通信方法は電波自体はWi-Fiと同じ電波を使用するため、Wi-Fiの電波状況の影響は受けてしまうと考えられます。
おわりに
今回はESP-NOWという通信方法を使ってみました。
今後、安定した通信が可能な距離や通信の安定性等の検証をして、システムに使用できるか判断していきます。
ub-GHz無線を利用する等、この他にもWi-Fi環境に関わらず機器同士で通信する方法があります。
それぞれの通信方法の特徴を学び、より効率的なIoTシステムの構築に生かしていけばと思います。