池袋晶葉ちゃん誕生日に向けてobnizで動くウサちゃんロボを作った

追記：SSR実装しました。
[池袋晶葉ちゃんSSRが可愛いので衣装の一部をobnizで再現した](https://qiita.com/youdie_/items/a128cd285b022eb22cb0)

## ウサちゃんロボを作る

JavaScriptで電子工作ができる、[obniz](https://obniz.io/ "obniz")というものが最近発売されました。
詳細はこの辺が詳しい。
[JavaScriptで制御できる電子工作ボード「obniz」が発売、実売4,980円](https://akiba-pc.watch.impress.co.jp/docs/news/news/1125352.html)

要はブラウザさえあればJavaScriptで簡単に電子工作ができるという超便利ツール。
こ、こりゃ面白そうじゃん！
電子工作やったことないけどJavaScriptならイける！
と食いついてみたものの、

* 電子工作　⇒　ロボ
* ロボ　⇒　メイドインアビスのレグ or アイドルマスターシンデレラガールズの池袋晶葉

くらいしか思い浮かばないオタクだったので、6月10日が池袋晶葉ちゃんの誕生日ということもあり、彼女の代表作**ウサちゃんロボ**を作ってみることにしました。
というかこのタイミングでobnizが出たのはもはやそういう啓示だったのでは？

ちなみにアイドルマスターシンデレラガールズに明るくない方々向けに説明すると、これが池袋晶葉ちゃんで、彼女が抱えているのがウサちゃんロボです。

![Cu229.jpg](https://qiita-image-store.s3.amazonaws.com/0/249864/4b27a57c-08a6-c075-d83d-b547fa88e577.jpeg)

**うむ。可愛い。**
その可愛さについて語るのはQiita向けではないと思うので泣く泣く割愛します。

## やっていきます

早速やっていきましょう。
今回使った素材は以下の通り

* [obniz](https://obniz.io/)（電源＋制御装置）
* [タミヤ楽しい工作シリーズ　アームクローラー工作セット](http://www.tamiya.com/japan/products/70228/index.html)（動力）
* [ウサちゃんロボ　ノンスケールプラモデル](https://www.amazon.co.jp/dp/B01I4FF6YM/ref=cm_sw_r_tw_dp_U_x_Lk5gBb2B9HRX)**（可愛さ）**

上記リンクを見てもらうとわかるように、ウサちゃんロボは**本来二足歩行**。
しかし、いきなり二足歩行ロボを自作するのはハードルが高い。

そこで、俗にいうプロトタイプウサちゃんロボに挑むことにしました。
さっきの画像のような、**キャタピラで動くタイプ**ですね。
というわけでお手軽に手に入るタミヤの工作キットを使うことに。

上記以外に準備したものは、obnizを動かすための**microUSB接続の電源**。

ちょうど最近スマホがType-C接続になったことで持て余していたモバイルバッテリーがあったので、こいつを使うことにしました。
大きさも名刺サイズでちょうどいい感じ。
![DSC_0089.JPG](https://qiita-image-store.s3.amazonaws.com/0/249864/8b7fa1bc-4117-8119-daa5-4409cf1e422b.jpeg)

あとは、自分は電子工作ど素人だったので初めて知ったのですが、諸々の機器をつなぐには**ジャンパワイヤ**というものを使うんですね。

はんだを使わずに差し込んでつなげる、固めのピンつきの導線。
obnizへの接続もこれが前提みたいですね。
Amazonとかで適当に買えます。

では前振りも長くなってきたのでいよいよ製作に入っていきますよ。

### 1. obinizを組み込んでツインモーター式のラジコンを作る

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">工作の素材その一です <a href="https://t.co/QV6mc1s59L">pic.twitter.com/QV6mc1s59L</a></p>&mdash; ud (@youdie) <a href="https://twitter.com/youdie/status/1004715262149455873?ref_src=twsrc%5Etfw">2018年6月7日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

今回ツインモーター式にこだわったのは、モーター１つだと単純な直進後退しかできないから。
やっぱり**超信地旋回**したいじゃないですか。オタクなので。
[Wikipedia: 超信地旋回](https://ja.wikipedia.org/wiki/%E8%B6%85%E4%BF%A1%E5%9C%B0%E6%97%8B%E5%9B%9E)

さてさて、タミヤのラジコンプラモです。
これはもう言われるがままに組み立てるだけ。
ただし、モーターにつなぐのが付属のリモコンではなく、obnizになるというところだけ違います。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">ふむふむ <a href="https://t.co/9OQOHMT4uw">pic.twitter.com/9OQOHMT4uw</a></p>&mdash; ud (@youdie) <a href="https://twitter.com/youdie/status/1005088104808529921?ref_src=twsrc%5Etfw">2018年6月8日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

さあお待たせいたしました。
**ようやくobnizのプログラム部分についての解説です。**

obniz購入後にアカウントと機器のシリアルを登録すると、ブラウザ上で使える開発環境が提供されます。
この辺のチュートリアルだったりモーターとのつなぎ方の詳細は公式が詳しいので割愛しますね。
[quickstart - obniz](https://obniz.io/doc/quickstart)



JavaScriptからモーターを操作するにはSDKの**DCMotor**というパーツを使用します。

```javascript:JavaScript
var obniz = new Obniz("XXXX-XXXX");
obniz.onconnect = async function () {

  var lmotor = obniz.wired("DCMotor", {forward:0, back:1});
  var rmotor = obniz.wired("DCMotor", {forward:2, back:3});

}
```
今回はツインモーター式なので割り当ても二つですね。

そしてこれらのモーターを動かすだけならとても簡単。
HTMLのボタンを置いて、クリックイベントでモーターを動かすメソッドを呼ぶだけです。

```html:HTML
<input id="forward" type="button" value="前進" />
<input id="reverse" type="button" value="後退" />
<input id="stop" type="button" value="停止" />
```
```javascript:JavaScript
var obniz = new Obniz("XXXX-XXXX");
obniz.onconnect = async function () {

  var lmotor = obniz.wired("DCMotor", {forward:0, back:1});
  var rmotor = obniz.wired("DCMotor", {forward:2, back:3});
  
  $("#forward").click(function(){
    lmotor.forward();
    rmotor.forward();
  });

  $("#reverse").click(function(){
    lmotor.reverse();
    rmotor.reverse();
  });

  $("#stop").click(function(){
    lmotor.stop();
    rmotor.stop();
  });

}
```
たったこれだけのコードで前進、後退、停止が実装できました。

あとはobnizさんの電源を入れて、プログラムを実行して表示されたボタンを押せば動きます。

![スクリーンショット 2018-06-09 18.35.19.png](https://qiita-image-store.s3.amazonaws.com/0/249864/6ae10fcd-c55a-f74d-cda1-73bd25c6bd37.png)

**は、早すぎる・・・！**

さらに、上記実装だと両方のモーターを同じ方向に動かしていますが、これを互い違いに動かすことで**夢の超信地旋回**になります。

ということでボタンを増やして動かしてみた結果がこちら。
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">ここまでわりとあっという間に出来てしまった <a href="https://t.co/WAa9BZsPaF">pic.twitter.com/WAa9BZsPaF</a></p>&mdash; ud (@youdie) <a href="https://twitter.com/youdie/status/1005097536791535616?ref_src=twsrc%5Etfw">2018年6月8日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

これでobnizでラジコンを動かすという第一段階はクリア！

### 2. ラジコンをスマホで操作できるようにする

とりあえず動いたものの、もっと手軽に、いうなればラジコンみたいに動かしたいですよね。

手軽といえばスマホ。

**スマホで画面を表示して、横持ちでレバーみたいに操作できたらいい感じになるのでは？**

あとはレバーっぽくするなら**倒し方に応じてモーターの動くスピードも変えたい。**
さらに超信地旋回が捗りそう（どんだけ好きなんだ）
この辺は`<input type="range" />`使ったらいい感じにできるかも？？

**ということで、スマホ用の操作画面を作成してみましょう。**

```html:HTML
  <div id="controller">
    <input id="right" type="range" min="-50" max="50" value="0" step="1" />
    <input id="left" type="range" min="-50" max="50" value="0" step="1" />
  </div>
```

```css:CSS
    html{
      overflow-y: hidden;
    }
    input[type=range] {
      -webkit-appearance:none;
      background:rgb(128,128,128);
      height:24px;
      width:200px;
      border-radius:8px;
      transform:rotate(-90deg);
    }
    input[type=range]::-webkit-slider-thumb{
      -webkit-appearance:none;
      background:#f00;
      height:40px;
      width:40px;
      border-radius:50%;
    }
    input[type=range]::-ms-tooltip{
      display:none;
    }
    input[type=range]::-moz-range-track{
      height:0;
    }
    input[type=range]::-moz-range-thumb{
      background:#f00;
      height:50px;
      width:50px;
      border:none;
      border-radius:50%;
    }
    #controller{
      position: relative;
      width: 100%;
    }
    #left{
      position: absolute;
      left: -60px;
      top: 100px;
    }
    #right{
      position: absolute;
      right: -60px;
      top: 100px;
    }
```

```javascript:JavaScript
var obniz = new Obniz("XXXX-XXXX");
obniz.onconnect = async () => {

  //左右のモーター
  var lmotor = obniz.wired("DCMotor", {forward:0, back:1});
  var rmotor = obniz.wired("DCMotor", {forward:2, back:3});

  //モーターを動かす関数
  var move = (motor, val) => {
    
    //パワー（絶対値）
    var absval = Math.abs(val);
    
    //メモリが0なら停止
    if(val == 0){ motor.stop(); }
    
    //パワーをセットして正の値なら前進、負の値なら後退
    motor.power(absval);
    motor.move(0 < val);
    
  }
  
  /*
    rangeのイベントは以下を使い分け
    ・input  : メモリの値が変わる度に発火
    ・change : ツマミを動かし終わった＝手を離したタイミングで発火
  */
  $("#controller").on("input", "#right", function(){
    
    //右のレバー倒してる間はメモリの位置に応じてモーターを動かす
    var val = $(this).val();
    move(rmotor, val);
    
  }).on("input", "#left", function(){

    //左のレバー倒してる間も同様に
    var val = $(this).val();
    move(lmotor, val);
    
  }).on("change", "#right", function(){

    //レバーから手を離したら0の位置に戻してモーターを止める
    $("#right").val(0);
    rmotor.stop();
    
  }).on("change", "#left", function(){
    
    //左も同様に
    $("#left").val(0);
    lmotor.stop();
    
  });

}
```
一気に全部のソースを載せましたが、ポイントをいくつか。

#### rangeコントロールを縦にして左右配置

やたらとstyle要素の内容が多いですが、これほとんどrangeコントロール用。
この辺を参考にスマホからでも操作しやすいようにツマミを大きくしました。
[input type=range タグをカスタマイズするために](https://www.g200kg.com/archives/2017/12/input-typerange.html)


縦に配置するのは`transform: rotate`で90度回してあげるだけ。
左右配置は`position: absolute`でチャチャっと。

#### rangeのイベントの使い分け

値をとるためのイベントは`change`と`input`の２つがあります。
コメント中にもある通り、それぞれ

|イベント|発火タイミング|
|:-:|:-:|
|input|メモリの値が変わる度|
|change|ツマミを動かし終わったら|

なので、これを使い分けてます。

実際にモーターを動かすのは`input`イベントで。
つまみから手を離したら0の位置に戻す処理を`change`イベントで。

ちなみに各rangeに直接イベントを仕込むと、２つのツマミを同時に動かすのがうまくいかなかったので、親要素のdelegateの形で設定しています。

#### rangeの閾値設定

rangeの値をそのままDCMotorのパワーに設定することで、メモリの位置と走るスピードを連動させます。
負の値の場合は後退ですね。

```html:HTML
<input id="right" type="range" min="-50" max="50" value="0" step="1" />
<input id="left" type="range" min="-50" max="50" value="0" step="1" />
```

```javascript:JavaScript

//モーターを動かす関数
var move = (motor, val) => {
  
  //パワー（絶対値）
  var absval = Math.abs(val);
  
  //メモリが0なら停止
  if(val == 0){ motor.stop(); }
  
  //パワーをセットして正の値なら前進、負の値なら後退
  motor.power(absval);
  motor.move(0 < val);
  
}
```

左右それぞれのrangeでそれぞれで上記の`move`関数を呼び出します。
呼び出すイベントについては前述の通り。

さて、obnizのDCMortorは最大パワーを100まで設定できます。
そりゃ爆走させたいから当たり前のように100から-100を閾値に設定して…

と、いきたいところだったのですが、全速力にしたところあっという間にバッテリーが限界を迎えて停止する羽目に。
確かにモーター２つ動かしてるし、モバイルバッテリーちゃんの電圧では厳しかったか。

そんなわけで半分の50から-50でやってみたところ安定したのでこの値に。
まあスピードにこだわっても仕方ないしね。

#### やっかいなPull-to-Refresh

自分はAndroidを使っているのでChromeさんでコントロール画面を表示することになるのですが、ツマミをぐりぐりしてるとPull-to-Refresh（引っ張って更新）が邪魔をします。

これはよろしくない。
ということで苦肉のスタイル設定。

```css:CSS
html{
  overflow-y: hidden;
}
```

まあそもそもスクロールしちゃダメな画面だし問題なし。

---

ってわけでこんな感じの画面になりました。
横持ち親指スタイルですね。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">スマホからこんな感じの画面でラジコンのスティック的に操作ができます <a href="https://t.co/Ngbf4OLdhD">pic.twitter.com/Ngbf4OLdhD</a></p>&mdash; ud (@youdie) <a href="https://twitter.com/youdie/status/1005359128036794370?ref_src=twsrc%5Etfw">2018年6月9日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>




### 3. ウサちゃんロボのプラモをこさえる

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">工作の素材その二が届きました <a href="https://t.co/CKSejEImRt">pic.twitter.com/CKSejEImRt</a></p>&mdash; ud (@youdie) <a href="https://twitter.com/youdie/status/1005315572563734528?ref_src=twsrc%5Etfw">2018年6月9日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

届いて、

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">さあここからが本番だ <a href="https://t.co/RVZVDPFsFF">pic.twitter.com/RVZVDPFsFF</a></p>&mdash; ud (@youdie) <a href="https://twitter.com/youdie/status/1005334951435296768?ref_src=twsrc%5Etfw">2018年6月9日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

**完成。**

特に説明はありません。
**「わー、かわいいー、ちっちゃーい」**って言いながら作るだけです。

あと勢いあまって**足つけちゃってますね。**
後で取り外します。

### 4. ワハハ、いよいよ完成だぞ！

余ったダンボールを使って箱を作成して、モバイルバッテリーとobniz本体と配線を収納。
そしてラジコンにマウント。

その上にさらに足を外したウサちゃんロボを乗っけて完成！

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">とりあえず工作部分は完成！！ <a href="https://t.co/RMOu8OCMaK">pic.twitter.com/RMOu8OCMaK</a></p>&mdash; ud (@youdie) <a href="https://twitter.com/youdie/status/1005352516769361920?ref_src=twsrc%5Etfw">2018年6月9日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

さあ、いよいよ動かします。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">明日の池袋晶葉ちゃん誕生日に向けて、自在に動くウサちゃんロボを作りました <a href="https://t.co/JCM9ex3aaD">pic.twitter.com/JCM9ex3aaD</a></p>&mdash; ud (@youdie) <a href="https://twitter.com/youdie/status/1005358124688015360?ref_src=twsrc%5Etfw">2018年6月9日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

わーいわーい楽しい。

多少スピード感には欠けますが、超信地旋回もできるし、操作自体もほとんどラグがなくてストレスフリー。
obnizは**同じWi-Fiスポットにつながった機器であればそのローカルエリア内で接続する**ため、ラグが少なくできるらしいです。

そしてモバイルバッテリーのLEDが光ってるのがロボ感あって個人的に好き。

ウサちゃんロボのプラモは顔のシールがいくつか用意してあって差し替えができるんですが、充電中はこんな風にもできます。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">リアル充電中の様子 <a href="https://t.co/JmNUWslcm8">pic.twitter.com/JmNUWslcm8</a></p>&mdash; ud (@youdie) <a href="https://twitter.com/youdie/status/1005360122900594688?ref_src=twsrc%5Etfw">2018年6月9日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

**うーん超可愛い。**

## おしまいに

そんなわけでobnizの存在を知ってから**わずか4日**でここまで工作できました。

繰り返しになりますが自分は電子工作に関しては**超ド素人。**
それでもobnizなら、JavaScriptが使えればちょっとしたアイディアがすぐに実現できます。

しかも一番うれしいのが**公式ドキュメントがめちゃくちゃ充実してるんですよね。**
これが本当に助かる。

そもそものインターフェースもシンプルってのはあるんですけど、ドキュメントがちゃんとしてるってだけでかなり実装のハードルが下がりますね。

とりあえずはパッと思いついたものがとても簡単に作れて満足しましたが、またアイディアが浮かんだらなんか作ってみようと思います。

最後に今回参考にした記事を。

* [スマホを最高級電子部品として電子工作に組み込む（カメラ編）](https://qiita.com/wicket/items/a45cf72e64fc346f4fe2)
* [スマホを最高級電子部品として電子工作に組み込む(加速度編)](https://qiita.com/wicket/items/3c121e45f1d432c368a8)