2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ESP NOWによる双方向通信(お試し編)

Posted at

ESP-NOWとは

ESP-NOWは、Espressif が定義した無線通信プロトコルで、ルーターを介さずに直接、高速、低消費電力でスマートデバイスを制御できます。Wi-Fi や Bluetooth LE との共存が可能で、Espressif の ESP8266、ESP32、ESP32-S、ESP32-C など、複数シリーズの SoC をサポートしています。1
ESP-NOW はデータリンク層 ( レイヤ 2) に基づく無線通信プロトコルで、5 層の OSI 上位プロトコルを 1 層に簡素化しています。データ伝送時に、ネットワーク層、トランスポート層、セッション層、プレゼンテーション層、アプリケーション層などの複雑な階層を順次経由する必要がなく、各層でパケットヘッダを追加/解除する処理も不要です。これにより、ネットワーク混雑時のパケット損失に起因する遅延やラグを大幅に軽減し、より高い応答速度を実現しています。1

要は、ESP32ボードやM5 stackシリーズの間において、接続の柔軟性や通信の量と質を制限する代わりに、消費電力や実装の簡略化が可能なようです。

開発環境

事前準備

ESP-NOWはピア・ツー・ピアの通信プロトコルであることから、接続先のアドレスをあらかじめ調査する必要があります。調査対象のESP32ボードに以下のプログラムを書き込み、シリアルでモニターします。

main.cpp
#include <Arduino.h>
#include <WiFi.h>

void setup() {
  Serial.begin(115200);
  Serial.println("MAC Address Reader\n");
}

void loop() {
  Serial.print("MACWIfi: ");
  Serial.println(WiFi.macAddress());
  delay(1000);
}

そうすると、xx:xx:xx:xx:xx:xxという6バイトの数字(16進数)が読み出せるはずです。ボードにシールを貼り、MACアドレスをメモしておくと良いでしょう。

相互通信テスト

タイムスタンプとテキストデータをボードA・B間で送り合い相互に通信できているかテストします。
ボードA/BのMACアドレスを、マクロで切り替えて設定出来るようにしてあります。

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

/**
 * @brief 通信テスト用のデータ構造体
 * @param タイムスタンプ
 * @param テキストメッセージ
 */
typedef struct { 
    uint32_t timestamp;
    char text[64];
}wifirbcom_test_t;


void onDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len);
void onDataSent(const uint8_t *mac_addr, esp_now_send_status_t status);

esp_now_peer_info_t peerInfo;
wifirbcom_test_t send_data;
wifirbcom_test_t recive_data;

/** 事前に調べた各々のMACアドレスを記載 **/
const uint8_t WIFIRBCOM_A_DIST_ADDRESS[6] =  {   0xXX,   0xXX,   0xXX,   0xXX,   0xXX,   0xXX}; // 送信先のデバイスのアドレス(6バイト)
const uint8_t WIFIRBCOM_B_DIST_ADDRESS[6] =  {   0xYY,   0xYY,   0xYY,   0xYY,   0xYY,   0xYY}; // 送信先のデバイスのアドレス(6バイト)

uint8_t myaddress[6];  // 自身のMACアドレス
uint8_t distaddress[6];  // 相手のMACアドレス
char recive_text[64] = {0};  // 受信したテキストデータ

/***** ESP32のボード選択 *****/
#define ESP32BOARD_A 0
#define ESP32BOARD_B 1
#define ESP32BOARD  ESP32BOARD_A // ESP32ボードの選択(ESP32BOARD_A or ESP32BOARD_B)
// #define ESP32BOARD  ESP32BOARD_B // ESP32ボードの選択(ESP32BOARD_A or ESP32BOARD_B)

void setup() {
    char serialString[64];
    // 自他のアドレスを設定
    #if (ESP32BOARD == ESP32BOARD_A)
        memcpy(myaddress, WIFIRBCOM_A_DIST_ADDRESS, 6);
        memcpy(distaddress, WIFIRBCOM_B_DIST_ADDRESS, 6);
    #else
        memcpy(myaddress, WIFIRBCOM_B_DIST_ADDRESS, 6);
        memcpy(distaddress, WIFIRBCOM_A_DIST_ADDRESS, 6);
    #endif
    Serial.begin(115200);
    
    // 一応自分のアドレスを表示しておく
    sprintf(serialString, "ESP-NOW BOOT ! %0X:%0X:%0X:%0X:%0X:%0X", 
                                            myaddress[0], myaddress[1], myaddress[2], myaddress[3], myaddress[4], myaddress[5]);
    Serial.println(serialString);
    // Initialize WiFi in station mode
    WiFi.mode(WIFI_STA);

    // Initialize ESP-NOW
    if (esp_now_init() != ESP_OK) {
        Serial.println("ESP-NOW initialization failed");
        return; // Initialization failed
    }
    memcpy(peerInfo.peer_addr, distaddress, 6);
    peerInfo.channel = 0; // Use current channel
    peerInfo.encrypt = false; // No encryption
    if (esp_now_add_peer(&peerInfo) != ESP_OK) {
        Serial.println("Failed to add peer");
        return; // Adding peer failed
    }

    // 受信時に呼び出される関数を登録(必須)
    esp_now_register_recv_cb(onDataRecv);
    // 送信完了時に呼び出される関数を登録(任意)
    esp_now_register_send_cb(onDataSent);
}

/**
  * @brief     受信完了時に呼び出されるコールバック関数
  *            受信したデータからタイムスタンプとテキスト
  *            を取り出し、そのまま表示する。
  * @param     mac_addr peer MAC address
  * @param     data received data
  * @param     data_len length of received data
  */
void onDataRecv(const uint8_t *mac_addr, const uint8_t *data, int data_len)
{
    memcpy(&recive_data, data, sizeof(recive_data));
    sprintf(recive_text, "%ld : %s", recive_data.timestamp, recive_data.text);
    Serial.println(recive_text);
}

/**
  * @brief     送信完了時に呼び出されるコールバック関数。
  *            送信完了時のエラー処理などは行わないので
  *            メッセージを表示するのみ
  * @param     mac_addr peer MAC address
  * @param     status status of sending ESPNOW data (succeed or fail)
  */
void onDataSent(const uint8_t *mac_addr, esp_now_send_status_t status)
{
    Serial.println("!!SEND DATA!!");
}

/**** 周期処理 ****/
void loop() {
    // 送信するタイムスタンプは起動後に経過した時間(ミリ秒)
    // 送信するテキストデータは自分のMACアドレスをフォーマットに従い格納
    send_data.timestamp = millis();
    snprintf(send_data.text, sizeof(send_data.text), "FROM <%s> ", WiFi.macAddress().c_str()); 
    esp_now_send(distaddress, (uint8_t*)&send_data, sizeof(send_data));  // 実際の送信処理
    delay(100);
}


実験結果

左がボードB、右がボードAです。
(オレンジはボードBのMACアドレス、緑はボードAのMACアドレスです。)
image.png

ライブラリの作成

現在作成中。完成したら記事を書きます。

  1. https://www.espressif.com/ja-jp/solutions/low-power-solutions/esp-now 2

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?