nariのアイコン画像
nari 2021年05月08日作成 (2021年05月10日更新)
製作品 製作品 閲覧数 918
nari 2021年05月08日作成 (2021年05月10日更新) 製作品 製作品 閲覧数 918

ラジコンカー&RFIDでミニゲーム作った

ラジコンカー&RFIDでミニゲーム作った

作ったもの&はじめに

スマホで操作できるラジコンカーを使って、RFIDに予め書き込んだポイントを集めていくミニゲームを作成しました。

ラジコンカーは入門編として作成する人が多いと思いますが、次のステップとして別のモジュールを組み合わせてゲーム化することで小中学生なども楽しめる&想像力を掻き立てるようなものにしたいと思い作成しました!

ゲームルール

基本ルール:制限時間内フィールドのタグを検知してポイントを集めていく
制限時間:90秒
タグ:2種類あり
・ポイントタグ(10ポイント)
・アイテムタグ
 当たり①:制限時間プラス(30秒)
 当たり②:ポイントプラス(30ポイント)
  ハズレ:ポイントマイナス(10ポイント)
その他ルール:同じタグは2回連続で検知できない。アイテムタグは1回のみ検知することができる

ゲーム動画

まずはご覧ください!

ここに動画が表示されます

操作画面について
キャプションを入力できます

部品一覧

マイコン obniz Board 1Y
モバイルバッテリー cheero Canvas 3200mAh IoT対応
RFID RC522
モータ 下記参照
モータドライバ L91110S

写真

ゲーム画面 スマホUI

ラジコンカーをスマホで操作する&ゲーム画面を作成します。こちらはCSSなどを利用してボタンに高級感を出しています。
キャプションを入力できます

コード該当部

<style type="text/css">
      .btn-circle {
        display: inline-block;
        text-decoration: none;
        font-size:80px;
        background: #2ECFCA;
        color: #FFF;
        width: 120px;
        height: 120px;
        line-height: 120px;
        border-radius: 80%;
        text-align: center;
        font-weight: bold;
        overflow: hidden;
        box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.05);
        border-bottom: solid 6px #359ddb;
        transition: .05s;
      }
      .btn-circle:active {
        -webkit-transform: translateY(4px);
        transform: translateY(4px);
        box-shadow: 0 0 1px rgba(0, 0, 0, 0.15);
        border-bottom: none;
      }
      body{
        background-color: #F9F3DE;
        font-size: 20px;
        font-weight: bold;
        -webkit-touch-callout: none;
        -webkit-user-select:none; // テキスト長押しの選択ボックスを無効化
      }
      p{
        font-family: "Arial", "メイリオ";
      }
    </style>

ラジコンカー

アマゾンで購入しました。モータ2つ+電池ボックス付きです。これは走ればなんでもいいと思います。今回はモータドライバも合わせて使用します。
キャプションを入力できます

RFID

こちらもアマゾンで購入しました。予めタグを読み取りIDを記録しておきます。
キャプションを入力できます

ちょっと無理やりですが付けました。
キャプションを入力できます

タグID読み取りコード

<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" />
    <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
    <script src="https://unpkg.com/obniz@3.x/obniz.js" crossorigin="anonymous" ></script>
  </head>
  <body>
    <div id="obniz-debug"></div>
    <script>
      var obniz = new Obniz("OBNIZ_ID_HERE");
      // Javascript Example
      obniz.onconnect = async function () {   // If obniz connect

        var mfrc522 = obniz.wired("MFRC522", { cs: 0, clk: 1, mosi: 2, miso: 3, gnd: 4, rst: 5, vcc: 6 });
      while(true) {
	      try {
          let card = await mfrc522.findCardWait();
          console.log("Card is detected!");
          console.log("UID : " + card.uid);
          console.log("PICC Type : " + card.PICC_Type);
          obniz.display.print(card.uid);

	        } catch(e) {
		      // Not Found or Error
		      console.log("タグをかざしてください")
          obniz.display.print("タグをかざしてください");
          obniz.display.clear()
          // console.error(e)
	        };
      };
      };
    </script>
  </body>
</html>

結線図

結線簡易図

キャプションを入力できます

結線表

obniz 0 RFID cs
obniz 1 RFID clk
obniz 2 RFID mosi
obniz 3 RFID miso
obniz 4 RFID rst
obniz 5 RFID gnd
obniz 6 RFID vcc
obniz 7 モータドライバ A1
obniz 8 モータドライバ A2
obniz 9 モータドライバ B1
obniz 10 モータドライバ B2

実写

実際に配線するとゴチャゴチャしてしまうので今回はテイッシュボックスの箱で隠してしまいました。

実際の配線
キャプションを入力できます

隠したあと
キャプションを入力できます

コード

<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" />
    <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
    <script src="https://unpkg.com/obniz@3.x/obniz.js" crossorigin="anonymous" ></script>
    <style type="text/css">
      .btn-circle {
        display: inline-block;
        text-decoration: none;
        font-size:80px;
        background: #2ECFCA;
        color: #FFF;
        width: 120px;
        height: 120px;
        line-height: 120px;
        border-radius: 80%;
        text-align: center;
        font-weight: bold;
        overflow: hidden;
        box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.05);
        border-bottom: solid 6px #359ddb;
        transition: .05s;
      }
      .btn-circle:active {
        -webkit-transform: translateY(4px);
        transform: translateY(4px);
        box-shadow: 0 0 1px rgba(0, 0, 0, 0.15);
        border-bottom: none;
      }
      body{
        background-color: #F9F3DE;
        font-size: 20px;
        font-weight: bold;
        -webkit-touch-callout: none;
        -webkit-user-select:none; // テキスト長押しの選択ボックスを無効化
      }
      p{
        font-family: "Arial", "メイリオ";
      }
    </style>
  </head>
  <body>
    <div id="obniz-debug"></div>
    <div style="inline">
    <span>TotalPoint:</span>
    <span id = "score"></span>
    </div>
    <span>Time:</span>
    <span id = "cntdown"></span>

    <div id="text-button"><p id="text" style="text-align:center;font-size: 20px;width: 250px;border: solid">Ready??(Push Start)</p></div>
    <div class="mt-5">
      <div class="text-center">
        <div id="front" class="btn-circle" ontouchstart="">↑</div>
        <div id="turn_l" class="btn-circle" ontouchstart="">↻</div>
      </div>
      <div class="text-center">
        <div id="back" class="btn-circle" ontouchstart="">↓</div>
        <div id="turn_r" class="btn-circle" ontouchstart="">↺</div>
      </div>
    </div>

    <script>
      /*RFIDミニゲーム ver0*/
      var obniz = new Obniz("OBNIZ_ID_HERE");
      var score = 0;
      var timer1 = null;
      var cntdown = 90;
      var timeLimit = cntdown * 1000;
      let startTime;
      var flag = 1;
      var random_tag_flag = 0;
      var plus_time = 30; //ランダムダグ 時間追加
      var plus_score = 30; //ランダムダグ ポイント追加
      var minus_score = 10; //ランダムダグ ポイント追加
      var temp_tag = ""; //一つ前に読み取ったタグ

      document.getElementById('score').innerHTML = score; //スコア表示
      document.getElementById('cntdown').innerHTML = cntdown; //カウントダウン表示

      const tags_normal = [
        {uid:"[204,1,174,46,77]",point:10},
        {uid:"[138,169,67,134,230]",point:10},
        {uid:"[42,205,7,133,101]",point:10},
        {uid:"[172,208,70,35,25]",point:10},
        {uid:"[106,210,50,134,12]",point:10},
        {uid:"[183,47,208,198,142]",point:10},
        {uid:"[202,206,63,134,189]",point:10},
        ];
      
      const tag_random = "[234,24,49,134,69]"

      //タイマー
      function updateTimer(){
        cntdown = startTime + timeLimit - Date.now();
        document.getElementById('cntdown').innerHTML = parseInt(cntdown/1000);
        const timeoutId = setTimeout(() => {
          updateTimer();
        }, 10);
        if(cntdown <= 0){
          document.getElementById('cntdown').innerHTML = "Time UP!!";
          flag = 0;
        }
      }

      //ランダムタグ
      function random_tag(){
        if(random_tag_flag == 0 ){
          var ram_no = Math.floor( Math.random() * 3 );

          switch(ram_no){
            case 0: //残り時間追加
              console.log("時間追加!!");
              timeLimit += plus_time*1000; 
              random_tag_flag = 1;
              document.getElementById("text").innerHTML = "Time Plus!!";
              break;
            case 1: //スコア追加
              console.log("スコア追加!!")
              score += plus_score;
              random_tag_flag = 1;
              document.getElementById('score').innerHTML = score ;
              document.getElementById("text").innerHTML = "Point Plus!!";
              break;
            case 2: //クラッシュ
            console.log("クラッシュ!!")
              score -= minus_score;
              random_tag_flag = 1;
              document.getElementById('score').innerHTML = score ;
              document.getElementById("text").innerHTML = "Point Minus!!";
            break;
          }
        }        
      };

      obniz.onconnect = async function () {   // If obniz connect
        var mfrc522 = obniz.wired("MFRC522", { cs: 0, clk: 1, mosi: 2, miso: 3, gnd: 5, rst: 4, vcc: 6 }); //RC522ライブラリ ピン配置は数値の通りに行う
        //wire one motor (left) to obniz
        let motorA = obniz.wired("DCMotor", { forward: 7, back: 8 });
            motorA.power(60);
        //wire the other motor (right) to obniz
        let motorB = obniz.wired("DCMotor", { forward: 9, back: 10 });
            motorB.power(60);

        //ボタンを押してスタート
        document.getElementById("text-button").onclick = async function() {
          document.getElementById("text").innerHTML = "Go!!";
          startTime = Date.now();
          //メインループ
          while(flag) {
            try {
              //while upper front button is clicked
              $("#front").on("touchstart mousedown", () => {
                //rotate left motor forward
                motorA.move(true);
                motorB.move(true);
                console.log("前進")
              });
              //if upper front button is released
              $("#front").on("touchend mouseup", () => {
                //stop left motor
                motorA.stop();
                motorB.stop();
              });
              //while back left button is clicked
              $("#back").on("touchstart mousedown", () => {
                //rotate left motor backward
                motorA.move(false);
                motorB.move(false);
              });
              //if lower back button is released
              $("#back").on("touchend mouseup", () => {
                //stop left motor
                motorA.stop();
                motorB.stop();         
              });

              //while turn_left upper button is clicked
              $("#turn_l").on("touchstart mousedown", () => {
                //rotate right motor forward
                motorA.move(true);
                motorB.move(false);
              });
              //if turn_left upper button is released
              $("#turn_l").on("touchend mouseup", () => {
                //stop right motor
                motorA.stop();
                motorB.stop();
              });

              //while turn_right lower button is clicked
              $("#turn_r").on("touchstart mousedown", () => {
                //rotate right motor backward
                motorA.move(false);
                motorB.move(true);

              });
              //if turn_right lower button is released
              $("#turn_r").on("touchend mouseup", () => {
                //stop right motor
                motorA.stop();
                motorB.stop();
              });
                    

              
              updateTimer();
              let card = await mfrc522.findCardWait();
              //タグidを検索 TF
              if(tags_normal.some((v) => v.uid === JSON.stringify(card.uid))&&temp_tag!=JSON.stringify(card.uid)){
                  const targetList = tags_normal.find((v) => v.uid === JSON.stringify(card.uid)); //ポイントを抽出
                  console.log("point",targetList.point);
                  obniz.display.print("ポイント = ",targetList.point);
                  score += targetList.point; //ポイントを加算
                  document.getElementById('score').innerHTML = score ;
                  document.getElementById("text").innerHTML = "Get!";
                  // console.log("Card is detected!");
                  // console.log("UID : " + card.uid);
                  // console.log("PICC Type : " + card.PICC_Type);
              }else if(tag_random==JSON.stringify(card.uid)&&temp_tag!=JSON.stringify(card.uid)){ //ランダムタグ
                random_tag();
              }else{
                  console.log("ERROR!!")
                  obniz.display.print("ERROR!!");
                  console.log("UID : " + card.uid);
                  document.getElementById("text").innerHTML = "Get!";
              }
              } catch(e) {
              // Not Found or Error
              obniz.display.clear()
              // console.error(e)
              };
          };
        };

      };
    </script>
  </body>
</html>

やってみてわかったこと・気になったこと

・モータ、RFIDを動かすまではサンプルコードがあるため簡単
・ピンが少ないので大掛かりな装置は工夫が必要
・ロボットの制御マイコンとして使うには反応が悪いためむいていない(こればかりはobnizの仕様のため仕方ない。)

終わりに

今回の作業を通じてobnizを本格的に触りましたが、とても素晴らしいものです。このデバイスを足掛かりにスキルアップに努めたいと思います。

nariのアイコン画像
20代の機械設計士です。エンジンを動力とした乗り物や台車を設計しています。IoTのようなハードとソフトが繋がるシステムが大好きです。 Qiita →https://qiita.com/taiyyytai
ログインしてコメントを投稿する