作ったもの&はじめに
スマホで操作できるラジコンカーを使って、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
さんが
2021/05/08
に
編集
をしました。
(メッセージ: 初版)
-
nari
さんが
2021/05/10
に
編集
をしました。
-
nari
さんが
2021/05/10
に
編集
をしました。
ログインしてコメントを投稿する