ESPr Developerで人感センサを使ってみる

スポンサーリンク
ESPr Developer

人感センサというものを買ったので、ESPr Developer につないで動作を確認してみようと思います。


将来的には、例えば、工場の製造装置に人感センサを設置して、装置の前に人がいること(≒段取り時間)を検知できれば、と思っていますが、まずは実験で、家のテレビの前にでも設置して、子供がテレビを見ている時間でも確認しようと思います。

購入したのは、パナソニックの「焦電型赤外線人感センサ PaPIRs」です。人体から放出される熱エネルギーの変化を検出するもので、人がいても、動きがほとんどない時は検出できないようです。
PaPIRsにはいくつかのラインアップがありますが、今回使うのは、最も一般的だと思われる「EKMC1601111(普及タイプの標準検出型)」です。

これをESPr Developerにつなぎ、人を検出したときにLEDを光らせようと思います。

実験1

人感センサにはVDD, OUT, GNDの3つのピンがあります。
この人感センサの動作電圧は3V〜7Vなので、ESPr Developerの出力電源(3.3V)を使うことができます。このため、VDDピンをESPr Developerの3V3ピンへ、GNDピンをESPr DeveloperのGNDピンへつなぎます。
この人感センサはデジタル出力で、人を検知するとOUTがHighになります。なお、プルダウン抵抗が必要なので、OUTピンとGNDの間に10kΩの抵抗をつないだ上で、OUTピンとESPr Developerの信号入力ピンをつなぎます。

本来はこのようにつなげば良いのですが、今回は、ESPr Developerに8chのADコンバータをつなぎ、8つのアナログ信号を取り込めるようにした回路(ブレッドボード)を既に作っていましたので、このうちの1chに人感センサをつなぐことにしました。よって、人感センサの出力するデジタル信号を、アナログ信号としてESPr Developerに取り込むことになります。

また、ESPr Developerの5番ピンとGNDの間に、LEDと330Ωの抵抗を直列につなぎます。人を検出したときには、このLEDを光らせます。

スケッチは以下のような感じになります。0.5秒毎に人感センサのデータを取り込み、それがHighであればLEDを点灯、そうでなければ消灯させます。また、データを90回取り込む毎に、その時のデータをWebサーバに送信します。
送信したデータをWebプログラムで観測することで、人がどのくらいの期間、そこにいたかを確認できます。

int count=0;

// WiFi接続や、ADコンバータとの通信のための各種設定(省略)

void setup() {
  pinMode(5, OUTPUT);
  // WiFi接続や、ADコンバータとの通信のための設定(省略)
}

void loop() {
  uint32 val0 = check(0); // 人感センサのデータを取り込み

  if(val0 > 511) {
    digitalWrite(5, HIGH);
  }
  else {
    digitalWrite(5, LOW);
  }
  count++;

  if(count>=90){
    sendRequest(val0)
    count=0;
  }
  delay(500);
}

int sendRequest(int val0) {
  // データをWebサーバに送信する(省略)
}

uint32 check(int channel) {
  // ADコンバータのデータを取り出す(省略)
}

これで動作確認してみました。
自分から50cmぐらい離れたところに人感センサを置き、パソコン作業をしているときの検知状況を確認したところ、センサに手をかざしたりすると、もちろんLEDが点灯しますが、キーボードをタイプしている程度では、頻繁にLEDが消灯してしまいます。
思ったよりもセンサの感度が悪く、これでは、テレビの前に座っている子供を検知できそうにはありません。

センサ本体には感度を調整する機能はないので、センサのラインアップをもう少し調べてみました。

パナソニックの「PaPIRs」には、以下のラインアップがあります。

  • EKMC(VZ)シリーズ:普及タイプ(デジタル出力)
    • 標準検出型、長距離検出型、壁取付型、広角検出型
  • EKMB(WL)シリーズ:低消費電流タイプ(デジタル出力)
    • 標準検出型、長距離検出型、壁取付型、広角検出型
  • AMN(NaPiOn)シリーズ:高機能タイプ(デジタル、およびアナログ出力)
    • 標準検出型、微動検出型、スポット検出型、10m検出型

今回使ったのは、EKMC(VZ)シリーズ(標準検出型)です。AMN(NaPiOn)シリーズ(微動検出型)などを使えば、もっと動きが少なくても、人を検知できるのかもしれません。

実験2

と、いろいろ調べているうちに、ひとつ思いつきました。

テレビを見ている子供であろうが、装置の段取り中の作業者だろうが、人がいれば、少なくとも1分に1度ぐらいは、センサが検知する程度には動くのではないか? そうであれば、90回に1度、データをWebサーバに送信する際に、その期間のデータの最大値を送信すればいいのではないか?と考えました。
そうすれば、90回のうち1回でも人を検知すれば、Webサーバには「人がいる」というデータが送られることになります。

スケッチを以下のように修正しました。

int count=0;
int vmax=0;

// WiFi接続や、ADコンバータとの通信のための各種設定(省略)

void setup() {
  pinMode(5, OUTPUT);
  // WiFi接続や、ADコンバータとの通信のための設定(省略)
}

void loop() {
  uint32 val0 = check(0); // 人感センサのデータを取り込み

  if(val0 > 511) {
    digitalWrite(5, HIGH);
  }
  else {
    digitalWrite(5, LOW);
  }
  count++;
  if(val0>vmax) {
    vmax=val0;
  }

  if(count>=90){
    sendRequest(vmax)
    count=0;
    vmax=0;
  }
  delay(500);
}

int sendRequest(int val0) {
  // データをWebサーバに送信する(省略)
}

uint32 check(int channel) {
  // ADコンバータのデータを取り出す(省略)
}

この回路を、子供がいる場所の近くに設置しました。

この状態で実験した結果、一応検知はできるのですが、以下の2点が気になりました。

(1) 少しの動きでは検知できない

人が検知エリアに入ってきたときには検知できますが、少し手を動かした程度では検知できないことが多いため、テレビの前に座ってしばらくすると、座ったままの状態でも、頻繁にOFFになってしまいます。

(2) 遠くにいる人の動きも検知してしまう

センサから5〜6m離れた場所でも、人が動けば結構な頻度でONになってしまいます。

本来は、子供がテレビの前に座っていれば常にON、となりの部屋にいれば常にOFF、となるのが理想的ですが、そのような分かりやすい結果にはなりませんでした。

実験3

これらの問題に対して、プログラムで対処することも考えられますが、今回は別の人感センサを試してみることにしました。

これまで使っていたのは、パナソニックの「焦電型赤外線人感センサ PaPIRs」のうち、普及タイプの標準検出型である「EKMC1601111」です。
今回、高機能タイプの微動検出型である「AMN32112」を追加で購入し、比較してみました。

ふたつのセンサの仕様を比較した結果は、以下のとおりです。「AMN32112」は「EKMC1601111」に比べ、検出距離が短い一方、より小さいものがゆっくり動いても検出できるということで、今回の問題への対策としては、ぴったりのようです。

検出距離移動スピード検出対象サイズ
EKMC16011115m1.0m/s700x250mm
AMN321122m0.5m/s200x200mm

回路構成は以下のとおりです。2種類の人感センサをひとつのESPr Developerに接続し、両者を同じように処理します。

回路は今回もブレッドボードで組みました。こんな感じです。

スケッチは以下のような感じになりました。
センサが人を検知すると、その情報を30秒保持します。その間に再び人を検知すると、さらに30秒保持します。その期間はLEDを点灯します。
45秒毎に、検知情報をWebサーバに送信します。
送信したデータをWebプログラムで観測することで、ふたつのセンサが人をどのように検出したかを確認します。

// WiFi接続等のための各種設定(省略)

#include <Ticker.h>
Ticker ticker1;
Ticker ticker2;

volatile boolean state1 = false;
volatile boolean state2 = false;

#define SENSOR1 14
#define SENSOR2 12
#define LED1 5
#define LED2 4

void onDetected1() {
  if(state1) {
    ticker1.detach();
    ticker1.attach(30, onTimer1);
  } else {
    ticker1.attach(30, onTimer1);
    digitalWrite(LED1, HIGH);
    state1 = true;
  }
}

void onDetected2() {
  if(state2) {
    ticker2.detach();
    ticker2.attach(30, onTimer2);
  } else {
    ticker2.attach(30, onTimer2);
    digitalWrite(LED2, HIGH);
    state2 = true;
  }
}

void onTimer1() {
  ticker1.detach();
  digitalWrite(LED1, LOW);
  state1 = false;
}

void onTimer2() {
  ticker2.detach();
  digitalWrite(LED2, LOW);
  state2 = false;
}

void setup() {
  // WiFi接続等のための設定(省略)

  pinMode(SENSOR1, INPUT);
  pinMode(SENSOR2, INPUT);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(SENSOR1), onDetected1, RISING);
  attachInterrupt(digitalPinToInterrupt(SENSOR2), onDetected2, RISING);
  digitalWrite(LED1, LOW);
  digitalWrite(LED2, LOW);
}

void loop() {
  delay(45000);
  sendRequest(state1, state2);
}

int sendRequest(boolean state1, boolean state2) {
  // データをWebサーバに送信する(省略)
}

これで動作確認してみたところ、結果は以下のようになりました。

この表は、1日分のセンサ検出結果を、1分間隔で一覧表示したもので、ONならば赤または緑、OFFならばグレイになっています。また、赤は「EKMC1601111(普及タイプ)」、緑は「AMN32112(高機能タイプ)」の結果です。両者の結果を上下に並べていますので、それらを見比べることで、両者の検出状況の違いが把握できます。

表を見ると分かるように、両者の検出結果に、それほど大きな違いはありませんでした。値段がそこそこ違う(「EKMC1601111」が432円、「AMN32112」が1151円。いずれもパナソニックのページにて)のですが、今回の用途では、それに見合うほどの差は見当たらないようです。

やはり、普及タイプをもっと使いこなす方法を、もう少し考えようと思います。

実験4

ここまで、人感センサと ESPr Developer を使った実験を続けています。

使っているセンサは、パナソニックの「焦電型赤外線人感センサ PaPIRs」のうち、普及タイプの標準検出型である「EKMC1601111」ですが、これまでの実験で、以下の問題が生じました。

  • 人が近くにいても、少しの動きでは検知できない。
  • 遠くにいる人の動きも検知してしまう時がある。

センサを違うものに変更すれば状況が改善するかも?と考え、高機能タイプの微動検出型である「AMN32112」を試してみましたが、結果に大きな違いは見られませんでした。
そのため、値段の安い普及タイプを使って、さらに調査を継続することにしました。

まずは、調査環境について。
これまでは、我が家のリビングに子供がいるかどうかを判定しようとしていましたが、もっと、人の在・不在が分かりやすい環境の方が調査しやすいと思い、今後は、トイレで調査することにします。
我が家のトイレには窓がなく、外光も入ってこないので、人を検知しやすい環境です。
トイレで人を検知した時に、メールを送信することで、離れて暮らす家族の安否確認ができるようにすることを目標にします。

スケッチは、前回から変わらず「センサからの信号を常時監視し、一定期間中に1度でもHighに変化すると、その期間に人がいたと判定する」ものです。
これをトイレに設置するだけで、簡単に人を検知できると思っていたのですが、実験してみると、実際は人がいないにも関わらず、人がいたと誤判定されることが頻繁に起こってしまいました。

誤判定のたびにメールが送られていては、安否確認になりません。

人感センサのパンフレットに「焦電素子の性質上、稀に突発性雑音出力により不要な検出信号が出力されることがあります。」という記載があります。センサからスパイクノイズか何かが発生しているのではないか?と考え、スケッチを「センサからの信号を1秒毎にチェックし、一定期間中に1度でもHigh状態があれば、その期間に人がいたと判定する」というように変更しました。
これで試したところ、前より頻度は減りましたが、やはり、誤判定が生じていました。

センサからの信号がどのような状態なのか?が気になったので、検出信号のパルス幅などを観測し、シリアルモニタで確認してみました。
その結果、人がいない時でも、長ければ幅1秒程度のパルス信号が、数回連続して発生する場合があることが分かりました。
誤検出信号はスパイクノイズではなく、本当に人がいる時の正しい検出信号との切り分けは困難です。

我が家のトイレには、誤検知の要因になるものはなさそうなのですが、もしかしたら、温水便座とか、トイレの外を通る人とか、何かに反応して検出信号が出力されているのではないか?と考えました。
これの確認のため、同じ構成の回路をもうひとつ準備し、同じ場所に設置して、両者の観測結果を比較しました。
その結果、どちらの回路も誤検知しているのですが、誤検知するタイミングは異なっており、誤検知に規則性もありませんでした。
つまり、何かに反応して誤検出信号が出力されている訳ではなく、ランダムに発生しており、やはり、誤検出信号を切り分けるのは困難です。

ここまでの調査の結果では、正常な検知と誤検知を区別する方法は、検出期間ぐらいしか思いつきません。
誤検出期間は、1回につき、せいぜい2〜3秒程度ですが、正常な検知では、1回のトイレ利用につき、1分程度は人がいると思われます。
よって、スケッチを「センサからの信号を1秒毎にチェックし、一定期間中にHigh状態が15回以上あれば、その期間に人がいたと判定する」というように変更しました。

これで、しばらく様子を見ることにしました。
ただ、この方法ではサジ加減次第で結果が変わるため、あまり筋が良くありません。なんだか、どんどん泥沼にはまってきた感じです。

ケースの作成

この回路をトイレに置くということで、トイレにあっても違和感がないように、ケースを作りました。

色は白で、センサを上向きにも横向けにもできるように置けそうなケースを探しました。

センサの先端をケースから出さないといけないので、大きな穴をあけるために、リーマと面取りカッターを購入しました。

電池式の安い電動ドライバと、百円ショップに売っていた5mmのドリル刃を使って穴を開け、リーマで穴を広げたあと、電動ドライバに面取りカッターを取り付けて、穴をあけた切り口をなめらかにしました。

結構きれいに仕上がりました。これならトイレに置いていてもそんなに気にならなさそうです。

ここまでのまとめ

我が家のトイレに、人感センサ(EKMC1601111)と ESPr Developer で作ったIoTデバイスを設置し、トイレに人が入ってきたことを検知しようとしています。

我が家のトイレには窓がなく、外光も入ってこないので、誤検知しにくい環境だと思うのですが、実験してみると、実際は人がいないにも関わらず、人がいたと誤判定されるという現象が頻繁に発生しました。

センサを取り替えても、同様な結果になるので、そもそもこのセンサは、このぐらい誤検知するものなのだと考え、プログラムで誤判定を減らすように対処することにしました。

当初は 1 のような判定方法だったのですが、これを 2 → 3 と変更することで、誤判定の発生頻度を減らしていきました。

  1. センサからの信号を常時監視し、一定期間中に1度でもHighに変化すると、その期間に人がいたと判定する。
  2. センサからの信号を1秒毎にチェックし、一定期間中に1度でもHigh状態があれば、その期間に人がいたと判定する。
  3. センサからの信号を1秒毎にチェックし、一定期間中にHigh状態が合計15秒以上あれば、その期間に人がいたと判定する。

3 の対処により、今のところ、完全に誤判定はなくならないものの、気にならないレベルまで削減できています。

実験5

一方、センサの誤判定について、個体差がどの程度あるのか把握しておきたいと考え、センサを追加で3個購入しました。
3個のセンサの出力信号を、ひとつのESPr Developerに取り込み、3個の検知結果を確認・比較することで、誤判定の頻度・個体差などを調べることにしました。

回路構成は以下のとおりです。

ふたつのセンサは、回路構成が全く同じ、残りひとつは、念のため、電源電圧を5Vにして調査しました。
ついでに、磁気スイッチをトイレの扉に取り付け、それもESPr Developerに繋ぎました。
これで、3個のセンサと扉スイッチの検知結果を確認し、誤判定の状況を比較できます。

ところが、この回路で2〜3日データを取ったところ、いずれのセンサも全く誤判定しませんでした。これまでの調査内容と違います。

今回の追加実験では、ブレッドボードで回路を組んでいますが、「実験4」で実験場所をトイレに移してからの実験回路は、ふたつとも、ユニバーサル基板で回路を作っています。

もしかして、ユニバーサル基板で回路を組む際に、どこか接続でも間違えたのではないかと思い、基板を再度見直しました。

すると、回路構成に間違いはなかったのですが、ひとつ気付いたことがあります。

ユニバーサル基板で回路を組む際に、やや小さめのケースに基板を詰め込むために、基板のおもてにESPr Developerを、裏に人感センサを取り付けています。人感センサとESPr Developerが重なって配置されており、ESPr Developerが発生する何らかのノイズを、人感センサが検知してしまうのではないか?と思いました。
さらによく観察すると、人感センサと重なっているのは、ESPr DeveloperのWiFiアンテナの部分です。ますます怪しそうです。

早速、追加で実験してみました。

ブレッドボードで組んだ実験回路は、これまで全く誤動作せずに稼働していますが、このうちのセンサひとつを、ESPr Developerの上面に移動しました。
変更したのはセンサの位置のみで、回路構成は以前から変更ありません。

これでデータ採取を継続しました。

すると、これまで誤判定は全くなかったにも関わらず、位置を変えたセンサひとつだけ、頻繁に誤判定するようになりました。ビンゴです!

トイレにデバイスを設置するために、できるだけ目立たないようにしようと思い、小さなケースに詰め込もうとしていましたが、それが原因で誤動作が頻発していたことになります。ケースについては、もう少し考え直さないといけません。

また、これまで作ってきたデバイスでは、このようなノイズの問題は起こりませんでしたが、今回のような問題は、人感センサだけではなく、他のセンサでも起こり得ます。
今後、電子工作をしていく際には、このような点にも気を付けなければいけないと思いました。