M5StickC で超音波通信を堪能
以前、Chirpというプラットフォームを使用して可聴帯域での音声通信を試してみました。
今回は超音波での通信を試してみます。
スマホやスピーカなど音が出せれば通信ができますのでBLEやWiFiのように事前の接続設定や特別な環境準備は必要ないので非常に手軽です。
また超音波を使用すれば聴こえないのも魅力です。
目次
構成
ここではM5StickCにLEDテープを接続して、超音波で色信号を送って光らせてみます。
部品
- M5StickC
- フルカラーテープLED Neopixel
Arduinoコード
Arduino IDEでコーディングしました。Arduino IDEでのM5StickC環境の詳細は以下を参照ください。
M5StickCの内蔵マイクを使用しますので以下のマイクのサンプルコードを参考にコーディングしました。
https://github.com/m5stack/M5StickC/blob/master/examples/Basics/Micophone/Micophone.ino
音声信号の周波数解析のために以下のFFTライブラリを使用しました。
https://github.com/kosme/arduinoFFT
Neopixel用のライブラリは以下を使用しました。
https://github.com/adafruit/Adafruit_NeoPixel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
#include <M5StickC.h> #include <driver/i2s.h> #include "arduinoFFT.h" #include <Adafruit_NeoPixel.h> Adafruit_NeoPixel pixels(6, 26, NEO_GRB + NEO_KHZ800); #define PIN_CLK 0 #define PIN_DATA 34 #define READ_LEN (2 * 1024) #define SAMPLING_FREQUENCY 44100 uint8_t BUFFER[READ_LEN] = {0}; uint8_t red = 0x00, green = 0x00, blue = 0x00; uint16_t *adcBuffer = NULL; const uint16_t FFTsamples = 256; // サンプル数は2のべき乗 double vReal[FFTsamples]; // vReal[]にサンプリングしたデーターを入れる double vImag[FFTsamples]; arduinoFFT FFT = arduinoFFT(vReal, vImag, FFTsamples, SAMPLING_FREQUENCY); // FFTオブジェクトを作る unsigned int sampling_period_us; float dmax = 10000.0; void i2sInit(){ i2s_config_t i2s_config = { .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM), .sample_rate = 44100, .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // is fixed at 12bit, stereo, MSB .channel_format = I2S_CHANNEL_FMT_ALL_RIGHT, .communication_format = I2S_COMM_FORMAT_I2S, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .dma_buf_count = 2, .dma_buf_len = 128, }; i2s_pin_config_t pin_config; pin_config.bck_io_num = I2S_PIN_NO_CHANGE; pin_config.ws_io_num = PIN_CLK; pin_config.data_out_num = I2S_PIN_NO_CHANGE; pin_config.data_in_num = PIN_DATA; i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL); i2s_set_pin(I2S_NUM_0, &pin_config); i2s_set_clk(I2S_NUM_0, 44100, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO); } void mic_record_task (void* arg){ while(1){ i2s_read_bytes(I2S_NUM_0,(char*)BUFFER,READ_LEN,(100/portTICK_RATE_MS)); adcBuffer = (uint16_t *)BUFFER; fft(); vTaskDelay(100 / portTICK_RATE_MS); } } void setup() { Serial.begin(115200); M5.begin(); M5.Axp.ScreenBreath(9); pixels.begin(); pixels.setBrightness(50); sampling_period_us = round(1000000 * (1.0 / SAMPLING_FREQUENCY)); i2sInit(); xTaskCreatePinnedToCore(mic_record_task,"mic_record_task",2048,NULL,1,NULL,1); } void fft(){ for (int i = 0; i < FFTsamples; i++) { unsigned long t = micros(); vReal[i] = adcBuffer[i]; vImag[i] = 0; while ((micros() - t) < sampling_period_us) ; } FFT.Windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD); // 窓関数 FFT.Compute(FFT_FORWARD); // FFT処理(複素数で計算) FFT.ComplexToMagnitude(); // 複素数を実数に変換 int nsamples = FFTsamples/2; for (int band = 0; band < nsamples; band++) { float d = vReal[band] / dmax; Serial.print(band); Serial.print(" : "); Serial.print((band * 1.0 * SAMPLING_FREQUENCY) / FFTsamples / 1000); Serial.print("kHz : "); Serial.println(d); } //15kHz if(vReal[87] / dmax > 0.3){ red = 0xff; }else{ red = 0x00; } //16kHz if(vReal[93] / dmax > 0.3){ green = 0xff; }else{ green = 0x00; } //17kHz if(vReal[99] / dmax > 0.3){ blue = 0xff; }else{ blue = 0x00; } uint32_t RGB888 = red << 16 | green << 8 | blue; Serial.println(RGB888); for(int i=0; i<6; i++) { pixels.setPixelColor(i, RGB888); } pixels.show(); //ディスプレイ用にRGB565に変換 uint16_t RGB565 = (((RGB888 >> 19) & 0x1f) << 11) | (((RGB888 >> 10) & 0x3f) << 5) | (((RGB888 >> 3) & 0x1f)); M5.Lcd.fillScreen(RGB565); } void loop() { } |
マイクで受信した音声をFFTして周波数解析します。
以下の周波数信号を受信することでLEDの各色を点灯させます。
15kHz:赤
16kHz:緑
17kHz:青
M5StickCのディスプレイもLEDと同様に色を変更しました。RGB888をRGB565に変換して色指定しています。
参考
動作
スマホから音声を再生させて通信動作を確認しています。
Androidアプリの周波数ジェネレータを使用して正弦波を再生しています。
#M5stickC で超音波通信を超堪能
15kHzでRed
16kHzでGreen
17kHzでBlue
を送信 pic.twitter.com/C11uejwFCN— HomeMadeGarbage (@H0meMadeGarbage) November 3, 2019
15kHzの再生で赤、16kHz:緑、17kHz:青とフルカラーLEDが点灯しています。
3つ再生でLEDは白く発光します。
私は14kHz以上の音は聴こえないので超音波通信と銘打っておりますが、若い人には聴こえてしまうかもしれません。。。あしからず。
マイクのサンプリング周波数を44.1kHzとしていますので22kHzまで信号として使用できるはずです。
音楽再生への応用
音楽に超音波信号を仕込めば遠隔でのライティングも可能です。
DAWで15kHz、16kHz、17kHzの正弦波を貼って再生してみました。
楽曲に超音波まぶせば、結線いらずでライティング可能です。#M5stickC pic.twitter.com/27T7Au50bD
— HomeMadeGarbage (@H0meMadeGarbage) November 3, 2019
このようにシーケンサに事前に仕込んでもいいですし、MIDIパッドでリアルタイムに通信してもいいですし色々応用可能です。
M5StickCならコンパクトですし音声なので複数台の同期も可能でセッティング時間もかからないので、手軽にライブでのライディング演出が実現できそうですね。
ライブしたいなぁ。
はじめまして。Arduinoで超音波(スピーカーからの音)を拾って周波数を表示したいと、こちらのページを拝見しました。
M5StickCはマイクも液晶も搭載しているので、とても参考になりました。
マイクの周波数帯が関係する以外で超音波(できれば市販されている害獣除け製品)がしっかりと超音波をだしているのか?疑問に思ったためです。
*20000Hz~40000Hz程度
LEDを点灯する形で制作されている部分で、液晶に拾った周波数を表示するようなスケッチなど無理でしょうか?
失礼をお詫びして、お聞かせください。m(__)m