心が疲れたので、可愛いものをBGM付きで右往左往させた

https://twitter.com/nnmshita/status/1453598678757769219


# とにもかくにも癒されたい
お仕事に、お勉強に、みなさん本当にお疲れ様です。2021年も残すところあと2ヶ月。
とにかく**可愛いものを見て癒されたい。**
そう思って手を動かした結果、とても可愛いものが出来たので報告させていただく。
我々が右往左往しても全く可愛くないが、**可愛いものが右往左往する姿はとても可愛い。**


# 材料
Visual Studio Code 1.61.0
Node.js 7.24.0

* obniz Board 1Y
* 超音波測距センサ
* サーボモータ
* スピーカー
* 右往左往させたいもの（今回の主役）

各パーツ
![image_50434049.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2122226/a7b883ce-472d-6661-b7d4-cd6419c0e545.jpeg)

右往左往させたいもの。（可愛い）
シルバニアの赤ちゃんたち。（可愛い）
![image_50431489.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2122226/a1ede48c-edd6-d15b-2206-c6b4cd3ffdd4.jpeg)


## 準備
右往左往させやすいように、準備をする。
①まずは、赤ちゃんの**足を固定する。**それなりの勢いで動くので、足をフェルトに縫い付けている。
![image_50737409.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2122226/dd1a8d55-7895-1fea-aede-15bc70383350.jpeg)

②サーボモータのプロペラを、厚紙に張り付ける。
![image_50426625.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2122226/4acb49bf-333f-aed6-cdfc-d4f4ba249e33.jpeg)

③①と②で作ったものを両面テープで貼り付け、サーボモータに装着する。
心なしか、赤ちゃんの顔が哀愁を帯びているような・・・
![image_50743297.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2122226/dc37781c-85c3-85ae-a671-cf0c66e98e2e.jpeg)

その他、必要なパーツを設置する。
![image_50398209.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2122226/7c147f68-e32e-4ff4-1869-3276fe56ca55.jpeg)

 　**準備完了！！**

# ソースコード

```JavaScript
const Obniz = require('obniz');
const obniz = new Obniz('Obniz_ID'); // Obniz_IDに自分のIDを入れます

// 任意の秒数待つことができる関数
const sleep = (msec) => new Promise(res => setTimeout(res, msec));

obniz.onconnect = async function () {
    // 超音波測距センサを利用する
    const hcsr04 = obniz.wired('HC-SR04', { gnd: 3, echo: 2, trigger: 1, vcc: 0 });
    // サーボモータを利用する
    const servo = obniz.wired('ServoMotor', { gnd: 9, vcc: 10, signal: 11 });
    // スピーカーを利用する
    const speaker = obniz.wired('Speaker', { signal: 5, gnd: 6 });

        //音符設定
       const sp1 = 3600                    //全音符・全休符
       const sp2 = sp1 / 2                 //2分音符・2分休符
       const sp4 = sp1 / 4                 //4分音符・4分休符
       const sp8 = sp1 / 8                 //8分音符・8分休符
       const sp16 = sp1 / 16               //16分音符・16分休符

        //音設定
        const c = 261.626 //ド
        const d = 293.665 //レ
        const e = 329.628 //ミ
        const f = 349.228 //ファ
        const g = 391.995 //ソ
        const a = 440.000 //ラ
        const b = 466.164 //シ♭
        const c1 = 523.251 //ド
    
    // ディスプレイ
    obniz.display.clear();  // クリア
    obniz.display.print('Ready');

    // setIntervalで一定間隔で処理
    setInterval(async function () {        
        // 距離を取得
        let distance = await hcsr04.measureWait();
        // 小数点以下の桁数が多いのでここでは整数にする
        distance = Math.floor(distance);

        // 距離をターミナルに表示
        console.log(distance + ' mm');
        // obnizディスプレイに表示
        obniz.display.clear();
        obniz.display.print(distance + ' mm');

        // 距離によって判定
        if (distance < 100.0) {
            // 100mm = 10cm 未満の場合 obnizディスプレイに表示
            obniz.display.clear();
            obniz.display.print('aka-chan,panic!!');

            // サーボモータ起動
            var angle = 0;
            setInterval(async function() {
                servo.angle(angle);
                if (angle == 0) {
                    angle = 180;
                    
                    // オラはにんきもの
                    speaker.play(c1); await sleep(sp16); speaker.stop(); await sleep(0); //ド
                    speaker.play(c1); await sleep(sp16); speaker.stop(); await sleep(0); //ド
                    speaker.play(a); await sleep(sp16); speaker.stop(); await sleep(0); //ラ
                    speaker.play(a); await sleep(sp16); speaker.stop(); await sleep(0); //ラ
                    speaker.play(g); await sleep(sp16); speaker.stop(); await sleep(0); //ソ
                    speaker.play(g); await sleep(sp16); speaker.stop(); await sleep(0); //ソ
                    speaker.play(a); await sleep(sp16); speaker.stop(); await sleep(0); //ラ
                    speaker.play(g); await sleep(sp16); speaker.stop(); await sleep(0); //ソ
                    speaker.play(c1); await sleep(sp16); speaker.stop(); await sleep(0); //ド
                    speaker.play(c1); await sleep(sp16); speaker.stop(); await sleep(0); //ド
                    speaker.play(a); await sleep(sp16); speaker.stop(); await sleep(0); //ラ
                    speaker.play(a); await sleep(sp16); speaker.stop(); await sleep(0); //ラ
                    speaker.play(g); await sleep(sp16); speaker.stop(); await sleep(0); //ソ
                    speaker.play(g); await sleep(sp16); speaker.stop(); await sleep(0); //ソ
                    speaker.play(a); await sleep(sp16); speaker.stop(); await sleep(0); //ラ
                    speaker.play(g); await sleep(sp16); speaker.stop(); await sleep(0); //ソ

                    // Ctrl+C を打たなくても自動で終了
                    exit();

                 } else {
                    angle = 0;
                 }
            }, 1000);
        } 

    }, 1000); // 1000ミリ秒 = 1秒おきに実行
}

```

曲はパニックといったらお馴染みの「オラはにんきもの」。
楽譜は分からないので、YoutTube動画から参考にさせていただいた。
【参考動画】[１本指ピアノ【オラはにんきもの】 クレヨンしんちゃん 簡単ドレミ楽譜 超初心者向け](https://www.youtube.com/watch?v=__WPj2SqSG8)）

**超音波測距センサの10㎝以内に近づいたら、サーボモータが起動して、スピーカーから音楽を鳴らす、**という仕様にした。


## 超音波測距センサ
```JavaScript
   // 距離を取得
   let distance = await hcsr04.measureWait();
   // 小数点以下の桁数が多いのでここでは整数にする
   distance = Math.floor(distance);

   // 距離をターミナルに表示
   console.log(distance + ' mm');
   // obnizディスプレイに表示
   obniz.display.clear();
   obniz.display.print(distance + ' mm');

   // 距離によって判定
   if (distance < 100.0) {
       // 100mm = 10cm 未満の場合 obnizディスプレイに表示
       obniz.display.clear();
       obniz.display.print('aka-chan,panic!!');
```
超音波測距センサの10㎝以内に近づいたらアクションをする設定。
他の機能と併用するにあたって、後々設定がイケてないことが判明したので、問題点を以下に記載する。

### 問題点

* 超音波測距センサに近づいたらサーバモータが動く仕様にしたが、センサに近づけたままの場合にモータ起動、音楽の両方が処理の頭の部分でループしてしまうので、**センサが反応したらすぐにセンサ前から外れる必要がある。**


## サーボモータ
```JavaScript
  // サーボモータ起動
  var angle = 0;
  setInterval(async function() {
  servo.angle(angle);
    if (angle == 0) {
        angle = 180;
    } else {
        angle = 0;
    }
 }, 1000);

```
サーボモータのプロペラ部分が、0度と180度で動きループするように設定。
動く角度を90度にしたい場合は、`angle = 180;` の箇所を `angle = 90;` に設定する。

ループについては、こちらのコードを参考にさせていただいた。
【参考】[【obniz入門】RC サーボモーターで同じ処理を繰り返す（ループ）](https://laboratory.kazuuu.net/obniz-repeat-the-same-process-with-the-rc-servo-motor/)

### 問題点

* 動く幅を0度から180度にした、かつ左右に動くようにプロペラを設置しているので、**動きが終わったときに赤ちゃんが真横を向いてしまう。**
90度で止まるように、`else{ angle = 90;}` にすればいいが、音楽が終わるタイミングも微妙なのでちょっと気持ち悪い。。

## 音楽を鳴らす
```JavaScript
   // スピーカーを利用する
   const speaker = obniz.wired('Speaker', { signal: 5, gnd: 6 });

   //音符設定
   const sp1 = 3600                    //全音符・全休符
   const sp2 = sp1 / 2                 //2分音符・2分休符
   const sp4 = sp1 / 4                 //4分音符・4分休符
   const sp8 = sp1 / 8                 //8分音符・8分休符
   const sp16 = sp1 / 16               //16分音符・16分休符

   //音設定
   const c = 261.626 //ド
   const d = 293.665 //レ
   const e = 329.628 //ミ
   const f = 349.228 //ファ
   const g = 391.995 //ソ
   const a = 440.000 //ラ
   const b = 466.164 //シ♭
   const c1 = 523.251 //ド

   // オラはにんきもの
   speaker.play(c1); await sleep(sp16); speaker.stop(); await sleep(0); //ド
   speaker.play(c1); await sleep(sp16); speaker.stop(); await sleep(0); //ド
   speaker.play(a); await sleep(sp16); speaker.stop(); await sleep(0); //ラ
   speaker.play(a); await sleep(sp16); speaker.stop(); await sleep(0); //ラ
   speaker.play(g); await sleep(sp16); speaker.stop(); await sleep(0); //ソ
   speaker.play(g); await sleep(sp16); speaker.stop(); await sleep(0); //ソ
   speaker.play(a); await sleep(sp16); speaker.stop(); await sleep(0); //ラ
   speaker.play(g); await sleep(sp16); speaker.stop(); await sleep(0); //ソ
   speaker.play(c1); await sleep(sp16); speaker.stop(); await sleep(0); //ド
   speaker.play(c1); await sleep(sp16); speaker.stop(); await sleep(0); //ド
   speaker.play(a); await sleep(sp16); speaker.stop(); await sleep(0); //ラ
   speaker.play(a); await sleep(sp16); speaker.stop(); await sleep(0); //ラ
   speaker.play(g); await sleep(sp16); speaker.stop(); await sleep(0); //ソ
   speaker.play(g); await sleep(sp16); speaker.stop(); await sleep(0); //ソ
   speaker.play(a); await sleep(sp16); speaker.stop(); await sleep(0); //ラ
   speaker.play(g); await sleep(sp16); speaker.stop(); await sleep(0); //ソ

   // Ctrl+C を打たなくても自動で終了
   exit();

```
サーボモータが動いている間に音楽を流したかったので、モータ起動のコード内に入れ込んでいる。

「オラはにんきもの」のパニックパニック、の部分を設定（脳筋なので、ループはしないで同じ部分を繰り返してコード記載）。
みんなが慌ててる～まで入れたかったが、どうにもリズムが崩れるので開き直ってパニックパニックのみに。赤ちゃんは**不穏な音楽に合わせて右往左往していても可愛い。**

実は前述のサーボモータのループ起動のままだとモータが止まらないのだが、音楽を追加したことで**音楽が終了したらモータも停止するようにできた。**

音楽の設定については、 こちらの記事を参考にさせていただいた。
【参考】[ドアモニターがないだと？代わりを作ればいいじゃない。](https://qiita.com/ikumi623/items/fcb317b0840479eb1ff7)


### 問題点

* **音楽が短い。**長く設定すると、リズムが上手く取れなかったり、音が飛んでしまったりする。



# まとめ
比較的短時間で作ったので、問題点は多いが楽しく作れた。
**可愛いものは動くともっと可愛い。**
新たな知見を得た。