obniz とソレノイドで 遠隔対戦もできる!おすもうバトル
ソレノイドでおすもうバトルゲームを作った
制作のきっかけ
[試作1] 箱をトントンして駒を動かすトントン相撲
ふと「5Vソレノイドでトントン相撲を作ったら楽しそう」と思ったのがきっかけです。
トントン相撲は台を手でトントン叩くことによって駒(お相撲さん)を進めて相手を倒す2人対戦型の昔ながらのゲームです。
このトントン叩く部分をソレノイドで作れないかなと思いました。
これは台を叩くのが横方向なのですが、縦方向にするために固定させるのが時間かかりそうだったのでとりあえずの形でこうしました。縦でも横でも揺れ感と進行方向は変わらなかったです。
ただなかなか思う方向に進んでくれませんでした。
これについては結局は駒の形が問題だったのですが、試行錯誤を重ねていくうちに「ソレノイド自体を飛び跳ねさせると楽しい」と思い、ソレノイド自体を戦わせるものを作りました。
[試作2] ソレノイド相撲
[試作3] 帽子落としバトル
「相手の帽子を落としたら勝ち」というゲームもいいなと思ったのですが、動作確認すると何度やっても動いた人が自分の帽子を落とすことがほとんど(=動かない人が勝つ)だったのでやめました。
■ 製作の方針決定
試作2のソレノイド同士をバトルさせる形に決めました。
キャラクター設計・3Dプリント
- 足パーツ … ソレノイドをはめこむパーツ
- 頭パーツ … 足パーツよりひとまわり大きく被せる形
- ぼうし/かつら … 頭の上にマグネットで装着
頭・足パーツはFusion360で設計しました。
かつらパーツはペットボトルキャップに羊毛フェルトをくっつけて作成しました。ペットボトルキャップの裏側にはマグネットを貼り付けており、ソレノイドのてっぺんにぴたっとくっつくようになっています。
ソレノイド制御基盤を支える治具
最初は変な方向にしか進まなかったのでうまくお相撲することができませんでした。
ソレノイドに繋がっているケーブルが影響している(ひっぱられている)ということがわかり、ソレノイドのケーブルに繋がっている制御基板(ここではUSB接続するための5Vソレノイド用の制御基板のこと)を固定する治具を作成することであらかたまっすぐ進むようにできるようになりました。
上記画像の黒い柱がそれです。
こちらもFusion360で設計し制御基盤をねじ止めできる穴2つと、下部に土俵に固定するためのねじ穴をあけました。
obnizを使ってリモート対戦できる構成
手動ON/OFF
ソレノイドへのON/OFF制御は「ソレキット マルチコントローラー」を使いました。
ねじをあけて上部のカバーをはずすと中身は「マルチコントローラーUSB」になっています。
これを電源に接続してボタンを押すことでソレノイドのON/OFF制御ができます。
こちらのコントローラーを使用する時にソレノイド制御基板にはジャンパーピンをお忘れなく。
obnizに接続するためにマイコンを接続
まずはマルチコントローラーにGroveコネクタをはんだづけしました。
これが結構苦戦しました。
見た目にはうまくはんだづけできている気がするのに接触不良でやりなおし安定するまで3度ほどやり直しました。
そして obniz を動かすためにマイコン(ESP32 DevKitC)をマルチコントローラーに接続しました。
上記ツイートは、試作品段階で obniz を 3台構成で接続しています。
この記事にまとめている最終形では、ESP32 DevKitC 1台のみobnizOS をインストールしたものを準備して作成しています。
なおobniz OSは esp32w バージョン3.5.0(この時点で最新)を利用しobniz Writerで書き込みを行いました。
回路と基板
右上のGrove1がマルチコントローラーのGroveコネクタです。IO16と17を制御することでそれぞれに繋がっているソレノイドを動かすことができます。
またLEDも赤と緑をそれぞれ1つ接続し、リモートアクセスが行われた時に光るようにしました。ソレノイドが動かない場合がにそもそも信号が届いているのいないのか切り分けを行うことができます。
図ではLEDと抵抗を書きましたが実際には抵抗入りLEDを使用しています。
これをユニバーサル基板にはんだ付けしました。
ちなみにマルチコントローラーと基板もネジで接続して一体型にしました。
ユニバーサル基板の端の穴の径を大きくすればマルチコントローラーの穴とはまりそうだったので、ルーターで穴を削って大きくしました。(初のルーター使用!)
プログラム
リモートおすもう大会プログラム
<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>
<div class="container">
<div class="text-center">
<h3>リモートおすもう大会</h3>
<div style="margin-top: 10px;"><button class="btn btn-primary" id="connect">接続する</button></div>
</div>
<div class="text-center">
<h5 style="margin-top:20px;">プレイヤー設定
<!--<div id="player-no"></div>-->
<!--<input type="text" id="player-no" value="1" />-->
<select id="player-no">
<option value="1">プレイヤー1</option>
<option value="2">プレイヤー2</option>
</select></h5>
<h5></h5>
</div>
<div class="text-center">
<button class="btn btn-info" id="push" accesskey="t">トン!(T)</button>
<button class="btn btn-info" id="push3" accesskey="y">トントントン!(Y)</button>
</div>
<!--<div class="text-center">
<h5 style="margin-top:20px;">Display Switch State on obniz</h5>
<div id="print"></div>
</div>-->
<div class="text-center">
<div style="margin-top: 100px;"><button class="btn btn-secondary" id="disconnect">切断する</button></div>
</div>
</div>
<script>
let stageObniz;
let led, solenoid;
let isOnceConnected = false;
// ■[接続する]ボタン押下時
$("#connect").on("click", function() {
if (!stageObniz) {
// stageObniz 土俵
stageObniz = new Obniz("XXXX-XXXX"); //TODO ESP32のobniz-idにする
stageObniz.onerror = console.log;
stageObniz.onconnect = async function() {
// ブラウザが居続けるとデバイスが再起動した時また繋がりにいくのでそれを避ける
if (isOnceConnected){
alert('再接続するときは「接続する」ボタンを押してください');
stageObniz.close();
stageObniz = null;
isOnceConnected = false;
}else{
isOnceConnected = true;
}
}
}
});
// ■[トン]ボタン押下時
// [トン]ボタン押下時:ボタンを押した瞬間
// pointerdown/up を使うと、mouseup(マウスクリック)やtouchstart(タップ)がどちらも受け取れる
$("#push").on("pointerdown", async function() {
setLedSolenoid($("#player-no").val());
led.on();
// ソレノイドON:ここではボタンから手が離れるまでずっとONにしておく
solenoid.output(true);
});
// [トン]ボタン押下時:ボタンから離した瞬間
$("#push").on("pointerup", async function() {
setLedSolenoid($("#player-no").val());
led.off();
// ソレノイドOFF
solenoid.end();
});
// ■[トントントン]ボタン押下時
$("#push3").on("click", async function() {
setLedSolenoid($("#player-no").val());
led.on();
// 3回連続でソレノイド動かす
await moveSolenoid3Times(solenoid);
led.off();
// ソレノイドOFF
solenoid.end();
});
// ■[切断する]ボタン押下時
$("#disconnect").on("click", async function() {
stageObniz.close();
});
// コントローラー上のLEDとソレノイドをプレイヤーによって切り替える
async function setLedSolenoid(playerNo){
if (playerNo == "1"){
// プレイヤー1:緑
led = stageObniz.wired("LED", {anode:23});
solenoid = stageObniz.io17;
}
else{
// プレイヤー2:赤
led = stageObniz.wired("LED", {anode:2});
solenoid = stageObniz.io16;
}
}
// 3回連続でソレノイドを動かす
async function moveSolenoid3Times(solenoid){
// 連打
for (let i = 0; i <= 2; i++){
solenoid.output(true);
await new Promise((resolve) => { setTimeout(resolve, 150) });
solenoid.output(false);
await new Promise((resolve) => { setTimeout(resolve, 150) });
}
}
</script>
</body>
</html>
<その他必要な設定>
obnizへの接続数の設定が必要です。
デフォルト1人となっているので設定を変更しないと2人対戦なのに1人しか繋げないことになります。
obniz管理画面のデバイスの設定のところで 「API最大同時接続数」というのがあるのでここを増やす必要があります。最低2人にすれば良いですが遊び終わった人が切断を忘れたりすることを想定してMAXの5人にしていても良いと思います。
<操作方法>
「接続する」で接続して接続OK状態になったら、プレイヤーを選択(選択肢はプレイヤー1かプレイヤー2となり話し合ってどちらにするか決めます)、「トン」で1回ソレノイド動作、「トントントン」で3回ソレノイド動作となります。
プログラムのポイントとしては以下です。
■トン・トントントン
「トン」のときはボタンを押した瞬間と話した瞬間のイベントで実行しています。つまり、押している間ソレノイドがON状態となるようにしました。
「トントントン」は150ミリ秒ON /OFFを3回行うようにしていますので長く押したからといって動作は変わりません。
■切断の制御
いったん接続して遊んでくれた人がそのまま画面を閉じずに開き続けていた場合、obniz側を再起動してもまた繋がりにきてずっとコネクションを奪ったままになり厄介だったので一旦切れた場合再接続は「接続する」ボタンを押さないと繋がらないようにロジックを入れてみました。
できあがり
動画を作りました。
投稿者の人気記事
-
siroitori0413
さんが
2023/02/05
に
編集
をしました。
(メッセージ: 初版)
-
siroitori0413
さんが
2023/02/05
に
編集
をしました。
Opening
Kazekaoru
2023/12/08
ログインしてコメントを投稿する突然のご連絡失礼いたします。
PCBGOGOマーケティング部門の葉と申します。
宣伝協力のことに関しまして、
一度ご相談させて頂けませんでしょうか。
ご興味がおありであれば、一度ご連絡をいただけますでしょうか。
ご多用の折恐れ入りますが、ぜひご検討くださいますよう
お願い申し上げます。
メール:service10@pcbgogo.jp