人間を感知してアクションを起こすプログラムの書き方比較 Arduinoとobniz

センサとアクチュエータを含む電子工作の単純な例として，「人が近づいてきたら電気を点ける」というような動作をさせたい場合がよくあります．
マイコンボードごとにそのプログラムの書き方を比較してみました．

人感センサとして，焦電型赤外線センサの[PaPIRs](http://akizukidenshi.com/catalog/g/gM-09750/)を使用し，一度人間を感知すると，５秒間LEDを点灯させるプログラムをいろいろな方法で書いてみました．

# Arduino

## ポーリングによる方法
ポーリングは，定期的にセンサの値を確認しにいく方法です．

```cpp:pir_polling.ino
const int SENSOR_PIN = 2;
const int LED_PIN = 13;

void setup()
{
  pinMode(SENSOR_PIN, INPUT);
  pinMode(LED_PIN, OUTPUT);
}

void loop()
{
  if (digitalRead(SENSOR_PIN) == HIGH) {
    digitalWrite(LED_PIN, HIGH);
    delay(5000);
  } else {
    digitalWrite(LED_PIN, LOW);
  }
}
```

人感センサの値を定期的に確認する以外にする動作がないのであればこれでも十分動きますが，もし他にもセンサを読み取ったり，時間のかかる動作をさせる必要がある場合は，センサの反応を見逃してしまう可能性があります．
そこで使われるのが**割り込み**です．

## 割り込みによる方法
```cpp:pir_interrupt.ino
const int SENSOR_PIN = 2;
const int LED_PIN = 13;
volatile bool flag = false;

void setup()
{
  pinMode(SENSOR_PIN, INPUT);
  pinMode(LED_PIN, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(SENSOR_PIN), foundPerson, RISING);
}

void loop()
{
  delay(100);//別の処理を回す
  if (flag == true) {
    digitalWrite(LED_PIN, HIGH);
    delay(5000);
    digitalWrite(LED_PIN, LOW);
    flag = false;
  }
}

void foundPerson() {
  flag = true;
}
```
Arduinoでは`attachInterrupt`関数を利用して，割り込みを使うことができます．`attachInterrupt`の３番目の引数に`RISING`を指定することで，センサの出力がLOWからHIGHに変わった瞬間，つまり人を検出した瞬間に，２番目の引数に指定した関数を実行することができます．
割り込み発生時に実行される関数内では，時間のかかる関数を含むことができないので，フラグを変化させるだけとし，メインループ内でフラグの値に応じて条件分岐する，というような工夫が必要です．
ただしこの場合，メインループ内に他の処理を含むことはできますが，センサ値が変化してからその処理を実行するまでにタイムラグが発生してしまいます．

# obniz

[obniz](https://obniz.io/)の場合，プログラムはJavaScriptで記述することができます．

## ポーリングによる方法
```html:obniz_io_polling.html
<script>
var obniz = new Obniz("OBNIZ_ID_HERE");
obniz.onconnect = async function () {
    obniz.io0.output(false);//センサのGND用
    obniz.io2.output(true);//センサの電源Vdd用
    var led = obniz.wired("LED", { anode: 3, cathode: 4 });

    while (1) {
        var value = await obniz.io1.inputWait();
        // console.log(value);
        if (value == true) {
            led.on();
            obniz.wait(5000);
            led.off();
        }
    }
}
</script>
```

obnizはインターネット経由で操作するマイコンボードなので，`inputWait()`では読み取ったピンの値が返って来るまでに少しタイムラグがあるかもしれません．


## 割り込みによる方法
obnizでも，ioピンの状態が変わったときにのみcallback関数を実行する，割り込み機能が備わっています．

```html:obniz_io_interrupt.html
<script>
var obniz = new Obniz("OBNIZ_ID_HERE");
obniz.onconnect = async function () {
    obniz.io0.output(false);//センサのGND用
    obniz.io2.output(true);//センサの電源Vdd用
    var led = obniz.wired("LED", { anode: 3, cathode: 4 });

    obniz.io1.input(function (value) {
        // console.log("value is " + value);
        if (value == true) {
            led.on();
            obniz.wait(5000);
            led.off();
        }
    });
}
</script>
```
このようにcallbackにすれば，処理を止めなくてもioの変化を知ることができます．
obnizの場合，callback関数内に，`obniz.wait`のように時間のかかる動作を書くこともできます．

## obniz公式ライブラリを使う
obnizには公式に，[各種センサ等のパーツライブラリが豊富に揃っている](https://obniz.io/ja/sdk/parts/)ので，それらを使えばよりシンプルにプログラムを記述することができます．
今回使用したPaPIRsのライブラリは[こちら](https://obniz.io/ja/sdk/parts/PaPIRsVZ/README.md)です．

```html:obniz_pir.html
<script>
var obniz = new Obniz("OBNIZ_ID_HERE");
obniz.onconnect = async function () {
    var sensor = obniz.wired("PaPIRsVZ", { gnd: 0, signal: 1, vcc: 2 });
    var led = obniz.wired("LED", { anode: 3, cathode: 4 });

    sensor.onchange = function (val) {
        console.log(val ? 'Moving Something!' : 'Nothing moving');
        if (val == true) {
            led.on();
            obniz.wait(5000);
            led.off();
        }
    }
}
</script>
```
見通しが良くなりましたね．

# センサの値を画面に表示したい
今回は，一度人間を感知すると５秒間LEDを点灯させるプログラムを書いてみましたが，人感センサの値をスマートフォンの画面に表示したりなど，もっと別のモノと連携したいこともあるでしょう．
Arduinoの場合，`Serial.print`関数を使えば，Arduinoを繋いだPCの画面上に一旦文字として表示することはできますが，離れたところにある端末からセンサの情報を見たい場合， **インターネットに繋ぐ必要**があります．そのためには，イーサネットシールドを使う，ESP8266, ESP32等のWi-Fiに対応したチップを使う必要があります．
いずれにしても，

- Wi-Fi接続設定
- センサ情報の送信

等でプログラムは複雑になってきます．

それに対し，obnizのJavaScriptのプログラムは，obnizを操作しているスマートフォンやパソコンといった端末のブラウザ上で動いているわけなので， **既に人感センサの情報は手元のブラウザに届いています**．だから，センサの情報をブラウザ上に表示させたり，他のインターネット上のサービスに送ったりすることも簡単にできます！

obniz公式サイトのサンプルには，obnizと人感センサをトイレに設置して，トイレに人がいるかどうかをiPadに画像で表示してくれる「[トイレにだれかいますかセンサー](https://obniz.io/ja/explore/3)」なるプロジェクトがあります．

# まとめ
- Arduinoでセンサの入力を監視する場合，ポーリングでは変化を見落とす可能性があるため，割り込みが使われる
- obnizのオブジェクト指向な書き方は見通しが良い
- obnizの公式ライブラリには電子工作の定番部品が豊富
- センサの情報を画面に表示したければ最初からobnizを使うのが楽そう

# 参考文献
- https://obniz.io/ja/explore/3