Maker Faire Tokyo 2019の僕らのコンセプトが「お祭り」ということで、神事でもある相撲をダンボールで執り行いたいと思いました。
が、そのまま大きな紙相撲を作るだけではMake(自分で創作するの意味)していないので、自動で動く土俵で落ちない様な力士を作るワークショップをして、その力士同士で相撲させるロボット土俵を作ることにしました。
まずはハードウエアスケッチ!
早速、どんな感じで動くのか?テアタマ〜ズ!の他のメンバーにも理解してもらうためにまずは動くモデルを作ります。土俵の真ん中に牛乳パックで作った紙バネを着けて
X軸とY軸に手元にあったサーボモータをそれぞれ取り付け、中華なarduinoを繋いで動かしてみます。
アームの組み方を検証
まあ動くのですが、あまりブルブル感がないので、サーボモータと土俵をつなぐアーム部分を何通りか違う組み合わせで試して、土俵自体を少し回転しつつ上方にも突く感じの組み方を見つけて実際に1/3位の力士を作って試します。
いい感じで動いて対戦が成立する感じなので、いくつか形の組み合わせを考えつつ力士のレギュレーションを仮決めします。
実寸でプロトタイプ
1/3サイズだと、本当に上手く動くか心配だ〜というメンバーの声から、実際の想定サイズ(直径75cm)のW段でプロトタイプを作り、動かして見せることに。
真ん中にダンボール製の紙バネを入れ込み、そのXY軸に1/3モデルと同様にサーボを配置して稼働してみると…ダンボールが振動を吸収してしまい思った様に土俵が動きません。
そこでサーボモータをXY軸からズラし、平面で正三角形の頂点の位置に来る様に均等に120度の角度で3台のサーボを配置して、より強力に振動させることにしました。
またなるべく土俵面が水平になる様に、土俵面と底板との距離が均等になる様に水糸で面同士を結びます。
もう一つ工夫したのは、アームを廃棄プラ定規で作り、ピンにプラネジを使うことで現場ですぐ組み立てられる上に結構精度の高い動きが実現できる様にしたことです。
無事組み上がった土俵で、レギュレーションに沿った力士を作ってメンバーにデモしたところ、約1分で勝負がつく様だとナカナカ好評だったので、これでGOということで練習用と予備も含め3台の土俵を作ることになりました。
ちなみに、なぜ土俵のサイズが直径75cmに決め打ちだったかと言うと…昨今の物流コストの上昇から、ヤマト便で送れる大きさに梱包が収まるものである必要(3辺合計2m以内)があったからです。できるだけ山形の工房で組立て梱包>ヤマト便でビックサイトまで届けることが、最初から求められていたこその大きさなのです。
モノ作りも時代の波に沿っていかなければ〜ですが、正直毎回ストレス感じます。なぜなら最初から自分がチマチマ考える様になって来ている気がするからです。負けないですが!(笑)
後は現場で〜が…
この時点で「何か忘れてない?」と思う方もいるかと思います。そうプログラムです。
今回のMFTもう全くというほど時間なく…その辺りは移動中に小さなサーボで検証しながら、まずは振動させるだけで初日を迎えました。
1日目は、振動するだけのためか対戦時間が2分近くになり取組が長引きました。
そこで、各サーボをランダムに動かすプログラムを書きましたが、それに振動を組み合わせるのに手こずっていました。
単に3台のサーボモータをブルブル振動させるだけのコード▼
#include <Servo.h> //サーボモーターのライブラリを読み込む
Servo servo1; //servo1っていう名前で使う
Servo servo2; //servo2っていう名前で使う
Servo servo3; //servo3っていう名前で使う
int i = 0; // デフォルト(中立)の角度を0度に
int rd = 0; // デフォルト(中立)のランダム角度を0度に
void setup() {
servo1.attach(3); //3番ピンを使う
servo2.attach(6); //6番ピンを使う
servo3.attach(9); //9番ピンを使う
}
void loop() {
for (i = 0; i < 8; i++) { //0から8度まで1度刻みで角度iを増やす
servo1.write(i);
servo2.write(i);
servo3.write(i);
delay(10); //待ち時間
}
for (i = 8; i > 0; i--) { //8から0度まで1度刻みで角度iを減らす
servo1.write(i);
servo2.write(i);
servo3.write(i);
delay(10); //待ち時間
}
}
3台のサーボをそれぞれランダムに動かすコード▼
#include <Servo.h> //サーボモーターのライブラリを読み込む
Servo servo1; //servo1っていう名前で使う
Servo servo2; //servo2っていう名前で使う
Servo servo3; //servo3っていう名前で使う
int pos = 90; // デフォルト(中立)の角度を90度に
void setup()
{
servo1.attach(3); //3番ピンを使う
servo2.attach(6); //6番ピンを使う
servo3.attach(9); //9番ピンを使う
}
int angle1 = 0; //角度の変数
int angle2 = 0; //角度の変数
int angle3 = 0; //角度の変数
void loop()
{
angle1 = random(88,93); //ランダムに88〜93度の間で動く
angle2 = random(87,92); //ランダムに87〜92度の間で動く
angle3 = random(86,91); //ランダムに86〜91度の間で動く
servo1.write(angle1); //サーボに送る
servo2.write(angle2); //サーボに送る
servo3.write(angle3); //サーボに送る
delay(8); //0.15秒待つ
}
さてどうしようかと悩んでいると…ブースにプログラマさん(マジックロジック 齋藤さん)が居るではありませんか!
即ご相談し、僕の書いた2つのプログラムを掛け合わせる方法を教えていただきつつ書いていただき、無事ランダム感ありつつ土俵面自体も振動し続けるイイ感じのロボット土俵ができました。
齋藤さんに改善していただいたコード▼
#include <Servo.h> //サーボモーターのライブラリを読み込む
Servo servo1; //servo1っていう名前で使う
Servo servo2; //servo2っていう名前で使う
Servo servo3; //servo3っていう名前で使う
int i = 0;
int angle1 = 0; //角度の変数
int angle2 = 0; //角度の変数
int angle3 = 0; //角度の変数
void setup() {
servo1.attach(3); //3番ピンを使う
servo2.attach(6); //6番ピンを使う
servo3.attach(9); //9番ピンを使う
}
void loop() {
int minAngle = 0; //動かす角度の最小値を0度に設定
int maxAngle = 13; //動かす角度の最大値を13度に設定
int randamMax = 7; //ランダムに書き出す数字の最大値を7に設定
int delayTime = 5; //待ち時間の設定
//最小角度+ランダムな数字=出てくる角度に動いて待つ(各サーボ)
servo1.write(minAngle + random(0,randamMax));
servo2.write(minAngle + random(0,randamMax));
servo3.write(minAngle + random(0,randamMax));
delay(delayTime);
//最大角度+ランダムな数字=出てくる角度に動いて待つ(各サーボ)
servo1.write(maxAngle+random(0,randamMax));
servo2.write(maxAngle+random(0,randamMax));
servo3.write(maxAngle+random(0,randamMax));
delay(delayTime);
}
2日目は、その土俵で熱戦が繰り広げられたのは、言うまでもありません。
熱戦すぎて、泣き出す子供も出てきて、白熱する取組ができてよかったです。
2日目の後半に気がつきましたが、勝負が長引いたのは別の理由で…なんと3台のうちに1台のサーボモータが異常発熱し接着していたグルーが溶けてしまい、サーボ自体が回転してしまったことが原因の一つでした。そのため上記のプログラムで動かしつつ、取り組み中に手でサーボを抑え続ける〜という、なんともアナログな感じで稼働させたのでした。
なおこのロボット土俵の作成にご協力いただいたのは以下の方々です。
株式会社美販 東大阪のダンボール加工会社 http://www.bihan.jp/
株式会社アルテコ 接着剤の専業メーカー https://www.alteco.co.jp/
マジックロジック 齋藤さん 面白い!をプログラムで実現 http://magiclogic.jp/