ESP32はESP NOWという通信方式を使って、ESP32同士でデータのやり取りが簡単にできてしまいます。
今回は、2つESP32を用意して、片方で音を録音したデータをESP NOWで転送して、もう片方で音を再生するという、片方向のトランシーバーを作ってみることしました。とりあえず動けばいいやという感じで、作っていきたいと思います。
ESP32には、便利なESP32 DevKitCを2個使用します。
送信側
回路
マイクとそのアンプ回路を用意して、音声信号をAD入力のピン(33)に入力します。
マイクとマイクアンプ回路はこんな感じです。作るのが面倒な方は、便利なマイクモジュールが売っているので、これが使えると思います。
プログラム
ネットにあったプログラムを適当に変更して、送信プログラムを作ってみました。
送信相手のMACアドレスが必要です。6行目にそのアドレスを入れてください。例としてAA.BB.CC.DD.EE.FFとなっています。
だいたい15kHzでADし、200サンプルたまったところで、ESP NOWを使ってデータを送信しています。
#include <esp_now.h> #include <WiFi.h> //Receiver Mac Address uint8_t broadcastAddress[] = { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF }; #define MIC_PIN 33 int buffer_size = 128;//8kib byte* buffer; #define LED_PIN 2 void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) { /* Serial.print("\r\nLast Packet Send Status:\t"); Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail"); */ } typedef struct struct_message {// ~ 250byte int8_t wave[200]; } struct_message; struct_message send_data; int bias = 0; void setup() { Serial.begin(9600); Serial.println("hello!"); WiFi.mode(WIFI_STA); if (esp_now_init() != ESP_OK) { Serial.println("Error initializing ESP-NOW"); return; } Serial.print("my mac address : "); Serial.println(WiFi.macAddress()); // Once ESPNow is successfully Init, we will register for Send CB to // get the status of Trasnmitted packet esp_now_register_send_cb(OnDataSent); // Register peer esp_now_peer_info_t peerInfo; memcpy(peerInfo.peer_addr, broadcastAddress, 6); peerInfo.channel = 0; peerInfo.encrypt = false; // Add peer if (esp_now_add_peer(&peerInfo) != ESP_OK) { Serial.println("Failed to add peer"); return; } adcAttachPin(MIC_PIN); analogReadResolution(10); //analogSetPinAttenuation(MIC_PIN, ADC_0db); pinMode(LED_PIN, OUTPUT); delay(100); bias = analogRead(MIC_PIN); } void loop() { digitalWrite(LED_PIN, HIGH); for (int i = 0; i < 200; i++) { int in = analogRead(MIC_PIN); int out = (in - bias); if (out < -128)out = -128; if (out > +127)out = +127; send_data.wave[i] = out; delayMicroseconds(1000000 / 15000); } digitalWrite(LED_PIN, LOW); // Send message via ESP-NOW esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &send_data, sizeof(send_data)); }
受信側
回路
出力ピンに、スピーカーを接続します。ただ直接接続すると壊れるので、トランジスタのバッファ回路を間に挟んでいます。
プログラム
#include <esp_now.h> #include <WiFi.h> #define SPEAKER_PIN 12 int buffer_size = 128;//8kib byte* buffer; #define LED_PIN 2 void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) { Serial.print("\r\nLast Packet Send Status:\t"); Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail"); } typedef struct struct_message {// ~ 250byte int8_t wave[200]; } struct_message; struct_message receive_data; void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) { digitalWrite(LED_PIN, HIGH); memcpy(&receive_data, incomingData, sizeof(receive_data)); for (int i = 0; i < 200; i++) { ledcWrite(0, receive_data.wave[i] + 128); delayMicroseconds(1000000 / 14500); } digitalWrite(LED_PIN, LOW); } void setup() { disableCore0WDT(); disableCore1WDT(); Serial.begin(115200); Serial.println("hello!"); WiFi.mode(WIFI_STA); if (esp_now_init() != ESP_OK) { Serial.println("Error initializing ESP-NOW"); return; } Serial.print("my mac address : "); Serial.println(WiFi.macAddress()); ledcSetup(0, 48 * 1000, 8); ledcAttachPin(SPEAKER_PIN, 0); pinMode(LED_PIN, OUTPUT); esp_now_register_recv_cb(OnDataRecv); } void loop() { delay(100); }
ESP NOWでデータを受信したら、PWMに1サンプルずつ出力していきます。Delayでループしていて、正確な周期が設定できないので、ループの周期が送信側と同じ感じになるように、Delayを調節しました。
結果
送信側で、チキンさんに歌ってもらいました。
タイトルは「チキンの夢物語」です。それではチキンさん。どうぞ。
ブーーーというノイズ音が聞こえます。残念ながらESP32は、WiFi通信をしているときにはA/D変換にノイズが入るようです。通信中は電源電圧も結構変動しているので、このような状態では綺麗なA/D変換は期待できないでしょう。
音質はいまいちですが、遅延はほとんどなくESP32同士を使って、片方向ですがトランシーバーができてしまいました。デジタル無線と言っていいのでしょうか。なんだか面白いです。
送信側にモバイルバッテリーをつないで、家中動き回りましたが、どこにいても受信側に声が届いていました。
試しに受信機を家の中に置いて、送信機を外へ持ち出してみました。家からみ通し30mくらいは電波が届きますが、それ以上だと電波が途切れ途切れになり、他の家の陰に入ってしまうと電波が完全に途切れてしまう感じでした。結構電波飛びますね。
ESP32とESP NOWでトランシーバーを作ってみたという記事でした。
コメント
ESP NOWでトランショーバーができると聞いて、ブログを拝見させていただきました。
見よう見まねでスケッチを書いてみたのですが、上手く動きません。公開いただいているスケッチはコンパイルは通るのですが、実際に送受信できない状況です。自分でも色々調べましたが結果、分かりませんでした。恐らくですが、add peerのあたりが上手く行かない原因ではないでしょうか。どうか今一度、サンプルスケッチを見直していただけないでしょうか。
よろしくお願い致します。
あさまる様
お返事遅くなってしまいすみません。
ブログを読んで頂きありがとうございます。
ライブラリが当時からバージョンアップしたことで、正常にコンパイルできなくなってしまったのだと思います。
時間がないためアップデートすることができません。
すみませんが、プログラムを参考に修正して頂ければと思います。