ESP-NOWを使ってみた【ESP32】

はじめに

Wi-Fi環境のない場所や電波環境が悪い場所でIoTシステムを構築する場合があります。

対策として、Wi-Fiルーターや中継器を設置する等で環境を改善する方法がありますが、Wi-Fiルーターを経由せずに機器同士で通信した方が良い場合もあります。

今回は、機器同士で直接通信する方法のESP-NOWという通信方法を使ってみることにしました。

ESP-NOWについて

Espressifが開発した通信方式で、Wi-Fiルーターを経由せず直接機器同士で通信を行います。
MACアドレスを指定しての1対1の通信やブロードキャストでの1対多の一斉送信も行えます。

ESP-NOW

参考: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システムの構築に生かしていけばと思います。

よかったらシェアしてね!