去年は「dwango readerを作るとしたら」というテーマだったので「紙テープでフィードが出力されたらおもしろいかなあ」とがんばってみたのですが、ちゃんと完成せず時間切れ。ちょっとくやしかったので、今年はもうちょっとサクッと作れそうなものを手がけてみることにしました。つまり「潜水艦をハンドパワーで潜航させてみる」!
…と、5時間一本勝負、やってみたらこんな感じに仕上がりました。
潜水艦ラジコンをLeap Motionで制御するとこまで作って本日の #ドワンゴハッカソン は終了~。5時間で解析からやったにしては上出来かなw https://t.co/3cyskXLNTu
— MIRO (@MobileHackerz) 2014, 7月 7
実のところ当日朝まで何をやるかは決めかねていました。せっかくならフィジカルなものを絡めたい、でも何やるかはいまいち決まらない。ただ、ひとつだけ「Arduinoをつかってみよう」ということだけは決めていました。Arduino以前から普通にマイコン野郎だったということもあって、なんだかいままで使う機会が微妙になかったのでした。せっかくだから使ってみたい。ハッカソンの趣旨(普段使っていない環境で書くべし)にも合うし。
以降、ハッカソン中に書き込んだツイートをベースに、どんなふうに進めていったかをまとめてみます。
最初は超小型クアッドコプターを制御しようかなーと思っていたのですが、
- コントロールが無線(2.4GHz)なので直接制御はできず「プロポを改造して制御する」ことになる
- つまりプロポをぶっ壊す必要があるが正直もっと遊びたい(壊すのが惜しい)
- 赤外コントロールのヘリコプターの安いやつでも買って(プロポは使わず)直接制御しようかなと思ったがぐぐってみたら既に先達がいるようだ
- で、どうしようかなーと思いながらビックカメラをうろついていたら、おもしろげな超小型潜水艦はっけん!
こいつを制御してみよう…!と決定。これが朝11時ころ。
その後ミーティングをひとつ済ませ、さっそく使えそうな部品や機材をかばんに放り込んでハッカソン会場に移動します。ハッカソン自体は13:30~18:30、5時間でどこまでできるか、いざ勝負です!
今日はハッカソンなので出社ついでに潜水艦買ってきた #ドワンゴハッカソン pic.twitter.com/T6SqOMdhUi
— MIRO (@MobileHackerz) 2014, 7月 7
とりあえずあそぶ #ドワンゴハッカソン pic.twitter.com/kSn31xqnhw
— MIRO (@MobileHackerz) 2014, 7月 7
そしてコントローラーから出てる波形眺める #ドワンゴハッカソン pic.twitter.com/Syu5goL5li
— MIRO (@MobileHackerz) 2014, 7月 7
前進・後進・左右旋回・潜航・浮上のそれぞれパターンを読んだ(13:30からはじめていまここ) #ドワンゴハッカソン pic.twitter.com/wRwRM8qGbw
— MIRO (@MobileHackerz) 2014, 7月 7
手持ちの赤外LEDがチップしかなかったので足つけて下準備完了。Arduinoと向き合う #ドワンゴハッカソン (※「普段使ってない環境(言語/フレームワーク)を使う」というルールがあるんだけど、実はArduino使ったことなかった) pic.twitter.com/iCCBC5CeRc
— MIRO (@MobileHackerz) 2014, 7月 7
Arduinoから送った信号でやっと潜水艦が動いた(前進コマンド)!いやしかしあれだ、書きやすいのはいいけどやっぱりタイミングクリティカルなことしようと思うと普通に生マイコン触りたくなるな… #ドワンゴハッカソン
— MIRO (@MobileHackerz) 2014, 7月 7
するとどうもパルス幅がdelayMicrosecondsの値通りにならないのです。delay以外の関数呼び出しなどのオーバーヘッドがあるにしてもちょっと許容できない遅れが見られます(場合によっては数百μSec程度遅れている)。うーん、こういうとき生マイコンでポート叩いているとどこに時間がかかっているのかさすがにすぐわかるのですが、Arduinoは初めてなのでよくわからないです。しかたないので、オシロで波形を見ながら希望するタイミングになるようにdelayMicrosecondsの引数を適当に調整することにしました。気持ち悪いのですが(本来はちゃんとボトルネックを確認したうえで実時間処理できていることを保証したい)時間がないし仕方ない。今回初めてArduinoを触ってみて一番引っかかったのがここで、あとはびっくりするくらい簡単でした。こりゃ流行るわ。うん。(ようやく理解した)void IR_ON() { tone(ir_led, ir_freq); digitalWrite(indicate_led, HIGH); } void IR_OFF() { noTone(ir_led); digitalWrite(ir_led, HIGH); digitalWrite(indicate_led, LOW); } void IR_0() { IR_ON(); delayMicroseconds(400); IR_OFF(); delayMicroseconds(1200); } void IR_1() { IR_ON(); delayMicroseconds(1200); IR_OFF(); delayMicroseconds(400); }
キーボードで操作できる楽しいw #ドワンゴハッカソン https://t.co/narymotSpr
— MIRO (@MobileHackerz) 2014, 7月 7
潜水艦動くのたのしくて先進めるのほっぽらかして遊んでたら、最初に調べたプロトコルに不備が見つかったのでもう一回ちゃんと調べ直した #ドワンゴハッカソン pic.twitter.com/mhbQqRlMrw
— MIRO (@MobileHackerz) 2014, 7月 7
まあだいたいやりたいことはできたっぽいのでLT枠確保。もうちょい調整して発表資料つくる #ドワンゴハッカソン
— MIRO (@MobileHackerz) 2014, 7月 7
…というわけで、冒頭の動画のように操作できるようになりました。ハッカソン終了までに間に合った!
最後に、参考までに今回書いたArduinoのスケッチを置いておきます。赤外LEDを3番と+5V間に接続してつかいます(3番=LoでLED点灯)。
#define SUBMARINE_UP (0x01) #define SUBMARINE_DOWN (0x02) #define SUBMARINE_FRONT (0x04) #define SUBMARINE_BACK (0x08) #define SUBMARINE_LEFT (0x10) #define SUBMARINE_RIGHT (0x20) int ir_led = 3; int indicate_led = 9; int ir_freq = 38000; char submarine_mode = 0; void setup() { pinMode(ir_led, OUTPUT); pinMode(indicate_led, OUTPUT); Serial.begin(9600); submarine_mode = 0; } // the loop routine runs over and over again forever: void loop() { CheckSerial(); IR_SendMode(); } void IR_ON() { tone(ir_led, ir_freq); digitalWrite(indicate_led, HIGH); } void IR_OFF() { noTone(ir_led); digitalWrite(ir_led, HIGH); digitalWrite(indicate_led, LOW); } void IR_0() { IR_ON(); delayMicroseconds(200); IR_OFF(); delayMicroseconds(1100); } void IR_1() { IR_ON(); delayMicroseconds(600); IR_OFF(); delayMicroseconds(400); } void IR_Send(char ch) { int i; for(i=0;i<7;i++) { if ((ch & 0x40)==0) { IR_0(); } else { IR_1(); } ch = ch << 1; } } void IR_SendPacket(char ch1,char ch2) { IR_Send(ch1); IR_Send(ch2); delayMicroseconds(7500); IR_Send(ch1); IR_Send(ch2); delay(128); } void CheckSerial() { char ch; while(Serial.available()>0) { ch = Serial.read(); switch(ch) { case 'u': submarine_mode |= SUBMARINE_UP; break; case 'd': submarine_mode |= SUBMARINE_DOWN; break; case 'f': submarine_mode |= SUBMARINE_FRONT; break; case 'b': submarine_mode |= SUBMARINE_BACK; break; case 'l': submarine_mode |= SUBMARINE_LEFT; break; case 'r': submarine_mode |= SUBMARINE_RIGHT; break; default: submarine_mode = 0; } } } void IR_SendMode() { unsigned char b8 = (unsigned char)submarine_mode; b8 = (unsigned char)( ((b8 & 0xAA) >> 1) + (b8 & 0x55) ); b8 = (unsigned char)( ((b8 & 0xCC) >> 2) + (b8 & 0x33) ); b8 = (unsigned char)( ((b8 & 0xF0) >> 4) + (b8 & 0x0F) ); IR_SendPacket(b8<<1,submarine_mode); }Arduinoはじめてなのでなんかこれでいいのかもよくわかっていないのですが(少なくともパルスのタイミングのあたりはとても気持ち悪い)、まあ動いているので参考までに。
で、「できたー!まにあったー!」という喜びのまま成果発表したわけですが…
このハッカソンの成果、Arduinoはあるわ水槽はあるわLeap Motionはあるわ(外部モニタはぶら下げてるわ)で結構デモ環境が大掛かりなのです。
成果発表後少しいろいろな人にデモし、その後片付けに手間取っている間にハッカソン後のパーティタイムがあらかた終わってしまいピザやら寿司やらに全くありつけない事態になるとはまったく想像していなかったのでした。とほほー。