距離を計測

皆さん,obniz Starter KitのHTML/JavaScriptのレッスンページへようこそ!
前回のレッスンではボタンが押されたかどうかをブラウザを動的に変更することで確認しました.
このレッスンでは,今度はパーツの中から「距離センサ」を使って,距離が測れているかをブラウザやobniz側で確認してみましょう.

そもそも距離センサはどうやって動くのか?

距離センサには超音波発生器がついており,そこから超音波を発生させています
それが物にぶつかった時に反射した超音波をセンサ部で受け取ることにより,音波が進むのにかかった時間T(sec)を知ることが出来ます
よってここから距離Dは,

D = T × 340(m/sec) ÷ 2

という式で計算すれば求められます.
原理が分かっていれば,超音波の反射しやすいもの(板等の平面状のもの)を用意して距離を測定してあげれば良いことが分かりますね.

さて,今までにも見たように,Starter Kitの各パーツについて解説しているパーツを接続するというページがあるので,早速"距離センサ"のリンクからHC-SR04の解説ページを見てみましょう.

さて,このページを見てみると

[await] measureWait()
measure()と同様ですが、こちらはpromiseを返す関数です。

という関数があります.
これを用いて前回同様プログラムをサクッと作ってみましょう.
(原理や式を解説しましたが,結局ライブラリが計算を全部やってくれますね.楽ちんです.)
「awaitやpromiseって何?」という人は"await promise javascript"等でブラウザで調べて見て下さい.
またその際に「同期処理・非同期処理」という言葉も出てくると思いますのでそれも調べてみると,JavaScriptでのプログラムの仕方がより分かってくると思います.
理解が難しい人は,obnizのプログラム中のawaitを付けたり外したりしてobnizの動作の違いなどを経験的に覚えてみても良いかもしれません.

プログラムを書く

今までの記事でも散々やりましたが,基本的なobnizを動かすプログラム部分に,今度は距離センサ用のライブラリを追加するだけです.
でもサンプルそのままだと1回しか距離が取得出来ないので,ループ文で連続で取得できるようにします.
ループ文は以前サーボモーターを交互に動かすプログラムでループを使うを用いたのを覚えているでしょうか?
今回はobniz.onloopを使ってみることにします.
それでは自分で出来るだけ書いてみてから,下のプログラムと比較してみましょう.
(書くと言ってもライブラリの文をコピーするもよし,自分で全部書いてみるもよし,個々人の裁量で!)
皆さんもそろそろ自分で考えながら書くことに慣れてきましたか?

<!-- HTML Example -->
<html>

<head>
    <!-- 各種環境設定を読み込み -->
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <script src="https://obniz.com/js/jquery-3.2.1.min.js"></script>
    <script src="https://unpkg.com/obniz@3.x/obniz.js"></script>
</head>

<body>
    <script>
        //ここからJavaScript
  var obniz = new Obniz("OBNIZ_ID_HERE"); //自分のobnizのIDを指定
    obniz.onconnect = async function () { //obnizが繋がったら...
    // Javascript Example
    const hcsr04 = obniz.wired("HC-SR04", {gnd:0, echo:1, trigger:2, vcc:3});
    obniz.onloop = async function(){
      let avg = 0;
      let count = 0;
      for (let i=0; i<3; i++) { // measure three time. and calculate average
        const val = await hcsr04.measureWait();
        if (val) {
          count++;
          avg += val;
        }
      }
      if (count > 1) {
        avg /= count;
      }
      console.log(avg);
      await obniz.wait(100);
    }
  };
    </script>
</body>

</html>

これでコンソールログ(Show console logsの部分です)を開けば,以下のような距離が示されるはずです.

さて,今回のレッスンはこれで終わりということで... うーん,流石に少なすぎる気がするのでまたまた他のパーツと組み合わせて動かしてみましょうか!
次のセクションでは,距離センサとLED信号を使ってみましょう!

距離を視覚的に分かるようにしてみよう

さっきまで動かしていたサンプルプログラムでは, avg という部分が何回か計測した距離を平均して示してくれていたので(距離センサの数値のばらつきを抑えるためです),

console.log(avg);

というコンソール画面に文を表示するプログラムで距離をみることが出来ました.
なので,この距離に応じてLED信号の挙動を変えてあげれば良さそうですね.
では早速それを実現する為の項目を考えてみましょう!
注意するのは,
・2つのパーツをちゃんと宣言して使えるようにする
→その際にパーツを接続する場所のピン番号を変える
・distanceという変数を作って,超音波センサ,LED信号のどちらでも使えるようにする
・距離によってLED信号の挙動が変わるように,if~else構文等の条件分岐のプログラム文を書く
あたりだと思います.
LED信号はまだ記事で触れていませんが,パーツを接続するのページから自分で使ってみましょう!
これが出来ればあなたはもう中級者,自分でパーツのページへ行きプログラムを見て使うことが出来るはずです!
ではLED信号についても把握できたら,プログラムを書いてみましょう.もちろんわからない所は下のプログラムを適宜見て大丈夫です.
下のプログラムでは距離によってLED信号が順番に光りますが,どのライブラリの関数を使ってどういう挙動にするかは皆さんの自由です.
ランダムに光るなんていうのも面白いかもしれませんね.

<!-- HTML Example -->
<html>

<head>
 <!-- 各種環境設定を読み込み -->
 <meta name="viewport" content="width=device-width, initial-scale=1">
 <script src="https://obniz.com/js/jquery-3.2.1.min.js"></script>
 <script src="https://unpkg.com/obniz@3.x/obniz.js"></script>
</head>

<body>
 <script> //ここからJavaScript
  var obniz = new Obniz("OBNIZ_ID_HERE"); //自分のobnizのIDを指定
    obniz.onconnect = async function () { //obnizが繋がったら...

        var hcsr04 = obniz.wired("HC-SR04", {gnd:0, echo:1, trigger:2, vcc:3});
        var light = obniz.wired("Keyestudio_TrafficLight", {gnd:4, green:5, yellow:6, red:7});

    obniz.onloop = async function(){
      let distance = 0;
      let count = 0;
      for (let i=0; i<3; i++) { // measure three time. and calculate average
        const val = await hcsr04.measureWait();
        if (val) {
          count++;
          distance += val;
        }
      }
      if (count > 1) {
        distance /= count;
      }
      console.log(distance);
            // await obniz.wait(100);
            if (distance < 50){
                light.single("red");
            }else if(distance <300){
                light.single("yellow");
            }else{
                light.single("green");
            }
    }
  };
 </script>
</body>

</html>

さて,これを実行すると(私のプログラムでは)距離によって近い→赤,中くらい→黄色,遠い→緑とLED信号が光ります.

パーツの接続は以下の写真のように距離センサ:03ピン,LED信号:47ピンにしています.

obniz.wired()の宣言部分を見れば確かにそうなっていますね.
皆さんはどういう挙動にしたでしょうか?自分が思った通りに動けば大成功です!
これからも記事のサンプルをどんどん改造したり1からプログラムを書いたりして,あなただけのパーツの組み合わせで色々動かしてみて下さい!

発展:距離当てゲームを作ろう

今回の発展では何人でも遊べる距離センサを使ったゲームを作ってみます.
例えばランダムに目標の距離の値を決めて,それを当てるゲームはどうでしょう.

  1. プログラムの中で,ランダムに距離を決める
  2. 距離センサの前の,ここだと思う場所に板を差しこむ.
    その距離の目標値からの離れ具合でLED信号を点灯させる.(近い→赤,中くらい→黄色,遠い→緑,など)
  3. 順番を交代して何回かやった後,見事当たったらおめでとう!LEDを全点灯させる!

前回のプログラムを参考にして書いてみます.
さっきも言ったように,「こうすればもっと面白い!」というアイデアがあればどんどん改造しちゃいましょう!

<!-- HTML Example -->
<html>

<head>
 <!-- 各種環境設定を読み込み -->
 <meta name="viewport" content="width=device-width, initial-scale=1">
 <script src="https://obniz.com/js/jquery-3.2.1.min.js"></script>
 <script src="https://unpkg.com/obniz@3.x/obniz.js"></script>
</head>

<body>
 <script> //ここからJavaScript
  var obniz = new Obniz("OBNIZ_ID_HERE"); //自分のobnizのIDを指定
    obniz.onconnect = async function () { //obnizが繋がったら...

        var hcsr04 = obniz.wired("HC-SR04", {gnd:0, echo:1, trigger:2, vcc:3});
        var light = obniz.wired("Keyestudio_TrafficLight", {gnd:4, green:5, yellow:6, red:7});

    var min = 50 ;
    var max = 1000 ;
        let target_distance =  Math.floor( Math.random() * (max + 1 - min) ) + min ;    //min~maxまでのランダムな数を取得する
    while(true) {
      let distance = 0;
            let count = 0;
      for (let i=0; i<3; i++) { // measure three time. and calculate average
        const val = await hcsr04.measureWait();
        if (val) {
          count++;
          distance += val;
        }
      }
      if (count > 1) {
        distance /= count;
      }
            let distance_diff = Math.abs(target_distance -distance);
      console.log("target_distance = " + target_distance + ", distance = " + distance + ", distance_diff = " + distance_diff);
            // await obniz.wait(100);
            if (distance_diff < 5){
        light.green.on();
        light.yellow.on();
        light.red.on();
      }else if (distance_diff < 50){
                light.single("red");
            }else if(distance_diff < 150){
                light.single("yellow");
            }else{
                light.single("green");
            }
    }
  };
 </script>
</body>

</html>