紙の本の香りを嗅ぎながら電子書籍を読もう

この記事は [obniz Advent Calendar 2021](https://qiita.com/advent-calendar/2021/obniz) 13日目の記事です。
## やったこと

iPadで本を読んでいる間、紙の本の香りを充満させるシステムを作ってみました。
iPadをスタンドから手に取ってから戻すまでの間、細かく切った紙をファンの風で舞わせています。

<blockquote class="twitter-tweet"><p lang="und" dir="ltr"><a href="https://twitter.com/TOS?ref_src=twsrc%5Etfw">@tos</a> <a href="https://t.co/V0dLxi8B93">pic.twitter.com/V0dLxi8B93</a></p>&mdash; さくあ@思いつきぶん投げ(?) (@sakua_create) <a href="https://twitter.com/sakua_create/status/1469720547353567234?ref_src=twsrc%5Etfw">December 11, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


本棚の圧迫状況を見てそろそろ電子書籍に切り替えたいとは思っていたのですが、
新品の本の香りが好きなのでなかなか電子書籍に手を出せずにいました。

そこで、じゃあ電子書籍を読んでいる間も同じ香りをかげるようにしちゃおう！ということで作ってみました。


## 配線と筐体

### 材料
* obniz
* バッテリ
* [赤外線距離センサ (秋月電子リンク)](https://akizukidenshi.com/catalog/g/gI-02551/)
* [DCファン (千石電商リンク)](https://www.sengoku.co.jp/mod/sgk_cart/detail.php?code=EEHD-55MW)
* iPad
* iPadスタンド
* プリンカップの蓋 x2
* お湯で自由変形できるプラスチック(固定用)
* 網

### 電子書籍を読んでいる判定

iPadスタンドに赤外線距離センサを取り付けました。

障害物との距離が近い : iPadがスタンドに置かれている状態 = 読書していない
障害物との距離が遠い : iPadがスタンドから取られた状態 = 読書中

という判定にしています。

**前から**
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130420/1df001f4-ac54-78b9-2387-c7c9f97360f1.jpeg" width=50% height=50%><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130420/4fa7fac7-925f-36e4-03b8-5c0e23313ecf.jpeg" width=50% height=50%>
**横から**
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130420/dcdcbce6-7a81-bac6-f489-e037495a3a4e.jpeg" width=50% height=50%><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130420/68013ad5-9a92-a7ca-b2ca-8fcb2c4943df.jpeg" width=50% height=50%>

### 本の香りを出す装置


本の独特な香りはインクや紙の匂いが混ざったものらしいので、
細かく切った紙をファンの風で舞うようにしました。

<blockquote class="twitter-tweet"><p lang="und" dir="ltr"><a href="https://twitter.com/TOS?ref_src=twsrc%5Etfw">@tos</a> <a href="https://t.co/YylhmNr9mg">pic.twitter.com/YylhmNr9mg</a></p>&mdash; さくあ@思いつきぶん投げ(?) (@sakua_create) <a href="https://twitter.com/sakua_create/status/1469707972918255616?ref_src=twsrc%5Etfw">December 11, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

**注: インクを吸うのは体によろしくなさそうなので、印刷はしていません。**
なので本の香りを再現しているかというと微妙です...タイトル詐欺ですみません。
本の香りを再現したアロマ等あったら教えて頂けると嬉しいです🙏


仕組みとしては風で舞う抽選器と同じです。
球体に近い形の入れ物に細かく切った紙を入れて、下からファンで風を当てています。

![筐体全体.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130420/892fc5b6-8027-2124-eccb-3465066cce34.jpeg)

![筐体裏.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130420/340ca1a7-16b3-b3cc-d731-45a93026bb3b.jpeg)

プリン用カップの蓋を上下に二つ組み合わせて球体の入れ物の代わりとしました。
上側の蓋はキリで空気穴を開け、下側の蓋はファンの直径に合わせて底をくり抜いています。雑ですみません。

![プリンカップ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130420/36e99638-410e-72c6-0e1e-6aaa933bdfe7.jpeg)

### 配線

![circuit.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130420/bb94a947-0380-6aa1-656e-d35a095599ce.jpeg)

赤外線距離センサは[obnizのパーツライブラリ](https://obniz.com/ja/sdk/parts/GP2Y0A21YK0F/README.md)を参考にしました。
ファンはピンのIO自体の5v/0vを切り替えることで、回転のON/OFFをしています。
obnizに直さしでファンが回るのはありがたいですね。

## プログラム

### 全体の流れ
1. ループで50msごとに距離センサと障害物の距離を計測
2. プログラム開始後 / ファンのON・OFF切り替え後 4ループ待った後の10ループの距離の平均値を基準値として設定
3. 現在の距離が基準値±閾値を超えたらiPadを動かしたと判定
4. 距離が遠ざかっていたらiPadがスタンドから取られた、近づいていたらスタンドに置いたと判定
5. スタンドから取られた場合はファンを回して紙の香りを充満させ、スタンドに置いた場合はファンを止める

```html
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <script src="https://unpkg.com/obniz@3.x/obniz.js"></script>
  </head>

  <body>
  <script>
    let obniz = new Obniz("OBNIZ_ID_HERE");
    const DIFF_THOREHOLD = 200;

    obniz.onconnect = async () => {
      let calibratedVal = 0;
      let calibLoopCount = 14;
      let rotateFlag = false;
      let distVals = [];
      let sensor = obniz.wired("GP2Y0A21YK0F", {vcc:0, gnd:2, signal:1});

      //ファン用GPIO設定
      obniz.io11.output(false);
      obniz.io10.output(rotateFlag);

      obniz.repeat(async () => {
        let distVal = await sensor.getWait();
        console.log("距離(mm): " + distVal);
        arrangeArray(distVals, distVal);

        //最初 or ファンのON/OFFが変わった後の20ループで距離の基準値を決める
        if(calibLoopCount > 0){
          console.log("基準値決め残りループ: " + calibLoopCount);
          if(calibLoopCount === 1){
            calibratedVal = Math.floor(calAverage(distVals));
            console.log("基準値: " + calibratedVal);
          }
          calibLoopCount--;
          return;
        }

        //現在の値が距離の基準値と比べて閾値分よりも大きい変化があった場合
        if(Math.abs(distVal - calibratedVal) > DIFF_THOREHOLD){
          if(distVal > calibratedVal){
            //障害物との距離が離れた場合、デバイスを手に取ったと認識
            rotateFlag = true;
          }else if(distVal < calibratedVal){
            //障害物との距離が近づいた場合、デバイスをスタンドに戻したと認識
            rotateFlag = false;
          }
          obniz.io10.output(rotateFlag);

          //基準値決めに戻る
          calibLoopCount = 14;
        }
      }, 50);
    }

    function arrangeArray(arr, val){
      const ARR_LIMIT_NUM =10;
      arr.push(val);
      if(arr.length > ARR_LIMIT_NUM){
        arr.shift();
      }
    }

    function calAverage(arr){
      let sum = arr.reduce((accumulator, current) => {
        return accumulator + current;
      });
      return sum / arr.length;
    }

  </script>
  </body>
</html>
```

## おわりに

インクを空気中に充満させるのに抵抗があって今回はただの紙を使ったので、正直あまり本の香りはしませんでした...
本の香りに近しい何かを探してアップデートしていきたいと思います💪