食事を楽しく最後まで「もぐもぐメーター」#obniz

# プロト版もぐもぐメーター
<iframe width="560" height="315" src="https://www.youtube.com/embed/Qy_ClrpN2wU" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

# もぐもぐメーターって何？
お皿の上にのった食品が減った量によって、目盛りが動き、音が鳴り、LEDが光る、というものです。
食べ勧める達成感を得ながら、動きや音、光りに注目してもらい、食事に集中してもらうのを目的にしています。
マリオの効果音を出すことで楽しんで食事をできるのをサポートします。

# 使ったもの
リンク先はすべて秋月電子通商のページです。
・[obniz](https://akizukidenshi.com/catalog/g/gM-14930/)
・[マイクロサーボ](https://akizukidenshi.com/catalog/g/gM-08761/)
・[圧電スピーカー](https://akizukidenshi.com/catalog/g/gP-04118/)
・[ジャンパワイヤー（オス-オス）](https://akizukidenshi.com/catalog/g/gC-05371/)
・[LED（赤）](https://akizukidenshi.com/catalog/g/gI-12605/)
・[ミニブレッドボード](https://akizukidenshi.com/catalog/g/gP-05155/)（なくてもいけますがあったほうが工作しやすいです。）

その他、画用紙、ペン、マスキングテープなど、必要に応じてご用意ください。
目盛りにはるシールは、お子さんの好きなキャラクターにしてみてください。

# 準備
サーボモーターにつける部品は下記のように短いものにしてください。
小さい穴が開いている部分に矢印をつけてください。
![20220301_143143.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2122198/496794d3-af49-986c-24b0-66fc7ce6e16d.jpeg)

圧電スピーカーなどをobnizに接続する場合は、プログラムと対応した位置に接続するようにしてください。

# プログラム
<details><summary>長いので折りたたんでおきます</summary>

```JavaScript
const Obniz = require('obniz');
const obniz = new Obniz('Obniz_ID');  // Obniz_ID

//***************************ここから音符・休符の定数宣言***************************
const sp1 = 2000                    // 全音符・全休符
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 sp16_34 = sp16 + (sp16 / 2)   // 付点16分音符・付点16分休符
//***************************ここまで音符・休符の定数宣言***************************
//***************************ここから音階周波数の定数宣言***************************
const oto_so_3 = 195.998;           // ソ3
const oto_do_4 = 261.626;           // ド4
const oto_re_4 = 293.665;           // レ4
const oto_mi_4 = 329.628;           // ミ4
const oto_fa_4 = 349.228;           // ファ4
const oto_so_4 = 391.995;           // ソ4
const oto_si_4 = 493.883;           // シ4
const oto_do_5 = 523.251;           // ド5
const oto_re_5 = 587.330;           // レ5
const oto_mi_5 = 659.255;           // ミ5
const oto_fa_5 = 698.456;           // ファ5
const oto_so_5 = 783.991;           // ソ5
const oto_do_6 = 1046.502;          // ド6

const oto_ra_3F = 207.652;          // ラb3(ソ#3)
const oto_si_3F = 233.082;          // シb3(ラ#3)
const oto_mi_4F = 311.127;          // ミb3(レ#3)
const oto_ra_4F = 415.305;          // ラb4(ソ#4)
const oto_si_4F = 466.164;          // シb4(ラ#4)

const oto_mi_5F = 622.254;          // ミb5(レ#5)
const oto_so_5S = 830.609;          // ソ#5
const oto_si_5F = 932.328;          // シb5(ラ#5)
//***************************ここまで音階周波数の定数宣言***************************

obniz.onconnect = async function () {
    //圧力センサーの設定
    const tempsens = obniz.wired('FSR40X', { pin0: 0, pin1: 1 });
    // サーボモータを利用（コードが出ている方を上にして可動部分を一番左に回した状態をスタート（180.0）とする）
    const servo = obniz.wired('ServoMotor', { gnd: 2, vcc: 3, signal: 4 });
    //LED
    const led = obniz.wired('LED', { anode: 5, cathode: 6 });
    // スピーカーを利用
    const speaker = obniz.wired('Speaker', { signal: 7, gnd: 8 });
    // 任意の秒数待つことができる関数
    const sleep = (msec) => new Promise(res => setTimeout(res, msec));
    
    // 初期値
    let degrees = 180.0; // サーボの初期値
    let flgcnt = 0; // 判定回数制御用
    // 点滅周期を保持する関数
    let interval = 100;

    setInterval(async function () {
        let temp = 0;
        temp = await tempsens.getWait();
        console.log(temp);

        // スタート
        if (temp >= 10){
            if (flgcnt === 0){
                //degrees = 170.0;
                servo.angle(degrees); // サーボを指定の角度まで動かす
                led.on();
                // マリオ スタート
                speaker.play(oto_mi_5); await sleep(sp16); speaker.stop(); await sleep(0);
                speaker.play(oto_mi_5); await sleep(sp16); speaker.stop(); await sleep(sp16);
                speaker.play(oto_mi_5); await sleep(sp16); speaker.stop(); await sleep(sp16);
                speaker.play(oto_do_5); await sleep(sp16); speaker.stop(); await sleep(0); 
                speaker.play(oto_mi_5); await sleep(sp16); speaker.stop(); await sleep(sp16); 
                speaker.play(oto_so_5); await sleep(sp16); speaker.stop(); await sleep(sp8+sp16);
                speaker.play(oto_so_4); await sleep(sp16); speaker.stop(); await sleep(sp16);
                led.off();
                flgcnt = 1;
            }
        }

        // サーボ（目盛り）が動き、LEDが点滅し、音が鳴る
        if (flgcnt === 1) {
            if (temp <= 420){
                degrees = 135.0;
                servo.angle(degrees); // サーボを指定の角度まで動かす
                
                flgcnt = 2; // 目盛りが1つ動いた
            }                           
        } else if (flgcnt === 2) {
            if (temp <= 400){
                degrees = 100.0;
                servo.angle(degrees); // サーボを指定の角度まで動かす
                led.on();
                // マリオ スタータイム
                speaker.play(oto_do_5); await sleep(sp16); speaker.stop(); await sleep(sp16); 
                speaker.play(oto_do_5); await sleep(sp16); speaker.stop(); await sleep(sp16); 
                speaker.play(oto_do_5); await sleep(sp16); speaker.stop(); await sleep(sp16); 
                speaker.play(oto_re_4); await sleep(sp16); speaker.stop(); await sleep(0); 
                speaker.play(oto_do_5); await sleep(sp16); speaker.stop(); await sleep(sp16); 
                speaker.play(oto_do_5); await sleep(sp16); speaker.stop(); await sleep(0); 
                speaker.play(oto_re_4); await sleep(sp16); speaker.stop(); await sleep(0); 

                speaker.play(oto_do_5); await sleep(sp16); speaker.stop(); await sleep(sp16); 
                speaker.play(oto_do_5); await sleep(sp16); speaker.stop(); await sleep(sp16); 

                speaker.play(oto_si_4); await sleep(sp16); speaker.stop(); await sleep(sp16); 
                speaker.play(oto_si_4); await sleep(sp16); speaker.stop(); await sleep(sp16); 
                speaker.play(oto_si_4); await sleep(sp16); speaker.stop(); await sleep(sp16); 
                speaker.play(oto_do_4); await sleep(sp16); speaker.stop(); await sleep(0); 
                speaker.play(oto_si_4); await sleep(sp16); speaker.stop(); await sleep(sp16); 
                speaker.play(oto_si_4); await sleep(sp16); speaker.stop(); await sleep(0); 
                speaker.play(oto_do_4); await sleep(sp16); speaker.stop(); await sleep(0); 

                speaker.play(oto_si_4); await sleep(sp16); speaker.stop(); await sleep(sp16); 
                speaker.play(oto_si_4); await sleep(sp16); speaker.stop(); await sleep(sp16);

                led.off();
                flgcnt = 3; // 目盛りが2つ動いた
            }            
        } else if (flgcnt === 3) {
            if (temp <= 300){
                degrees = 75.0;
                servo.angle(degrees); // サーボを指定の角度まで動かす
                
                flgcnt = 4; // 目盛りが3つ動いた
            }            
        } else if (flgcnt === 4) {
            if (temp <= 250){
                degrees = 20.0;
                servo.angle(degrees); // サーボを指定の角度まで動かす
                led.on();
                // マリオ ステージクリア
                speaker.play(oto_so_3); await sleep(sp16_34); speaker.stop(); await sleep(0);
                speaker.play(oto_do_4); await sleep(sp16_34); speaker.stop(); await sleep(0);
                speaker.play(oto_mi_4); await sleep(sp16_34); speaker.stop(); await sleep(0);    
                speaker.play(oto_so_4); await sleep(sp16_34); speaker.stop(); await sleep(0);    
                speaker.play(oto_do_5); await sleep(sp16_34); speaker.stop(); await sleep(0);    
                speaker.play(oto_mi_5); await sleep(sp16_34); speaker.stop(); await sleep(0);    
                speaker.play(oto_so_5); await sleep(sp4); speaker.stop(); await sleep(0);    
                speaker.play(oto_mi_5); await sleep(sp4); speaker.stop(); await sleep(0);    

                speaker.play(oto_ra_3F); await sleep(sp16_34); speaker.stop(); await sleep(0);    
                speaker.play(oto_do_4); await sleep(sp16_34); speaker.stop(); await sleep(0);    
                speaker.play(oto_mi_4F); await sleep(sp16_34); speaker.stop(); await sleep(0);    
                speaker.play(oto_ra_4F); await sleep(sp16_34); speaker.stop(); await sleep(0);    
                speaker.play(oto_do_5); await sleep(sp16_34); speaker.stop(); await sleep(0);    
                speaker.play(oto_mi_5F); await sleep(sp16_34); speaker.stop(); await sleep(0);    
                speaker.play(oto_so_5S); await sleep(sp4); speaker.stop(); await sleep(0);    
                speaker.play(oto_mi_5); await sleep(sp4); speaker.stop(); await sleep(0);    

                speaker.play(oto_si_3F); await sleep(sp16_34); speaker.stop(); await sleep(0);    
                speaker.play(oto_re_4); await sleep(sp16_34); speaker.stop(); await sleep(0);    
                speaker.play(oto_fa_4); await sleep(sp16_34); speaker.stop(); await sleep(0);    
                speaker.play(oto_si_4F); await sleep(sp16_34); speaker.stop(); await sleep(0);    
                speaker.play(oto_re_5); await sleep(sp16_34); speaker.stop(); await sleep(0);    
                speaker.play(oto_fa_5); await sleep(sp16_34); speaker.stop(); await sleep(0);    
                speaker.play(oto_si_5F); await sleep(sp4); speaker.stop(); await sleep(0);    
                speaker.play(oto_si_5F); await sleep(sp16_34); speaker.stop(); await sleep(0);    
                speaker.play(oto_si_5F); await sleep(sp16_34); speaker.stop(); await sleep(0);    
                speaker.play(oto_si_5F); await sleep(sp16_34); speaker.stop(); await sleep(0);    

                speaker.play(oto_do_6); await sleep(sp2); speaker.stop(); await sleep(sp2);
                led.off();

                flgcnt = 5; // 目盛りが4つ動いた
            }            
        } else {
            led.off();
            speaker.stop();
        }

        if (flgcnt === 5){
            exit(); // 終了
        }
    }, 10000); // 10000ミリ秒 = 10秒おきに実行

}
```
</details>

# なぜ作ったのか
この開発を行うにあたり、身の回りの悩み、課題、どうにかしたい！と思っていることを出しまくりました。

▽出しまくった図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2122198/402ba5e3-2efb-4a31-1e6b-938a2aac5dd5.png)

その中からチーム内の「わかるー！」が多く集まった「子どもの食べ残しをなくしたい！」に着目しました。

## フードロス問題とは
最近よく **「フードロス」（＝食品ロス）** って言葉を聞きませんか？
本当はまだ食べられたはずの食品や食材を廃棄してしまう。
その数が世界的に多くなっており問題になっています。

詳しくは農林水産省のHPをご覧ください。

https://www.maff.go.jp/j/shokusan/recycle/syoku_loss/161227_4.html

なお、世界的には「フードロス」は生産者や販売者側の廃棄について使う言葉であり、消費者側の廃棄については **「フードウェイスト」** と言うのが正しいようですが、ここでは「フードロス」を使わせていただきます。

## お子さんの食べ残し問題
日々の食事について、
昨日食べていた料理でも今日は食べない
食べたいと言ったから出したのに結局食べない
食事に集中できなくて食べている途中で席を立ってしまう
……などなどの悩みがありました。

賞味期限切れに関するプロダクトはすでにいくつか存在しているので、
チームでは、この「お子さんの食べ残し」についてアイデアを出しました。

## もぐもぐメーターを作ろう！
お子さんが最後まで楽しく食事ができる　＝　食べ残しが減る　＝　フードロス削減につながる
と考え、実際にお子さんのいる方にヒアリングしたところ、
「音が鳴ったり、光ったりなど単純な動きをするものに興味を持ちやすい」
とのことでした。

これを受けて「お皿の上にのった食べ物が減ったら、音が鳴り、光って、目盛りが動く」ものを作ろう！
となりました。

▽おえかきしながらアイデア出し
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2122198/2a2bc557-295a-1218-d905-74f7366c5cc7.png)

# つくってみて
・お子さんに試してもらいたい
今回作成したものはプロト版のため、ここで終わり！ではありません。
改良を加えてお子さんのいるご家庭で試してもらえたらいいなぁ、と思っています。

・圧力センサーで重さは量れない！
重みで圧力が変わって量れるのではないか？と考えて作りましたが、センサーのあたりどころによるブレが大きく、圧力センサーは重さを量るのに向いていませんでした。
改良点として、ロードセルなどの重量を量るセンサーを用いたいと思います。