うごくものをつくる

個人的な学習ノート

基礎技術メモ

ESP-NOWによる無線通信の使い方(送信編)

ネット上にいくらでも情報はあるんだろうけど個人的メモ用に記事として残す。

ESP -NOWっていうのは、ESP32というマイコンを作っているEspressif社が独自に提供している通信方式で、高速、お手軽にデータを送ることができる。

速いし低消費電力というのが利点だけど、デメリットとしては「相手がちゃんと受信可能な状態なのかを確かめず一方的に送りつけるので、通信エラーが起きやすい」ということ。どうしてもパケットロスが出てはいけないという部分に使うのはおすすめできないが、そうでなければWi-FiとかBluetooth機能とか使うよりシンプルでいいかも?Espressif社のマイコン同士でしか通信できないけどね。

とりあえずESP-NOWを使うための構成について、分かる範囲で解説しつつ載せる。なるべくごちゃごちゃしないように、必要最小限(と思われる)部分のみ記述する。

まずは送信用のコードについて。

1,必要なライブラリのインクルード

ESP-NOW機能を使うために必要なライブラリをインクルードする。

#include <WiFi.h>
#include <esp_now.h>

WiFi.hをインクルードしてるのは、ESP-NOWはWi-Fi通信そのものではないけど無線機能としてWi-Fiを使うから。で、esp-now.hをインクルードすることで、ESP-NOW機能を使えるようにする。

2,送信先の相手のMACアドレスを設定する。

const uint8_t addr[6] = {0x24, 0x0A, 0xC4, 0x5A, 0x4D, 0x94};

MACアドレスは6個の2桁16進数で表される。要素数6個のリストを用意して、送信先のMACアドレスを格納する。ちなみに上記MACアドレスは僕が持っているM5stackのMACアドレスなので、みなさんが自分の機器で使いたい場合は自分のESP32搭載機器のMACアドレスを入れてね。

3,ESP-NOW機能を初期化

  WiFi.mode(WIFI_STA); //Wi-Fi機能をステーションモードで起動
    WiFi.disconnect(); //初期化前にWi-Fi接続を切断
    if (esp_now_init() == ESP_OK) {
        Serial.println("ESP-Now Init Success");
    }

前述の通り、ESP-NOWはWi-Fi機能を使うので、ESP32のWi-Fi機能をステーションモードで起動する。ただし、ESP32が無線LANルーターに接続してしまっているとESP-NOWが使えないので、初期化前に接続を切断する。

その後esp_now_init()を呼び出すことで初期化が実行されるが、ちゃんと初期化成功したかどうかを確認するため、初期化に成功したらシリアル通信で文字を表示するようにした。(なので、ここのSerial.printlnによる文字列表示は不要なら削除してよいし、LEDを光らせる等別の方法で確認したいならその処理分に置き換えて良い)

4,ESP-NOWの各種設定

//ESP nowの各種設定
  esp_now_peer_info_t peerInfo;
  memcpy(peerInfo.peer_addr, addr, 6);
  peerInfo.channel = 0;
  peerInfo.encrypt = false;
  if (esp_now_add_peer(&peerInfo) != ESP_OK) {
        Serial.println("Failed to add peer");
        return;
    }

ここはよくわからない……。

esp_now_peer_info_tというのが必要のようなので、作る(ここではpeerInfoという名前で作成した)。

peerInfo.peer_addrというので、送信先のアドレスとして先程用意したMACアドレスを格納したリストを使って、送信先を設定する。

peerInfo.channelというのはよくわからないが、ネット上の作例通りに0にしておく。

peerInfo.encryptというのは通信を暗号化して送信するか否かを設定するもので、今回は暗号化はしないので、falseとする。

esp_now_add_peer()でここの設定をESP-NOWに適用するが、その処理に失敗したときに気付けるように、何らかのメッセージを表示するようにしている。もちろん、成功したときにメッセージ表示としても良い。

5,送信用関数の実行

esp_err_t result = esp_now_send(addr, data, sizeof(data));

esp_now_send()というのが呼び出されると、送信が実行される。ここで、カッコ内の変数は次のような感じで入れる。

esp_now_send(送信先MACアドレス, 送信するデータ, 送信するデータのサイズ)

今まで記載したコードでは省略しているが、dataというのは適当な要素数のリストである。ここで、dataの各要素はuint8_tしかいれることができない。つまり、整数で0~255までしか送ることができない。これ以上の数値を送りたいなら、少し工夫が要る。

ちなみに、esp_err_t result = esp_now_send(○, △, sizeof(△))とすると、送信を実行した上で、それがどのような結果になったかがresultに代入される。

送信が成功したのか、何らかのエラーによって失敗したのかを可視化したい場合、resultの中身に応じて次のようにしてメッセージ表示する。

switch (result)
        {
        case ESP_OK:
            Serial.println("Success");
            break;
        case ESP_ERR_ESPNOW_NOT_INIT:
            Serial.println("ESPNOW not Init.");
            break;
        case ESP_ERR_ESPNOW_ARG:
            Serial.println("Invalid Argument");
            break;
        case ESP_ERR_ESPNOW_INTERNAL:
            Serial.println("Internal Error");
            break;
        case ESP_ERR_ESPNOW_NO_MEM:
            Serial.println("ESP_ERR_ESPNOW_NO_MEM");
            break;
        case ESP_ERR_ESPNOW_NOT_FOUND:
            Serial.println("Peer not found.");
            break;

        default:
            Serial.println("Not sure what happened");
            break;
        }

6,まとめ

ここまで記載した内容で、ESP-NOWの送信機能を使うことができる。ここまでの実装の各ステップについて細切れに紹介したものを統合し、他機能を追加したサンプルコード全体としては以下のようになる。ESP32開発ボードに接続したボタンを押したときに、要素数3個のリストを送信する。リストの0番目の要素はボタンを押した回数、1番目の要素はその5倍の数値、2番目の要素は常に固定で「47」を送信する、という内容のサンプルである。

#include <Arduino.h>
#include <WiFi.h>
#include <esp_now.h>

const uint8_t addr[6] = {0x24, 0x0A, 0xC4, 0x5A, 0x4D, 0x94};//送信先のMACアドレス
uint8_t data[3];//送信用データ(リスト)
int cnt=0;//ボタンを押した回数カウント用変数

void setup() {
  
  Serial.begin(115200);

    WiFi.mode(WIFI_STA); //Wi-Fi機能をステーションモードで
    WiFi.disconnect(); //初期化前にWi-Fi接続を切断
    if (esp_now_init() == ESP_OK) {
        Serial.println("ESP-Now Init Success");
    }

  //ESP nowの各種設定
  esp_now_peer_info_t peerInfo;
  memcpy(peerInfo.peer_addr, addr, 6);
  peerInfo.channel = 0;
  peerInfo.encrypt = false;
  if(esp_now_add_peer(&peerInfo) != ESP_OK) {
        Serial.println("Failed to add peer");
        return;
    }

  //以下はその他設定
  pinMode(5, INPUT_PULLUP);//D5ピンを入力に指定
  }

void loop() {
  if(digitalRead(5) == LOW)//ボタンが押されたとき
  {
    cnt += 1;//cntを1加算
    data[0] = cnt;//dataの0番目にcntを代入
    data[1] = 5*cnt;//dataの1番目にcntの5倍を代入
    data[2] = 47;//dataの2番目に47を代入

    esp_err_t result = esp_now_send(addr, data, sizeof(data));//送信を実行
    switch (result)//結果の確認
        {
        case ESP_OK:
            Serial.println("Success");
            break;
        case ESP_ERR_ESPNOW_NOT_INIT:
            Serial.println("ESPNOW not Init.");
            break;
        case ESP_ERR_ESPNOW_ARG:
            Serial.println("Invalid Argument");
            break;
        case ESP_ERR_ESPNOW_INTERNAL:
            Serial.println("Internal Error");
            break;
        case ESP_ERR_ESPNOW_NO_MEM:
            Serial.println("ESP_ERR_ESPNOW_NO_MEM");
            break;
        case ESP_ERR_ESPNOW_NOT_FOUND:
            Serial.println("Peer not found.");
            break;
        }

  }
  delay(1000);//1秒待つ

}

ボタンは押したときにD5ピンがGNDに繋がるように配線したよ。

これで3つの整数を格納したリストが指定のMACアドレスの機器に送信される。

ちょっと記事が長くなったので、受信用プログラムの解説は別記事として書くことにする。

受信編の記事はこちら

(おわり)

返信する

メールアドレスが公開されることはありません。 が付いている欄は必須項目です