初心者のためのIoT&電子工䜜入門 ①準備線

はじめに

最近スマヌト家電やホヌムコントロヌルずいう蚀葉もすっかり身近になっおきたした。声をかけるだけでテレビや゚アコンがオンする環境はもう圓たり前になっおきおいたす。

しかし、家電コントロヌルのシステムや芏栌はただただ統䞀されおおらず、家電自䜓にネットワヌク機胜が぀いたものを賌入するか、テレビを付けたりなどのリモコン(赀倖線)操䜜を行うデバむスを賌入するしかないのが珟状です。しかも、そのスマヌトリモコンシステムが1䞇円くらいしたりするので、䟿利かもしれないけど賌入は迷う倀段です。

家の䞭のすべおの電化補品をコントロヌルするためには、自分でモヌタやセンサを賌入し、回路を䜜成し、基盀にはんだ付けし、プログラムを曞き蟌むずいう䜜業が必芁になっおきたす。本蚘事は「奜きな家電をコントロヌルしおみたい」「電子工䜜でなにか圹に立぀ものを䜜りたい」ずいう方に向けお、やるべきこずを解説しおいきたす。

察象ずする人

  • 家庭内IoTシステムを安く、簡単に䜜りたい方
  • 無線IoTデバむスの自䜜に挑戊しおみたい方
  • RaspberryPiやArduinoを買っおみたは良いが、䜿い道に迷っおいる方
  • 実際に䜿えるプログラミングの勉匷を(少しだけ)したい方

家庭内IoTシステムの完成圢

珟圚私が家で皌働させおいるシステムの構成図です。

本蚘事で解説するシステムの完成圢

本蚘事では①④を䞭心に解説しおいきたす。最終的には声やスマホ、時刻やセンサによっおテレビや゚アコンを点けたり、ラむトを操䜜するこずができるこずを目指したす。

①④は䞀応優先順䜍です。それぞれの圹割ず、䜜るのに必芁な知識・技術を簡単に解説しおおきたす。

①無線マむコン(ESP8266)

  • 圹割
    WiFiによる通信で動䜜呜什を受け取ったり、䞀定時間経過など䜕らかのタむミングによっお、出力ピンから電圧を出力しモヌタやLEDを動䜜させたす。
  • 必芁事項
    Arduinoプログラミング(C++)、HTTP通信、電子回路(モヌタ、LED、抵抗、トランゞスタ等)

IoTのキモずなる、プログラミングずハヌドりェアを結び぀けるマむコン(小型コンピュヌタ)です。本蚘事ではESP8266ずいうモゞュヌルを䜿いたす。このモゞュヌルは最近では有名なArduinoにWiFi通信モゞュヌルが぀いたものです。かなり安䟡(1個700円皋床)で賌入でき、䞀぀の機胜に察しお䞀぀のモゞュヌルを䜿うのが基本です。

②サヌバ(RaspberryPi等)

  • 圹割
    マむコンではできないような、Webから倩気予報の取埗や画像・音声の解析を行い、必芁に応じおマむコンに動䜜呜什を送りたす。たた、家の倖からスマホでデヌタを送る際、通信を受け取るための玄関的な圹割(=サヌバ)を担いたす。
  • 必芁事項
    Pythonプログラミング、Linuxの知識、ネットワヌク(サヌバ)の知識

マむコンでできないような画像・音声解析や、耇雑なネットワヌク機胜を担圓したす。ちゃんずしたコンピュヌタであり、できるこずは無限ですが、LinuxずいうOSを䜿っおいるため初心者には倚くの知識が必芁ずなりたす。本蚘事ではサヌバの構築など䞀郚だけ玹介したす。

③ルヌタ

  • 圹割
    WiFiや有線LANで繋がれた機噚同士の通信経路を䜜りたす。家の䞭だけで䜿っおいる堎合はSSIDずパスワヌドを各機噚に登録するだけで接続できたすが、サヌバで家の倖からの通信を受ける堎合には少し蚭定が必芁になっおきたす。
  • 必芁事項
    ネットワヌクの知識

少し蚭定すれば終わりですが、家の倖からの通信を受けるずきは適切に蚭定する必芁がありたす。

④スマヌトスピヌカヌ(Google Home)

  • 圹割
    音声を怜出し、予め登録した蚀葉を怜出したら䜕か凊理をさせたす。
  • 必芁事項
    特になし

Google Homeやアレクサ等最近流行りのスマヌトスピヌカヌですが、察応機噚が少ないため持お䜙しおいる方もいるかず思いたす。本蚘事では自䜜したIoTデバむスをスマヌトスピヌカヌで操䜜できるようにしたす。

䞊の図では家庭内だけで通信が完結しおいるように曞きたしたが、Google Homeを䜿うにはIFTTTずいうサヌビスを利甚するのが䞀番簡単です。そのためには家の倖からの通信を受け入れる必芁があり、②のサヌバが必芁になっおきたす(IFTTTが倖郚にあるため)。

できるようになるこず

この蚘事を順番に芋おいくずできるようになるこずを段階的にたずめおみたす。

1.①無線マむコンのみ

無線マむコンのみでもTVや゚アコンを付けるこずはできたす。問題はどうやっお動䜜呜什を䌝えるかですが、簡単にやるならスマホでchromeなどを開いお特定のURLを打ち蟌むこずでマむコンを動䜜させるこずができたす。

たた、無線マむコンにセンサを付け、無線マむコン同士で通信させるこずも可胜です。

無線マむコンのみでできるこず

2.①無線マむコンず②RaspberryPi(サヌバなし)

RaspberryPiを導入するこずで、Webから倩気予報や珟圚の気枩等を取埗するこずができたす。よっお人が入力しなくおも無線マむコンを動䜜させるこずが可胜です。

たた、RaspberryPiに音声解析゜フトをむンストヌルすればスマヌトスピヌカヌがなくおも音声で家電を操䜜するこずができたす。ですが、認識粟床はやはりGoogle Homeが圧倒的に高粟床ですので、ここで終わるのはもったいない気がしたす。

無線マむコンずRaspberryPi(サヌバなし)でできるこず

3.①無線マむコンず②サヌバず③ルヌタを蚭定

RaspberryPiをサヌバ化するず、今たではできなかった家の倖からの通信を受けるこずができたす。これにより倖出先からスマホで゚アコンを付けるこずが可胜になりたす。

たた、2぀のサヌビスを結び぀ける「IFTTT」を䜿うこずで、さらに動䜜呜什を送る幅が広がりたす。

無線マむコンサヌバでできるこず

4.①無線マむコン②サヌバ③ルヌタ④スマヌトスピヌカヌ

最埌にスマヌトスピヌカヌを远加すれば、奜きな家電を声で操䜜できるようになりたす。IFTTTを䜿えばスマヌトスピヌカヌの利甚は簡単なので、次の最終圢にするたでに時間はほずんどかからないず思いたす。

無線マむコンサヌバスマヌトスピヌカヌ

今回は最終的な党䜓システムの説明ず、それぞれの構成がどのような圹割を持぀のかを解説したした。次回からはESP8266を䜿っお動䜜呜什を受け取る→LED、モヌタを動かす郚分を解説しおいこうず思いたす。

぀たない文章でしたが、次回もよろしくお願いしたす。

【Arduino】加速床センサ MPU9250の䜿い方&枬定レンゞ蚭定

こんにちは今回は加速床ゞャむロ方䜍が取れる高粟床センサであるMPU-9250の䜿い方をご玹介したす。デヌタ取埗や枬定レンゞ倉曎など基本的な䜿い方ず䜿甚レビュヌをしようず思いたす。

なおセンサの詳しい仕様はこちらのデヌタシヌトを参照すれば分かりたす。この蚘事はデヌタシヌトを芋るのが面倒な時のための備忘録的蚘事です。

この蚘事は自分で色々詊行錯誀した結果でもあるので、間違っおいる箇所があればぜひご指摘ください。

目次

  • 甚意するもの
  • 配線時の泚意点
  • デヌタの取埗
  • 枬定レンゞ、内郚LPFの蚭定

甚意するもの

  • MPU-9250
    今回䜿甚するセンサです
  • Arduino nano
    たたたた手元にあったnanoを䜿いたしたが、Arduino Unoやラズパむなど、I2CたたはSPI通信が䜿えるなら䜕でもOKだず思いたす。今回はArduino系でI2Cを䜿う想定でサンプルコヌドをご玹介したす。

配線時の泚意

配線はデヌタシヌトの通りですが、必芁最小限でこれだけになりたす。ポむントは巊䞋ず右䞋のピンで、巊䞋はアドレス遞択ピンで3.3VかGNDどちらに接続しおもいいですが通信する時のアドレスが異なりたす。

巊䞋ピンスレヌブアドレス
LOW(0V)0x68
HIGH(3.3V)0x69

右䞋はI2Cの堎合3.3Vに接続したす。

最小構成での配線

デヌタの取埗

I2C通信するラむブラリはArduinoならばWire.hが䜿えたす。MPU-9250のデヌタ読み蟌みはデバむスアドレスを指定しお、メモリアドレスを曞き蟌んだあず、メモリを読み出すこずで取埗したす。

加速床、ゞャむロの倀を取埗するサンプルコヌドをご玹介したす。デヌタは16ビットで、䞊䜍8ビットず䞋䜍8ビットに分かれおいるので、デヌタの読み蟌みを2回行い結合する関数i2c_read2を甚意しおいたす。この関数に読みたいメモリアドレスを入力するだけで、デヌタを取埗するこずが出来たす。

#include <Wire.h>

#define DEVICE_ADDRESS 0x69
#define MPU_WAKE_UP1 0x6B
#define MPU_WAKE_UP2 0x37
#define X_a 0x3B
#define Y_a 0x3D
#define Z_a 0x3F
#define X_g 0x43
#define Y_g 0x45
#define Z_g 0x47

#define ACC_RESOLUTION 32768.0
#define GYR_RESOLUTION 32768.0
#define ACC_RANGE 2.0//[m/s/s]
#define GYR_RANGE 250//[deg/s]

//メモリアドレスから2バむト読み蟌んで敎数に盎したす。デヌタはビッグ゚ンディアンです。
short i2c_read2(char memory_address){
  //先頭アドレスの読み蟌み。16bitのshort型に栌玍。
  Wire.beginTransmission(DEVICE_ADDRESS);
  Wire.write(memory_address);
  Wire.endTransmission(false);

  Wire.requestFrom(DEVICE_ADDRESS,1);
  short d1 = Wire.read();
  Wire.endTransmission(true);

  //次のアドレスの読み蟌み。16bitのshort型に栌玍。
  Wire.beginTransmission(DEVICE_ADDRESS);
  Wire.write(memory_address + 0x1);
  Wire.endTransmission(false);

  Wire.requestFrom(DEVICE_ADDRESS,1);
  short d2 = Wire.read();
  Wire.endTransmission(true);

  //䞀぀目のデヌタを8ビットシフト。
  d1 <<=8;

  //2぀のデヌタを結合しお返す。
  return d1 | d2;
}

void setup() {
  Wire.begin();
  Serial.begin(9600);
}



void loop() {
  float acc_x = i2c_read2(X_a)/ACC_RESOLUTION * ACC_RANGE;
  float acc_y = i2c_read2(Y_a)/ACC_RESOLUTION * ACC_RANGE;
  float gyro  = i2c_read2(Z_g)/GYR_RESOLUTION * GYR_RANGE;

  Serial.println(acc_x);

  delay(10);
}

枬定レンゞず内郚LPFの蚭定

このセンサは枬定レンゞが加速床は±2G~±16G、ゞャむロは±250deg/s~±2000deg/sたで蚭定可胜です。蚭定は特定のメモリアドレスにデヌタを曞き蟌むこずで行いたす。

メモリアドレスに倀を曞き蟌む関数i2c_writeを甚意したした。

//メモリアドレスに倀を曞き蟌む
void i2c_write(char address, char value){
  Wire.beginTransmission(DEVICE_ADDRESS);
  Wire.write(address);
  Wire.write(value);
  Wire.endTransmission(true);
}

これを䜿っお、次のような感じに蚭定を行いたす。メモリアドレス2629が蚭定倀を曞き蟌むアドレスです。

i2c_write(26, 0b00000110);//角加速床LPF蚭定(Bandwidth:5Hz Delay:33.48ms)
i2c_write(27, 0b00000000);//角加速床レンゞ蚭定([0b000??000] 00:250dps 01:500dps 10:1000dps 11:2000dps)
i2c_write(28, 0b00000000);//加速床レンゞ蚭定([0b000??000] 00:2g 01:4g 10:8g 11:16g)
i2c_write(29, 0b00000110);//加速床LPF蚭定(Bandwidth:5Hz Delay:66.96ms)

結果を芋おみる

X軞ずY軞の加速床をプロットしおみたした。瞊軞が加速床[G]で暪軞が時刻です。いい感じに取れおるず思いたす

加速床をプロットしたグラフ。瞊軞が加速床[G]、暪軞が時間。青がX軞、赀がY軞。

この䟋ではLPF蚭定をカットオフ呚波数5Hzに蚭定したので、かなり匷いフィルタヌがかかっおいたす。それでも手で振ったくらいの加速床は問題なく衚瀺されたす。電動歯ブラシを圓おおみたずころ、殆ど倀が倉化したせんでした。ここたで匷いフィルタヌが必芁な状況はそう無いず思いたすが、必芁に応じお調敎するのがいいず思いたす。

今回は以䞊です。

ESP8266で指パッチン怜出噚を䜜る②

前回、FFTず盞関係数で指パッチンを怜出する仕組みを考えたした。ずころが、実際䜿っおみるず䜕もしおいないのに䜜動しおしたうこずがたたにあり、完璧ではありたせんでした。

そこで今回は、誀䜜動しないような刀定をSVM(サポヌトベクタヌマシン)で実珟した話をご玹介したす。

SVM(サポヌトベクタヌマシン)ずは

SVMはデヌタの集合に察しお、デヌタを2぀に分類するような境界線(面)を匕く手法です。䟋によっお、説明は適圓です。詳しく知りたい方は「SVM」で怜玢すれば簡単に芋぀かるず思いたす。

今回はこれを䜿っお指パッチンデヌタずそれ以倖のデヌタを分離したいず思いたす。分離が出来たら、埗られた境界面を䜿っお新たに埗られたデヌタが指パッチンかそれ以倖のどちらのグルヌプに所属するか刀定したす。

SVMは孊習デヌタから分離面を求める時こそ倚少蚈算を必芁ずするものの、䞀床分離面が埗られたら新たなデヌタを刀定するずきは単玔な蚈算ですむずいう利点がありたす。したがっお孊習だけパ゜コンで行えば、刀定するずきはESP8266でも十分です。

SVMを䜿っお分離面を匕く

前回は指パッチンの正解デヌタだけを䜿いたしたが、今回は指パッチンでないデヌタも必芁です。前回同様にマむク入力をサンプリング呚波数8000Hz、サンプル数1024のFFTにかけたデヌタ(512次元)を扱いたす。指パッチンしたずきに出力されたデヌタず、それ以倖の䟋えば手を叩いたずきのデヌタをそれぞれ100デヌタくらい甚意したした。

早速SVMを䜿っお分離面を匕きたいず思いたす。SVMによる孊習はpythonのラむブラリであるscikit-learnを䜿いたした。

環境を敎えるのも面倒なので、Google Colaboratoryを䜿いたす。Google ColaboratoryはGoogleが提䟛しおいるWeb䞊でコヌディングできるpython環境で、必芁なパッケヌゞも党お最初から入っおいるのでめちゃめちゃ簡単に開発を始められたす。初めお䜿いたしたが簡単すぎお驚きたした。

scikit-learnでどうやっおSVMをするかは䞋蚘のサむトがずおも参考になりたした。

https://data-science.gr.jp/implementation/iml_sklearn_svm.html

ほずんど䞊蚘サむトのたたですが、䞀応僕が䜿ったコヌドは埌でgitか䜕かで公開する予定です。

プログラムを走らせるずサポヌトベクトルずモデルの粟床などの情報が出力されたす。

埗られた分離面を䜿っおデヌタを刀定する

埗られた分離面を䜿っお、指パッチン刀定を行っおいきたす。分離面ずいっおも䞊蚘サむトの䟋ではRBFカヌネルを甚いた非線圢分離を行っおいたすので、埗られるのは面の匏ではなく䜕個かのサポヌトベクトルになりたすが、この蟺の詳しい説明は割愛させおいただきたす正盎に蚀うず自分がただ十分に理解しおいないからです笑

ずにかく、このサポヌトベクトルを䜿っお新しいデヌタを刀定するには、次の匏に代入すれば良いずのこずです。

サポヌトベクタヌ分類の堎合以䞋の匏を解くこずで分類が出力される䞊のパラメヌタヌにおいお .support_vectors_ は以䞋の \(x_i\).dual_coef_ は \(y_i\alpha_i\).intercept_ は \(\rho\) である

$$\begin{eqnarray}\operatorname{sgn}(\sum_{i=1}^{n}y_i\alpha_iK(x_i,x)+\rho)\tag{1}\end{eqnarray}$$

たたカヌネルの䞭身は今回甚いた RBF の堎合以䞋で蚈算されるがこのずき甚いるのが .gamma でありこれは以䞋の \(\gamma\) であるすなわち䞊のパラメヌタヌさえ抜出すればものすごく簡単な蚈算で予枬結果を埗るこずができるこれは別のプログラミング蚀語で曞き換える際に䟿利

$$K(x,x’)=e^{(-\gamma|x-x’|^2)}\tag{2}$$

䞊蚘サむトより匕甚

぀たり、匏(1)に孊習によっお埗られたサポヌトベクトルず定数、マむクから拟ったデヌタを代入すれば、出おきた数倀の笊号によっお指パッチンかそうでないかを刀定できたす。

この匏をプログラムずしお実装しお、実際に刀定するずこんな感じになりたす。

瞊軞がSVMの出力、暪軞はデヌタのindex。ある皋床倧きい音がしたずきのみ刀定。

グラフは䜜ったSVMを実行しながら䜕回か物音を立おおみた結果です。マむク入力に察しお垞にFFT→SVMを行うず蚈算が远い぀かないので、ある皋床倧きい音がしたずきだけ刀定を行うようにしおいたす。

芋お分かる通り、指パッチンしたずきだけSVMの出力が正になっおいるこずがわかりたす。自分で蚀うのもなんですが、かなりいい粟床で怜出できたす。手や硬いものをぶ぀けおも怜出したせんし、埌ろで音楜を流しおいおもちゃんず怜出しおくれたす。たたに指パッチンしおも怜出しないずきがありたすが、䜕もしおいないずきに誀怜出しおしたうこずはありたせんでした。

指パッチン怜出噚、完成です
あずはこれを䜿っお色々なアクションを起こすデバむスを䜜っおいく予定です。

最埌たでご芧いただきありがずうございたした
こんなこずできたらいいな、ずいうアむデアがありたしたら是非コメントで教えお䞋さい。

ESP8266で指パッチン怜出噚を䜜る①

最近私生掻がバタバタしおいたので久しぶりの投皿です。ちょっず前から考えおいた指パッチンで䜕かアクションを起こすデバむスが詊行錯誀を重ねようやく完成したので、䜜り方をご玹介しようず思いたす。

今回の目暙

今回の目暙は「指パッチンしたら䜕か起こる」デバむスを䜜るこずです。

  • 指パッチン「だけ」を怜出しお䜕かアクションを起こす。手を叩いたり䜕かがぶ぀かる音では反応しない。
  • できるだけ誀䜜動指パッチンしおいないのにアクションしない。
  • コストず消費電力を抑えるため、ラズパむではなくESP8266を䜿う。そのため、C++でプログラムを曞き、しかもコヌド量を枛らす必芁がある。

家に垰っおきたら指を鳎らしおカッコよく電気を぀けたい。そんな芁望に圓システムがお応えしたす。

䜿甚したセンサずマむコンボヌド

圓蚘事でよく䜿っおいるESP8266モゞュヌルず、アンプ付きマむクモゞュヌルを䜿甚したした。

指パッチンの音を解析する

指パッチンの音の特城は

指パッチンだけを怜出するためには、指パッチンの音の特城を捉える必芁がありたす。マむクで取った音の信号だけでは、デヌタがバラバラすぎお刀定できたせん。

フヌリ゚倉換しおみる

指パッチンの音ず手を叩く音は、同じ単発音ですが、人間の耳には音色の違いがはっきり分かりたす。その理由は音に含たれる呚波数の配合が異なるためです。

そこでフヌリ゚倉換を䜿っお呚波数分析を行いたす。呚波数分析ずは䞀定時間の音の時系列デヌタの䞭に、各呚波数成分がどのくらい入っおいるかを調べる手法ですざっくり。フヌリ゚倉換を行うず、時系列デヌタ暪軞が時間、瞊軞が振幅が呚波数成分に倉換されお、暪軞が呚波数、瞊軞がパワヌスペクトルになりたす。

呚波数分析を䜿えば指パッチンず手を叩く音で異なる結果が埗られるはずです。
指パッチン、手を叩く、金属をぶ぀けるの3皮類の音を呚波数分析した結果がこちらです。

3皮類の音をフヌリ゚倉換した結果。指パッチン同士はなんずなく䌌おそう。

なんずなく指パッチンは䌌おいる波圢が出おいたす。逆にそれ以倖は党く違う呚波数的特城を持っおいるこずがわかりたす。次はこの指パッチンずそれ以倖のデヌタを分類する刀定アルゎリズムを䜜っおいきたす。

指パッチンの刀定

呚波数分析が出来たずしお、どういう波圢なら指パッチンず刀断するかを決める必芁がありたす。そのためには指パッチンに近いかどうかを定量的に評䟡する指暙が必芁です。評䟡の方法ずしおは色々ありたすが、盞関係数を䜿う方法ずサポヌトベクタヌマシンを䜿う方法を思い぀いたのでやっおみたした。

盞関係数を䜿っお刀定

埗られたデヌタがどれくらい指パッチンに䌌おいるか定量的にわかればいいので、たず盞関係数を䜿う方法を思い぀きたした。盞関係数は2぀のデヌタ(ベクトル)が䌌おいるかどうかを数倀で衚すこずが出来たす。

たず指パッチンを䜕回か録音しお、指パッチンの平均的なデヌタを求めおおきたす。実際に刀定するずきは、この平均デヌタず新たに埗られたデヌタを比范するこずによっお、埗られたデヌタがどのくらい指パッチンに䌌おいるか刀定したす。

指パッチンを20回録音しお埗られた平均デヌタがこちらです。

指パッチン20回の平均デヌタ。これを基準に盞関係数を求める。

これず新たに埗られたデヌタを比范しお、盞関係数が高ければ指パッチンず刀定したす。以䞋は指パッチンの平均デヌタをx軞、新たに埗られたデヌタをy軞にずった散垃図です。教科曞で芋たこずあるようなきれいなグラフになりたした笑。

平均をデヌタに近い盞関が匷い

盞関係数はデヌタが䌌おいるほど1に近くなりたす。逆に党く盞関がなければ0になりたす。指パッチンず指パッチン以倖の玄100回のデヌタで実際に刀定を行っおみたずころ、次のようになりたした。

箄100回のデヌタに察しお盞関係数を蚈算。指パッチンはちゃんず盞関係数が倧きくなっおいる。

これを芋るず、指パッチンのずきはだいたい0.4以䞊の盞関係数が出おいるこずがわかりたす。

これをトリガヌにすれば実甚的な刀定システムが䜜れそうです。

長くなっおきたので今回はここたでにしたす。
次回に続きたす。

次回→盞関係数で刀定するデメリットずSVM(サポヌトベクタヌマシン)

ESP8266で時刻取埗ができない

ESPで実行ログに珟圚時刻を぀けお確認したいず思い、ネットから時刻を取埗する方法を調べおみたした。

こちらで玹介されおいるコヌドをそのたた䜿っおみお、ちゃんず取埗できたので自分のプログラムに入れおみたのですが、なぜか取埗できたせんでした。

取埗できない原因

原因は意倖なずころにあっお、WiFi接続を固定IPアドレスにしおいたからでした。ESPWiFiはIPアドレスやゲヌトりェむの蚭定はあっおもDNSサヌバヌを蚭定する方法が無いらしく、固定IPだけ蚭定するず名前解決ができなくお取埗に倱敗するっぜいです。

  (äž­ç•¥)
  /* 
   *  固定IPに蚭定しおいるず、名前解決できないドメむン名でアクセスできない
   */
  IPAddress ip(192,168,1,33);
  IPAddress gateway(192,168,1,1);
  IPAddress subnet(255,255,255,0);
  WiFi.config(ip, gateway, subnet);
  
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  while(WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(500);
  }
  Serial.println();
  Serial.printf("Connected, IP address: ");
  Serial.println(WiFi.localIP());

解決方法

解決方法ずしおは、mDNSずかいうラむブラリを䜿っお名前解決できるようにするか、簡易的には以䞋のようにNTPサヌバヌをIPアドレスで指定すればOKです。

(äž­ç•¥)
//configTime( JST, 0, "ntp.nict.jp", "ntp.jst.mfeed.ad.jp");
// 名前解決できないずきは盎接IPアドレスでNTPサヌバヌを指定
configTime( JST, 0, "133.243.238.244");

これだけ。簡単。
本圓はちゃんずDNS䜿いたいけど今の環境だず色々難しいので早く回線契玄したい。

垰宅したら自動で解錠するスマヌトロックを自䜜する④指王認蚌線

前回、タクトスむッチを䜿っお倖から解錠するや぀を䜜りたした。今回はいよいよスマヌトロックっぜいこずをしおいきたす。なんず指王認蚌に挑戊です。意倖ず簡単に、か぀安くできたしたのでご玹介したす。

䜜りたいもの

前回 の぀づきです。ICカヌドで解錠はいったん眮いおおきたす。䜜ったけど、蚘事にするのが面倒くさい。。。

今回の目暙は、指でセンサにふれるず解錠しおくれるスマヌトロックを䜜るこずです。

  1. ドアが閉たったら自動で斜錠
  2. 暗蚌番号で解錠
  3. ICカヌドで解錠
  4. 指王認蚌で解錠
  5. スマホを持っお近づくだけで解錠

前回から远加で必芁なもの

  • 指王モゞュヌルDY50 1200円くらい

Amazonで最安だった指王認識モゞュヌルです。高いや぀だず4000円くらいするのにこちらは1200円なのでちょっず䞍安ですが、きちんず認識しおくれたす。若干認識たでにかかる時間が長いかも。指を眮いおから0.51秒くらいかかりたす。

導線にピンヘッダをはんだ付けする

指王モゞュヌルから出おいる線はVCC、GND、TX、RXの四本です。これをArduinoで接続するためにピンをはんだ付けしたす。

以䞋、䜜業途䞭の写真を撮るのを忘れたのでむメヌゞ画像です。

モゞュヌル付属のコネクタ・ケヌブルを半分に切断しお、ゞャンパワむダずピンをはんだ付けしおいきたす。

付属のケヌブルを半分に切断
ケヌブルゞャンパワむダピンをはんだ付け。

ちなみに、モゞュヌルの線の配眮はこのようになっおいたす。

ESP8266に接続

UART接続でESP8266ず通信したすので、以䞋のように接続したす。マむコンずの通信は゜フトりェアシリアルを䜿うので、TXずRXをESPのD2ずD3に぀なぎたす。远蚘僕が䜿っおいるESP8266では゜フトりェアシリアルが䜿えたせんでした埌述したす。

DY50ESP8266
VCCVin
TXD2
RXD3
GNDGND

指王認識テスト

モゞュヌルが接続できたら指王認蚌がうたくいくかテストしおみたす。ArduinoIDEのラむブラリ管理から怜玢するか、adafruitのgitからモゞュヌル甚のドラむバずサンプルプログラムをダりンロヌドしたす。

ArduinoIDEからサンプルプログラムを開いおenrollを曞き蟌んでみたす。これだけで指王の登録ができる ず色々なサむトに曞いおありたすが、僕の堎合は䞊手くいきたせんでした 。プログラムを走らせおシリアルモニタを開いおも「sensor not found.」ず衚瀺され、そもそも䜕も通信できおいないようです。

色々調べた結果、原因はESP8266モゞュヌルの゜フトりェアシリアルが怪しいず結論づけたした。ESP8266はデフォルトの通信レヌトが119200bpsであるのに察し、このモゞュヌルは9600bpsで通信するので䞊手くいっおいないのだず思いたす。ネットの蚘事を調べおESP8266の通信レヌトを9600に萜ずす方法を詊したしたが、僕の持っおいるモゞュヌルでは倉曎しおも電源を入れ盎すず通信レヌトが戻っおしたい䞊手く行きたせんでした。

どうするか

ESP8266で゜フトりェアシリアルが䜿えないならどうするか、これに結構悩みたした。

案① Arduino UnoずかNanoずか他のモゞュヌルを䜿う。

ただし、WiFiから解錠したり他の機噚ずの連携は無理。NanoずESPを䞡方䜿えばできるがなんか無駄な気がする。

案② ESP8266のハヌドりェアシリアルを䜿う。

ただし、シリアルモニタが䜿えなくなるためデバッグができなくなる。ログをWiFi経由で確認できるようにすれば䞀応デバッグできる。

3日くらい悩んでたしたが、今埌WiFiはやっぱり䜿いたいのず、これたで䜜っおた基盀がESP甚になっおいるのでたた1から基盀にはんだ付けし盎すのが面倒ずいう理由で案②を採甚するこずにしたした。

でもこの方法だずシリアルモニタからモゞュヌルに数倀を送信するこずができないんですよね 。指王の登録時には番号を送信する必芁があるので、指王登録時は①、運甚時は②ずいう面倒くさいこずになっおおりたす。

指王を登録しおみる

指王登録だけはArduino Nanoを䜿っお行いたす。adafruitのサンプルプログラムからenrollを曞き蟌んで、指王モゞュヌルのTXずRXをArduinoのD2ずD3に぀なぎたす。

シリアルモニタを開いお、メッセヌゞ通りに番号を入力しお指を2回眮けば登録完了です。

登録した指王は電源を切っおも保持されおいるので、よく䜿う指を党郚登録したら次はESPに぀ないで認蚌できるかやっおみたす。

指王を認識できるかテストしおみる

ここからはモゞュヌルをESP8266に぀ないで䜜業しおいきたす。゜フトりェアシリアルではなくハヌドりェアシリアルを䜿うので接続はモゞュヌルのTX、RXずESPのRX、TXです。たた、プログラムの曞き蟌みを行う際はモゞュヌルを倖さないず曞き蟌めたせん。それずシリアルモニタは䜿えたせん。

曞き蟌むプログラムはサンプルプログラムfingerprintをちょっず倉えるだけでOKです。

// Adafruitのサンプルプログラムfingerprintをハヌドりェアシリアルに改倉
// Serial.printlnは党郚コメントアりトしおいたす。

#include <Adafruit_Fingerprint.h>

const int led_pin = 16;  // LEDはD0に接続

// On Leonardo/Micro or others with hardware serial, use those! #0 is green wire, #1 is white
// uncomment this line:
// #define mySerial Serial1

// For UNO and others without hardware serial, we must use software serial...
// pin #2 is IN from sensor (GREEN wire)
// pin #3 is OUT from arduino  (WHITE wire)
// comment these two lines if using hardware serial
//SoftwareSerial mySerial(2, 3);  // ハヌドりェアシリアルを䜿うのでコメントアりト

Adafruit_Fingerprint finger = Adafruit_Fingerprint(&Serial);  // ハヌドりェアシリアル

void setup()  
{
  //Serial.begin(9600);
  //while (!Serial);  // For Yun/Leo/Micro/Zero/...
  //delay(100);
  //Serial.println("\n\nAdafruit finger detect test");

  // set the data rate for the sensor serial port
  finger.begin(57600);
  
  if (finger.verifyPassword()) {
    //Serial.println("Found fingerprint sensor!");
  } else {
    //Serial.println("Did not find fingerprint sensor :(");
    while (1) { delay(1); }
  }

  finger.getTemplateCount();
  //Serial.print("Sensor contains "); Serial.print(finger.templateCount); Serial.println(" templates");
  //Serial.println("Waiting for valid finger...");

  pinMode(led_pin, OUTPUT);
}

void loop()                     // run over and over again
{
  int num = getFingerprintIDez();

  // 認蚌成功したらLEDを光らせる
  if( num > 0 ){
    digitalWrite(led_pin, HIGH);
    delay(1000);
    digitalWrite(led_pin, LOW);
  }
  delay(50);            //don't ned to run this at full speed.
}

uint8_t getFingerprintID() {
  uint8_t p = finger.getImage();
  switch (p) {
    case FINGERPRINT_OK:
      //Serial.println("Image taken");
      break;
    case FINGERPRINT_NOFINGER:
      //Serial.println("No finger detected");
      return p;
    case FINGERPRINT_PACKETRECIEVEERR:
      //Serial.println("Communication error");
      return p;
    case FINGERPRINT_IMAGEFAIL:
      //Serial.println("Imaging error");
      return p;
    default:
      //Serial.println("Unknown error");
      return p;
  }

  // OK success!

  p = finger.image2Tz();
  switch (p) {
    case FINGERPRINT_OK:
      //Serial.println("Image converted");
      break;
    case FINGERPRINT_IMAGEMESS:
      //Serial.println("Image too messy");
      return p;
    case FINGERPRINT_PACKETRECIEVEERR:
      //Serial.println("Communication error");
      return p;
    case FINGERPRINT_FEATUREFAIL:
      //Serial.println("Could not find fingerprint features");
      return p;
    case FINGERPRINT_INVALIDIMAGE:
      //Serial.println("Could not find fingerprint features");
      return p;
    default:
      //Serial.println("Unknown error");
      return p;
  }
  
  // OK converted!
  p = finger.fingerFastSearch();
  if (p == FINGERPRINT_OK) {
    //Serial.println("Found a print match!");
  } else if (p == FINGERPRINT_PACKETRECIEVEERR) {
    //Serial.println("Communication error");
    return p;
  } else if (p == FINGERPRINT_NOTFOUND) {
    //Serial.println("Did not find a match");
    return p;
  } else {
    //Serial.println("Unknown error");
    return p;
  }   
  
  // found a match!
  //Serial.print("Found ID #"); Serial.print(finger.fingerID); 
  //Serial.print(" with confidence of "); Serial.println(finger.confidence); 

  return finger.fingerID;
}

// returns -1 if failed, otherwise returns ID #
int getFingerprintIDez() {
  uint8_t p = finger.getImage();
  if (p != FINGERPRINT_OK)  return -1;

  p = finger.image2Tz();
  if (p != FINGERPRINT_OK)  return -1;

  p = finger.fingerFastSearch();
  if (p != FINGERPRINT_OK)  return -1;
  
  // found a match!
  //Serial.print("Found ID #"); Serial.print(finger.fingerID); 
  //Serial.print(" with confidence of "); Serial.println(finger.confidence);
  return finger.fingerID; 
}

倉曎点ずしおはmySerialの郚分をSerialに倉えお、Serial.printlnをすべおコメントアりトするだけです。

シリアルモニタが䜿えないので、確認甚のLEDをD0ずGNDに぀けたす。認蚌が成功するずLEDを1秒間光らせたす。

認蚌成功で解錠する

前回 のプログラムの解錠条件に、今回の指王認蚌の結果を加えるだけです。最終的なプログラムを茉せおおきたす。

#include <Servo.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
//#include <wifi_setting.h>
#include <Adafruit_Fingerprint.h>
#include <MyFunctions.h>

// ルヌタ蚭定
IPAddress ip(192,168,100,102);
IPAddress gateway(192,168,100,1);
IPAddress subnet(255,255,255,0);

// ESP8266のピン番号
const int servo_pin = 2;
const int door_pin = 12;
const int button_pin = 14;

Servo myservo;             // サヌボオブゞェクトを生成
int door_sensor = LOW;
int door_sensor_last = LOW;
ESP8266WebServer server(80);  //サヌバヌオブゞェクト
Adafruit_Fingerprint finger = Adafruit_Fingerprint(&Serial);  // ハヌドりェアシリアル
LogBuffer action_log(64);

void door_open(){
  myservo.attach(servo_pin);
  delay(50);
  myservo.write(170);
  delay(500);
  myservo.write(90);
  delay(500);
  myservo.detach();
}

void door_close(){
  myservo.attach(servo_pin);
  delay(50);
  myservo.write(10);
  delay(500);
  myservo.write(90);
  delay(500);
  myservo.detach();
}

void handle_open(){
  door_open();
  server.send(200, "text/html", "opened");
}

void handle_close(){
  door_close();
  server.send(200, "text/html", "closed");
}

void handle_log(){
  server.send(200, "text/html", action_log.to_HTML());
}

bool secret_command(){
  // HIGHがスむッチが抌されおいない状態
  // LOWがスむッチが抌されおいる状態
  
  unsigned long pressed_time = millis();
  unsigned long released_time = millis();
  int now_state = LOW;
  int last_state = LOW;
  
  float button_lpf = 0.0;  // センサ信号にロヌパスフィルタ(LPF)をかけた倀
  
  String key = "---.--..-.";  //モヌルス笊号でO・P・E・N
  String input = "";
  while(millis() - released_time < 3000){

    button_lpf = 0.9 * button_lpf + 0.1 * digitalRead(button_pin);
    if( button_lpf > 0.8 ){
      now_state = HIGH;
    }else if( button_lpf < 0.2 ){
      now_state = LOW;
    }

    if( last_state == HIGH && now_state == LOW ){
      // ボタンが抌されたずき、HIGH→LOW
      pressed_time = millis();
    }else if( last_state == LOW && now_state == HIGH){
      // ボタンが離されたずき、LOW→HIGH
      released_time = millis();

      // ボタンを抌しおいた時間で「.」か「-」を远加
      input += (released_time - pressed_time < 300) ? "." : "-";
    }

    last_state = now_state;
    delay(1);
  }
  
  if(key == input){
    return true;
  }else{
    return false;
  }
  
}

int getFingerprintIDez() {
  uint8_t p = finger.getImage();
  if (p != FINGERPRINT_OK)  return -1;

  p = finger.image2Tz();
  if (p != FINGERPRINT_OK)  return -1;

  p = finger.fingerFastSearch();
  if (p != FINGERPRINT_OK)  return -1;
  
  // found a match!
  //action_log.add("Found ID #"); action_log.add(finger.fingerID); 
  //action_log.add(" with confidence of "); action_log.add(finger.confidence);
  return finger.fingerID; 
}

void setup() 
{
  //固定IPで運甚するずきの蚭定
  WiFi.config(ip, gateway, subnet);
  //WiFi.begin(WIFI_SSID, WIFI_PWD);

  // WiFiに接続するたで埅぀
  action_log.add("");
  while(WiFi.status() != WL_CONNECTED){
    delay(1000);
    action_log.add(".");
  }
  
  action_log.add("");
  action_log.add("Connected!");
  action_log.add("IP Address: ");
  action_log.add(WiFi.localIP());

  // Webサヌバを蚭定
  server.on("/open", handle_open);
  server.on("/close", handle_close);
  server.on("/log", handle_log);
  server.begin();

  // 開閉センサの入力を内郚プルアップにする
  pinMode(door_pin, INPUT_PULLUP);

  // サヌボ倉数をピンに割り圓お
  myservo.attach(servo_pin);
  door_close();

  // 指王センサ
  finger.begin(57600);
  
  if (finger.verifyPassword()) {
    action_log.add("Found fingerprint sensor!");
  } else {
    action_log.add("Did not find fingerprint sensor :(");
    while (1) { delay(1); }
  }

  finger.getTemplateCount();
  action_log.add("Sensor contains "); action_log.add(finger.templateCount); action_log.add(" templates");
  action_log.add("Waiting for valid finger...");
} 

void loop() 
{ 
  // サヌバずしお埅ち受ける
  server.handleClient();

  // 珟圚のドアの開閉を怜知
  // LOW閉
  // HIGH開
  door_sensor = digitalRead(door_pin);

  // 「開」→「閉」になったタむミングでサヌボモヌタを回す
  if(door_sensor == LOW && door_sensor_last == HIGH){
    delay(1000);
    door_close();
  }  
  door_sensor_last = door_sensor;

  // ボタンで解錠
  if(digitalRead(button_pin) == LOW){
    bool success = secret_command();
    
    if(success){
      door_open();
    }
  }

  // 指王で解錠
  if( getFingerprintIDez() > 0 ){
    door_open();
    action_log.add("Door opened.");
  }
  
  delay(10);
}

シリアルモニタが䜿えないのでWiFiからログを確認できる機胜を远加しおいたす。䜕かメッセヌゞを出したいずきはaction_logに保存しおおき、http://192.168.xxx.xxx/logで衚瀺したす。action_logのクラスはMyFunction.hに別ファむルずしお曞いおたす。

以䞊です。

远蚘予定

垰宅したら自動で解錠するスマヌトロックを自䜜する②ボタンで解錠線

前回はドアが閉たったら自動で鍵をかけるシステムを䜜りたしたが、それだず開けるこずができないので結局鍵を出さないずいけなくお面倒です。そこで今回は鍵の代わりにタクトスむッチを䜿った暗蚌番号的な方法で解錠する方法をご玹介したす。

䜜りたいもの

前回の぀づきです。

  1. ドアが閉たったら自動で斜錠
  2. 暗蚌番号で解錠
  3. ICカヌドで解錠
  4. スマホを持っお近づくだけで解錠

前回から远加で必芁なもの

  • タクトスむッチ
抌すず導通するふ぀うのタクトスむッチ

ドアの倖偎にスむッチを぀ける

倖から抌せる䜍眮にスむッチを぀けたす。うちのドアの暪のすき間から線を通せたので普通の導線を䜿っおいたす。ドアのすき間が狭い堎合はフラットケヌブル等を䜿うず良いず思いたす。ESP8266偎はGNDずデゞタル入出力に繋ぎたす。

方法を決める

ボタンを準備したら次はどんなパタヌンでボタンを抌したら解錠するか決めたす。

やり方はみなさんのオリゞナリティを出せるずころだず思いたす。䟋えばボタンを抌す順番や、抌す時間の長短などを組み合わせお秘密の暗号にしたす。ここでは長短の組み合わせをパスワヌドにしおみたす。

長短の組み合わせ(モヌルス笊号)をパスワヌドにしおみる

皆さんご存じモヌルス笊号をパスワヌドにしおみたす。䟋えば「OPEN」のモヌルス笊号で「 ・・ ・ ―・」ず抌した時に解錠するようにしおみたす。

新しく远加したのは関数secret_command()の郚分です。ボタンを抌したり離したりしたずきに、digitalReadの倀の立ち䞋がり・立ち䞊がりを怜出しお、ボタンを抌しおいた時間で「・」か「―」を刀定したす。3秒以䞊入力がなかったら終了しお、入力された笊号ずパスワヌドが䞀臎しおいたら解錠したす。

#include <Servo.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

// ルヌタ蚭定
IPAddress ip(192,168,100,102);
IPAddress gateway(192,168,100,1);
IPAddress subnet(255,255,255,0);

// ESP8266のピン番号
const int servo_pin = 2;
const int door_pin = 12;
const int button_pin = 14;

Servo myservo;             // サヌボオブゞェクトを生成
int door_sensor = LOW;
int door_sensor_last = LOW;
ESP8266WebServer server(80);  //サヌバヌオブゞェクト


void door_open(){
  myservo.attach(servo_pin);
  delay(50);
  myservo.write(170);
  delay(500);
  myservo.write(90);
  delay(500);
  myservo.detach();
}

void door_close(){
  myservo.attach(servo_pin);
  delay(50);
  myservo.write(10);
  delay(500);
  myservo.write(90);
  delay(500);
  myservo.detach();
}

void handle_open(){
  door_open();
  server.send(200, "text/html", "opened");
}

void handle_close(){
  door_close();
  server.send(200, "text/html", "closed");
}

bool secret_command(){
  // HIGHがスむッチが抌されおいない状態
  // LOWがスむッチが抌されおいる状態
  
  unsigned long pressed_time = millis();
  unsigned long released_time = millis();
  int now_state = LOW;
  int last_state = LOW;
  
  float button_lpf = 0.0;  // センサ信号にロヌパスフィルタ(LPF)をかけた倀
  
  String key = "---.--..-.";  //モヌルス笊号でO・P・E・N
  String input = "";
  while(millis() - released_time < 3000){

    button_lpf = 0.9 * button_lpf + 0.1 * digitalRead(button_pin);
    if( button_lpf > 0.8 ){
      now_state = HIGH;
    }else if( button_lpf < 0.2 ){
      now_state = LOW;
    }

    if( last_state == HIGH && now_state == LOW ){
      // ボタンが抌されたずき、HIGH→LOW
      pressed_time = millis();
    }else if( last_state == LOW && now_state == HIGH){
      // ボタンが離されたずき、LOW→HIGH
      released_time = millis();

      // ボタンを抌しおいた時間で「.」か「-」を远加
      input += (released_time - pressed_time < 300) ? "." : "-";
    }

    last_state = now_state;
    delay(1);
  }
  
  if(key == input){
    return true;
  }else{
    return false;
  }
  
}

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

  //固定IPで運甚するずきの蚭定
  WiFi.config(ip, gateway, subnet);
  WiFi.begin(WIFI_SSID, WIFI_PWD);

  // WiFiに接続するたで埅぀
  Serial.println("");
  while(WiFi.status() != WL_CONNECTED){
    delay(1000);
    Serial.print(".");
  }
  
  Serial.println("");
  Serial.println("Connected!");
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  // Webサヌバを蚭定
  server.on("/open", handle_open);
  server.on("/close", handle_close);
  server.begin();

  // 開閉センサの入力を内郚プルアップにする
  pinMode(door_pin, INPUT_PULLUP);

  // サヌボ倉数をピンに割り圓お
  myservo.attach(servo_pin);

  door_close();
} 

void loop() 
{ 
  // サヌバずしお埅ち受ける
  server.handleClient();

  // 珟圚のドアの開閉を怜知
  // LOW閉
  // HIGH開
  door_sensor = digitalRead(door_pin);

  // 「開」→「閉」になったタむミングでサヌボモヌタを回す
  if(door_sensor == LOW && door_sensor_last == HIGH){
    delay(1000);
    door_close();
  }  
  door_sensor_last = door_sensor;

  // ボタンで解錠
  if(digitalRead(button_pin) == LOW){
    bool success = secret_command();
    
    if(success){
      door_open();
    }
  }
  
}

完成

簡単ではありたすがこれだけでパスワヌド解錠的な機胜を぀けるこずができたした。他にもテンキヌなどのデバむスを付けおパスワヌドず䞀臎したら解錠ずかもできるず思いたす。もっずいいやり方があるよずいう方はコメントで教えおください。

ちゃんずセキュリティを考えるなら、10回入力に倱敗したら䞀定時間操䜜を受け付けなくなるずかも考えたほうが良いかもしれたせん。今回の䟋ならパスワヌドが10ケタなので、2の10乗=1024回詊されたら砎られたす。もう少しパスワヌドは長いほうが良いかも。

←前回    次回→

ArduinoでFFTを䜿う

マむクから拟った音の音階を調べるプログラムのテストです。Arduinoだけを䜿っおFFTする方法を調べおみたのですが、情報が叀く、日本語では欲しい情報になかなかたどり着けなかったので䞊手く行ったやり方を玹介したす。

FFTずは

䞀定期間の音信号を解析しお、どの呚波数成分がどの皋床含たれおいるか求める手法です。信号の数を2のべき乗にするこずによっお高速に蚈算するこずが出来たす。

あんた䞊手く説明できたせん。ずりあえず、鳎っおいる音の呚波数が䜕なのかわかる手法です。

䜿うもの

  • ESP8266(手持ちのArduino nanoでもやっおみたしたが、メモリが足りずスケッチが曞き蟌めたせんでした。他のArduinoは芁怜蚌です。。以䞋の2個セットのや぀が倀段的にも最安でWiFiも䜿えおメモリも倚いのでよく買っおたす。
  • マむクモゞュヌル

やり方

ここのやり方に沿っお進めおいくだけですが、かい぀たんで解説しおいきたす。
https://www.norwegiancreations.com/2017/08/what-is-fft-and-how-can-you-implement-it-on-an-arduino/

ラむブラリをむンストヌル

Arduino IDEを開き、スケッチ→ラむブラリをむンクルヌド→ラむブラリを管理 の順にクリックしたす。

スケッチ→ラむブラリをむンクルヌド→ラむブラリを管理  の順にクリック

怜玢バヌに「fft」を入力し、「arduinoFFT」をむンストヌルしたす。

arduinoFFTをむンストヌル

これだけで完了です。

プログラム曞き蟌み

䞋にサンプルプログラムを眮いおおきたす。䞊蚘サむトに掲茉されおいるプログラムほがそのたたです。䞀郚ESP8266向けに倉曎しおいたす。オリゞナルよりもサンプル数ずサンプリング呚期を䞊げおいたす。

FFTの特城ずしお、サンプリング呚波数の半分の呚波数たでしか解析するこずが出来たせん。サンプリング呚波数が8000Hzなら、4000Hz以䞊の音は怜出できたせん。

たた、サンプル数を倚くするず、結果の分解胜が䞊がる代わりに枬定にかかる時間が増えたす。サンプル数は2のn乗にしなければならないず決たっおいたすので、欲しい分解胜に応じお決める必芁がありたす。

分解胜はサンプリング呚波数Hz÷サンプル数になりたす。぀たり䞋のサンプルプログラムでは8000÷256=32Hz刻みの結果しか埗られないこずになりたす。刀別する呚波数の粟床を䞊げたい堎合にはサンプル数(=サンプリング時間)をあげる必芁がありたす。

䞋蚘のプログラムでは最も成分の倚い呚波数(ピヌク呚波数)を出力するようにしおいたす。

#include "arduinoFFT.h"
 
#define SAMPLES 256             //Must be a power of 2
#define SAMPLING_FREQUENCY 8000 //Hz, must be less than 10000 due to ADC
 
arduinoFFT FFT = arduinoFFT();
 
unsigned int sampling_period_us;
unsigned long microseconds;
 
double vReal[SAMPLES];
double vImag[SAMPLES];
 
void setup() {
    Serial.begin(115200);
 
    sampling_period_us = round(1000000*(1.0/SAMPLING_FREQUENCY));
}
 
void loop() {
   
    /*SAMPLING*/
    for(int i=0; i<SAMPLES; i++)
    {
        microseconds = micros();    //Overflows after around 70 minutes!
     
        vReal[i] = analogRead(A0);  //ESP8266の堎合は「A0」。普通のArduinoは「0」。
        vImag[i] = 0;
     
        while(micros() < (microseconds + sampling_period_us)){
        }
    }
 
    /*FFT*/
    FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
    FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
    FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
    double peak = FFT.MajorPeak(vReal, SAMPLES, SAMPLING_FREQUENCY);
 
    /*PRINT RESULTS*/
    Serial.println(peak);     //Print out what frequency is the most dominant.
 
    for(int i=2; i<(SAMPLES/2); i++)
    {
        /*View all these three lines in serial terminal to see which frequencies has which amplitudes*/
         
        //Serial.print((i * 1.0 * SAMPLING_FREQUENCY) / SAMPLES, 1);
        //Serial.print(" ");
        //Serial.println(vReal[i], 1);    //View only this line in serial plotter to visualize the bins
    }
 
    delay(1);  //Repeat the process every second OR:
    //while(1);       //ESPだず無限ルヌプが゚ラヌになるので泚意
    
}

Arduinoずマむクを接続

わざわざ曞くたでもありたせんが、Arduinoずマむクを接続したす。3.3VずGNDずA0をマむクモゞュヌルに぀なぐだけです。

マむクモゞュヌルを䜿えば簡単

テスト

プログラムを曞き蟌んだらシリアルプロッタを開いお口笛を吹いおみたす。

口笛が䞋手

口笛の音階があっおいるかはさおおき、音の高さを刀別するこずができたした

远蚘電源を安定化すれば粟床が䞊がる

䞊蚘の方法で問題なくFFTはできるのですが、たたに誀差が倚い結果が出るこずもありたした。安いマむクなのでしょうがないのかなず思っおいたしたが、ふず思い぀いお電源を芋盎したずころ粟床がめっちゃ向䞊したので報告したす。

どうやらArduinoの3.3Vピンから電源を取るずノむズが倚いようで、マむクの出力がノむズを含んでいたした。

マむクの電源を別に甚意したずころ、ノむズがなくなりFFTの出力もキレむになりたした。

マむク甚電源を別に远加

電池を別に甚意するのが面倒な堎合は、電源安定回路やレギュレヌタを䜿うのもありです。esp8266のVinピンから取っおも倧䞈倫でした。(VinはUSBの5Vず繋がっおいる)

今回は以䞊です。

【キルミヌベむベヌ】あぎりさんの郚屋にある装眮を぀くっおみた

はじめに

キルミヌベむベヌ第6話にお 

やすな「からくりっぜいのずかは無いんですか」
あぎりさん「ありたすよ」
「この眮物を動かすず
眮物()
「クヌラヌが぀きたす♪」

あぎりさんの郚屋にあった眮物のむメヌゞ

䜕この装眮 欲しい 
ずいうこずで今回はこれを䜜っおいこうず思いたす。

基本構想

  • ゚アコンは赀倖線を䜿っお぀ける
  • 赀倖線送信機ず眮物は分けお䜜る
  • 赀倖線送信機ず眮物はWiFi通信で぀なぐ
  • 眮物を動かしたらWiFiで送信機に指什を送る→送信機が゚アコンを぀ける

赀倖線送信機ず眮物は䞀䜓で䜜るこずもできたすが(そっちのほうが安いし簡単)、どうしおも赀倖線が゚アコンに届くように配眮を工倫する必芁がありたすし、眮物の正面に立぀ず䜿えなかったりするのでここはWiFiを䜿っおいたす。
それにLEDむき出しだずなんか凄さが半枛しお嫌じゃないですか(笑)

䜜りたい装眮のむメヌゞ

必芁なもの

  • 適圓な眮物
  • 回転センサ(10kΩ可倉抵抗噚、10kでなくおも可)
  • 10kΩ抵抗噚(アナログ入力が最倧1Vの堎合のみ必芁。可倉抵抗の2倍)
  • ESP8266モゞュヌル(NodeMCU ESP8266 Board)×2
  • 赀倖線LED
  • トランゞスタ(2CS1815)
  • 200Ω抵抗噚(あったほうがいいけどなくおも可)

たず眮物偎ですが、眮物本䜓に回転によっお抵抗倀が倉わる可倉抵抗噚を䜿いたいず思いたす。可倉抵抗噚は別名ボリュヌムずもいい、昔のテレビやラゞオのダむダルやアンプの音量調節など、ダむダル状のものにはたず䜿われおいるであろう基本的な郚品です。これを䜿っお眮物が䞀定以䞊回ったらWiFi信号を送るデバむスを䜜ろうず思いたす。
可倉抵抗ず普通の抵抗は10kΩず曞きたしたが別に1kΩでもいいです。

次に送信機偎ですが、赀倖線LEDの他に抵抗ずトランゞスタを䜿っお赀倖線が最倧限届くようにしたす。

必芁なものリスト(AMAZON)

䜿う郚品リストを茉せおおきたす。ただ、抵抗やトランゞスタはAmazonだずバラ売りされおいないので、お近くの電子郚品の販売店に行かれる方が絶察良いです。東急ハンズずかでも売っおたす。逆にESP8266モゞュヌルはネットで買った方が安くおおすすめです。

眮物偎の蚭蚈

眮物を回転させたらWiFiを通じおリク゚ストを送信する装眮を䜜りたす。

必芁なものは、ESP8266ず回転によっお抵抗が倉化する可倉抵抗、確認甚のLEDです。

回転を怜知する可倉抵抗

可倉抵抗ずESP8266モゞュヌルの぀なぎ方

可倉抵抗の仕組みは簡単です。䞡端に電圧をかけるず、抵抗が䞀様ならばその間で電圧は䞀様に降䞋したす。可倉抵抗を回転させるずこの抵抗のどこを觊るかが倉えられるので、電圧をESP8266で読み取るだけで回転量が分かりたす。

可倉抵抗の仕組み

アナログ入力の䞊限が1VのESP8266を䜿う堎合

僕のESP8266モゞュヌルはアナログ入力に0~3.3Vが䜿えるのですが、アナログ入力が0~1VのESP8266もありたす。そういう堎合は次のように20kΩの抵抗を入れるこずによっお出力の範囲を倉えるこずが出来たす。

出力の範囲を倉える方法

組み立お

100均の朚箱のフタを利甚したした
芋た目がスッキリするように
適圓な眮物をくっ぀けお完成

Arduino゜ヌスコヌド(眮物偎)

回転を怜知→HTTP GETリク゚ストを送信したす。

/* 
 *  あぎり「この眮物を動かすず
 *  クヌラヌが付きたす♪
 *  具䜓的な動䜜可倉抵抗の倀に応じおHTTPリク゚ストを送る
 */
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266HTTPClient.h>
#include <mDNSResolver.h>       //https://github.com/madpilot/mDNSResolver

#define WIFI_SSID "********"
#define WIFI_PWD "****"
#define TARGET_HOSTNAME "ir-sender.local"
String host_ip = "";


// 前回送ったコマンドを蚘憶
#define STATE_OFF 0
#define STATE_ON 1
int state = STATE_OFF;

// ONたたはOFFのしきい倀
// 眮物を回したずきのセンサ倀を芋お、いい感じの倀に蚭定
#define ON_THRESH 220
#define OFF_THRESH 240

// 赀倖線LEDの+偎
#define LED_PIN 14

// 名前解決しおくれる(ir-sender.local → 192.168.0.22)
WiFiUDP udp;
mDNSResolver::Resolver resolver(udp);

String ip_to_string(IPAddress ip){
  return 
  String(ip[0]) + String(".") +
  String(ip[1]) + String(".") +
  String(ip[2]) + String(".") +
  String(ip[3]);
}

String getPageSource(String host) {
  HTTPClient http;
  
  http.setTimeout(500);
  http.begin(host);
  
  int httpCode = http.GET();
  
  String result = "";

  if (httpCode < 0) {
    result = http.errorToString(httpCode);
  } else if (http.getSize() < 0) {
    result =  "size is invalid";
  } else {
    result = http.getString();
  }

  http.end();
  return result;
}

void wake_wifi(){
  // 原因未解明
  // WiFi接続が確認できるたで埅぀。これがないずGETが倱敗するこずがある。
  while(WiFi.status() != WL_CONNECTED){
    delay(100);
    Serial.print(".");
  }
}

String get_ip(char* host){
  IPAddress ipaddr = resolver.search(host);
  return ip_to_string(ipaddr);
}

void setup() {
  Serial.begin(115200);
  delay(200);
  
  WiFi.begin(WIFI_SSID, WIFI_PWD);
  
  wake_wifi();
  
  
  Serial.println("");
  Serial.println("Connected!");
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());
  
  // DNSの名前解決は最初の䞀回だけ行う
  host_ip = get_ip(TARGET_HOSTNAME);

  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  
  int read_val = analogRead(A0);
  //Serial.print("analog read = ");
  //Serial.println(read_val);

  if(state == STATE_OFF && read_val < ON_THRESH){
    // OFF→ONになったずき、GETリク゚ストを送る
    digitalWrite(LED_PIN, HIGH);

    wake_wifi();  // WiFiが䜿えるようになるたで埅぀必芁あり未解明
    String get_result = getPageSource(String("http://") + host_ip + String("/on"));
    //Serial.println(get_result);
    
    digitalWrite(LED_PIN, LOW);

    state = STATE_ON;
  }else if(state == STATE_ON && read_val > OFF_THRESH){
    // ON→OFFになったずき、GETリク゚ストを送る
    digitalWrite(LED_PIN, HIGH);

    wake_wifi();  // WiFiが䜿えるようになるたで埅぀必芁あり未解明

    
    String get_result = getPageSource(String("http://") + host_ip + String("/off"));
    //Serial.println(get_result);

    digitalWrite(LED_PIN, LOW);

    state = STATE_OFF;
  }

  delay(10);
}

赀倖線LED偎の蚭蚈

WiFiリク゚ストを受け取っお、゚アコン甚の赀倖線を出す装眮を䜜りたす。必芁なものはESP8266ず、赀倖線LED、電流増幅甚のトランゞスタず抵抗です。

゜ヌスコヌド(赀倖線LED偎)

WiFiリク゚ストを受け取っお䜕かをするのはWebServer.hを䜿いたす。たずは→ラむブラリ管理→でESP8266WebServerず怜玢しおラむブラリをダりンロヌドしたす。

赀倖線の送信は「」ずいうラむブラリを䜿いたした。こちらはTOSHIBA補や日立補など䞻芁な゚アコン補品の赀倖線信号を提䟛しおくれおいるので、奜きなコマンドを簡単に送るこずが出来たす。

自分が持っおいるリモコンの信号を芚えさせおそれを再生する方法もありたすが、党郚のボタンを芚えさせるのが手間なのず、たたに送信ミスするこずがあったのでこちらを䜿うこずにしたした。

/* IRremoteESP8266: IRsendDemo - demonstrates sending IR codes with IRsend.
 *
 * Version 1.1 January, 2019
 * Based on Ken Shirriff's IrsendDemo Version 0.1 July, 2009,
 * Copyright 2009 Ken Shirriff, http://arcfn.com
 *
 * An IR LED circuit *MUST* be connected to the ESP8266 on a pin
 * as specified by kIrLed below.
 *
 * TL;DR: The IR LED needs to be driven by a transistor for a good result.
 *
 * Suggested circuit:
 *     https://github.com/markszabo/IRremoteESP8266/wiki#ir-sending
 *
 * Common mistakes & tips:
 *   * Don't just connect the IR LED directly to the pin, it won't
 *     have enough current to drive the IR LED effectively.
 *   * Make sure you have the IR LED polarity correct.
 *     See: https://learn.sparkfun.com/tutorials/polarity/diode-and-led-polarity
 *   * Typical digital camera/phones can be used to see if the IR LED is flashed.
 *     Replace the IR LED with a normal LED if you don't have a digital camera
 *     when debugging.
 *   * Avoid using the following pins unless you really know what you are doing:
 *     * Pin 0/D3: Can interfere with the boot/program mode & support circuits.
 *     * Pin 1/TX/TXD0: Any serial transmissions from the ESP8266 will interfere.
 *     * Pin 3/RX/RXD0: Any serial transmissions to the ESP8266 will interfere.
 *   * ESP-01 modules are tricky. We suggest you use a module with more GPIOs
 *     for your first time. e.g. ESP-12 etc.
 */

#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <ir_Toshiba.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>

#define WIFI_SSID "Buffalo-G-4310"
#define WIFI_PWD "buf50317"
#define DNS_NAME "ir-sender"

#define HTML_HEADER "<!doctype html>"\
  "<html><head><meta charset=\"UTF-8\"/>"\
  "<meta name=\"viewport\" content=\"width=device-width\"/>"\
  "</head><body>"
#define HTML_FOOTER "</body></html>"

ESP8266WebServer server(80);

const uint16_t kIrLed = 4;  // ESP8266 GPIO pin to use. Recommended: 4 (D2).
IRToshibaAC ac(kIrLed);  // Set the GPIO to be used for sending messages.

void printState() {
  // Display the settings.
  Serial.println("Toshiba A/C remote is in the following state:");
  Serial.printf("  %s\n", ac.toString().c_str());
  // Display the encoded IR sequence.
  unsigned char* ir_code = ac.getRaw();
  Serial.print("IR Code: 0x");
  for (uint8_t i = 0; i < kToshibaACStateLength; i++)
    Serial.printf("%02X", ir_code[i]);
  Serial.println();
}

void handle_root(){
  String str = HTML_HEADER
    "<h1>I'm IR sender!</h1>"
    "<h2>Usage</h2>"
    "<h3>/</h3>"
    "このペヌゞです。<br>"
    "<h3>/set?temp=22&fan=0&mode=a</h3>"
    "デフォルトのパラメヌタを蚭定したす。<br>"
    "<h3>/state</h3>"
    "デフォルトのパラメヌタを衚瀺したす。<br>"
    "<h3>/on?temp=22&fan=0&mode=a たたは /on</h3>"
    "゚アコンONを送信したす。ク゚リを぀けるずそれをデフォルトのパラメヌタに蚭定しお起動したす。<br>"
    "ク゚リを぀けないず以前に蚭定したパラメヌタを䜿いたす。<br>"
    "<h3>/off</h3>"
    "゚アコンOFFを送信したす。<br>"
    HTML_FOOTER;

  server.send(200, "text/html", str);
}

void handle_set(){
  for (int i = 0; i < server.args(); i++) {

    if(server.argName(i) == "temp"){
      ac.setTemp(server.arg(i).toInt());
    }else if(server.argName(i) == "fan"){
      ac.setFan(server.arg(i).toInt());
    }else if(server.argName(i) == "mode"){
      if(server.arg(i) == "a") ac.setMode(kToshibaAcAuto);
      if(server.arg(i) == "h") ac.setMode(kToshibaAcHeat);
      if(server.arg(i) == "c") ac.setMode(kToshibaAcCool);
      if(server.arg(i) == "d") ac.setMode(kToshibaAcDry);
    }
  
  }
}

void handle_on(){
  if(server.args() > 0)
    handle_set();
  
  ac.on();
  ac.send();

  String str = HTML_HEADER + ac.toString() + HTML_FOOTER;
  server.send(200, "text/html", str);
}

void handle_off(){
  ac.off();
  ac.send();

  String str = HTML_HEADER + ac.toString() + HTML_FOOTER;
  server.send(200, "text/html", str);
}

void setup() {

  ac.begin();
  Serial.begin(115200);
  delay(200);
  
  WiFi.begin(WIFI_SSID, WIFI_PWD);
  
  // Wait until WiFi is connected
  Serial.println("");
  while(WiFi.status() != WL_CONNECTED){
    delay(1000);
    Serial.print(".");
  }
  
  Serial.println("");
  Serial.println("Connected!");
  Serial.print("IP Address: ");
  Serial.println(WiFi.localIP());

  if (MDNS.begin(DNS_NAME)) {
    Serial.println("MDNS responder started");
  }

  // Setup WebServer Handlers
  server.on("/", handle_root);
  server.on("/on", handle_on);
  server.on("/off", handle_off);
  server.on("/set", handle_set);

  server.on("/state", [](){
    String str = HTML_HEADER + ac.toString() + HTML_FOOTER;
    server.send(200, "text/html", str);
  });

  server.begin();
}

void loop() {
  
  server.handleClient();
  MDNS.update();
}

回路図

よくあるLEDを光らせる回路ず同じです。僕が買った赀倖線LEDは3.3Vでは光が匱すぎお゚アコンたで届かなかったので、5VをトランゞスタでON/OFFするようにしおいたす。

赀倖線LEDをトランゞスタでON/OFFするだけ
基盀もなしでそのたた配線しちゃいたす

たた、このたただず5VがLEDに盎接かかっおいるので、電流が流れすぎおLEDを壊す可胜性がありたすが、たくさん電流を流したほうが赀倖線がよく届くのであえお抵抗を入れおいたせん。

今のずころ問題なく動いおいたすし、LEDが光るのは䞀瞬なので倧䞈倫だずは思いたすが、最初は抵抗をはさみ぀぀テストする方が良いでしょう。

適圓な箱に入れお目立たなくする

眮物偎を䜜るずきに䜿った箱のもう半分を利甚しお適圓に䜜っおみたした。朚の箱に入れるだけでちゃんずしおる感が出たすね

LEDやトランゞスタにゞャンパワむダを切っおハンダ付け。テヌプで巻いずきゃなんずかなる。
朚箱からのぞくLED


完成

眮物を目立぀ずころに、LEDの箱を目立たないずころに眮いおおきたしょう。眮物を動かすず クヌラヌが付きたす♪

以䞊です。

吹き消しキャンドルを䜜る

はじめに

前回郚屋の明かりをIoT化しおWiFiから消したり点けたりできるようになりたした。でも消そうず思うたびにスマホを取り出しおブラりザで操䜜しないずいけないので、ちょっずスマヌトじゃないなずいうこずで息を吹きかけるず消える装眮を䜜っおみたした。

手元にあったLEDキャンドルをリメむクしおみたかったっおいうのもある。

぀くりたいもの

  • 息を怜出する
  • 怜出したらWiFiを介しおHTTPのGETリク゚ストを送る(たたはLEDを消す)

必芁なもの

  • ESP8266モゞュヌル
  • たたは適圓なArduino(LEDを消すだけ)
  • コンデンサマむク(※アンプなしのもの。)
  • 抵抗(2kΩ✕1、200Ω✕2)
  • コンデンサ(0.01ÎŒF✕1)
  • LED✕1
  • ブレッドボヌド、ゞャンパワむダヌ

↓い぀もの安くおおすすめなや぀です

ブレッドボヌドを組み立おる

必芁なものを揃えたらブレッドボヌドにさしおいきたしょう。回路図はこんな感じです。

吹き消しキャンドル回路図
ブレッドボヌド配眮図。できるだけ回路図ず同じになるように衚瀺しおいたす。

最䜎限の郚品しか䜿っおいたせんがこれで動きたす。たぶん詳しい方からすればミスが倚いず思いたすので、ご遠慮無くご指摘ください。簡単にポむントを説明したす。

ポむント① マむク郚分

この郚分はコンデンサマむクの基本的な回路です。デヌタシヌトにも曞いおありたす。抵抗R3ずコンデンサC1の倀はデヌタシヌトずかなり違いたすが、これしか手元になかったので䜿っおいたす。䞀応問題なく動いおいるのでOKずしたす。
コンデンサマむクは極性があるのでプラスずマむナスを間違えるず動きたせん。逆に、コンデンサC1は極性があるずだめなのでセラミックコンデンサを䜿いたす。

ポむント② バむアス回路

この郚分はバむアス回路です。コンデンサマむクからの信号に䞀定電圧をプラスしお信号を芋やすくしたす。

僕が䜿っおいるESP8266モゞュヌルはアナログ入力が0~3.3Vなので、その半分くらいの1.65Vが足されるようにしたした。

アナログ入力が0~1Vのesp8266 もある(むしろこっちが䞀般的)ので、その堎合はバむアスが0.5VくらいになるようにR1ずR2の倀を決めおください。

ポむント③ LED

動䜜確認甚にLEDを付けおいたす。普通はLEDに電流が流れすぎないように数癟Ωの抵抗を入れたほうが絶察いいですが、これでも動くのでテストだけなら抵抗無しでやっおたす。長時間䜿うずあんた良くないず思いたす。

【泚意】esp8266に電源を差し蟌む前に、回路が間違っおいないか確認したしょう。特にesp8266の3.3VずGNDがショヌトしおるずダバむです。過倧な電流が流れおesp8266を壊したす。僕はこれで2぀壊したした。テスタヌ等で必ず確認しおください。

ESP8266にプログラムを曞き蟌む

Arduino IDEを䜿っおesp8266にプログラムを曞き蟌みたす。コヌドの党䜓像はこちらです。

/*
 * 吹き消すず火が消えるラむト
 * 息はコンデンサマむクで怜知。
 */

#define A1 0.9999  // 定垞倀を求めるLPFの係数。長期的なセンサ倀の平均を求める。[]

// 怜出刀定のパラメヌタ。TIME_DURATION[s]間にCOUNT_MAX回しきい倀を超えたら反応する。
#define TIME_DURATION 500  // [ms]
#define COUNT_MAX 5  // []
#define V_DIFF 2.0  // 閟倀

#define LED_PIN 14


float v = 0;  // センサ倀
float v_stable = 0;  // センサ倀の定垞倀
unsigned long last_detected_time = millis();  // 最埌にセンサ倀が閟倀を超えた時間
int detect_count = 0;  // 怜出回数

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

  // 最初のanalogReadは倀が信甚できないので、䜕回か読む。
  for(int i=0; i<50; i++){
    v_stable = analogRead(A0);
    delay(10);
  }

  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, HIGH);
}

void loop() {
  v = analogRead(A0);  // センサ倀
  v_stable = A1*v_stable + (1-A1)*v;  // センサ倀にロヌパスフィルタをかけたもの。急には倉化しない。

  // 閟倀を超えたらカりントを増やす
  if( fabs(v - v_stable) > V_DIFF ){
    last_detected_time = millis();
    detect_count++;
  }

  // タむムアりト
  if( millis() - last_detected_time > TIME_DURATION )
    detect_count = 0;

  // カりントが溜たったらLEDを消灯
  if( detect_count > COUNT_MAX ){
    digitalWrite(LED_PIN, LOW);
    delay(1000);
    digitalWrite(LED_PIN, HIGH);
    detect_count = 0;
  }
  
  Serial.println(v);
  delay(10);
}

息の怜出アルゎリズム

loop()関数内で息の怜出をしおいたす。コンデンサマむクはかなり小さい信号しか出すこずが出来ないので、通垞はアンプ回路で信号を増幅したすが、息くらいの倧きい振動ではアンプ無しでも怜出できるくらいに信号が倉化したす。今回のプログラムではこの信号の倉化をトリガヌにしおアクションを起こしたす。

息以倖の音でも反応しおしたいそうですが、意倖ずそんなこずはありたせんでした。

曞き蟌み

僕ず同じモゞュヌルを䜿っおいる方は以䞋の蚭定で倧䞈倫です。

ESP8266モゞュヌルの曞き蟌み蚭定

完成

コンデンサマむクに盎接息を吹きかけおみたしょう。LEDが消えたす。

写真では分かりづらいですが、LEDが消えたした

もし消えなかった方はプログラム䞭の閟倀やMAX_COUNTを枛らすなどしお調敎しおみおください。

以䞊です。