多脚戦車に乗ろう

# 0. 序

こんにちは Bugfire です。
2019年の10月からクラウドワークスにジョインいたしました。
最近は TypeScript が好きです。

[クラウドワークス Advent Calendar 2019](https://qiita.com/advent-calendar/2019/crowdworks) の7日目になりました。
さっそくですが普段の仕事内容と全く関係ない記事を書きたいと思います！

---

クラウドワークスはとても良い会社で、エンジニアはフルリモートで仕事をすることが可能になっています。リモート参加者がいる場合のミーティングは Google Hangout Meet や Zoom などを組み合わせて行われます。

しかし、やっぱり没入感が足りない...、全員が VR でのミーティングがベストだと思いますが、その時代はまだ少し先のようです。

ならば、没入感を高めるために、自分だけ VR の世界から現実のミーティングに参加すればいいじゃないですか！

**ポイント**

* 仮の体として動かすことができる
* 広い視界を高速なレスポンスで閲覧できる

*理想はそうですが、現在はそのような段階では全然ありません、ゴールまでは遠いです。*

# 1. フォロ

## [6脚歩行ロボット「フォロ」](https://www.elekit.co.jp/product/MR-9107)

6脚ってだけでゾクゾクしますね！
子供用のおもちゃですが、動作確認が大事です。まずは、説明書通りにまず組み立てましょう！
組み上がると、とてもかわいいです❤️
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180344/4ef4b31c-48bb-7adb-752c-1e918393a29d.jpeg">
これが私たちの **新しい体💪** です。

# 2. Raspberry Pi Zero WH

## [Raspberry Pi Zero WH](https://www.switch-science.com/catalog/3646/)

小さいけれど高性能なコンピュータです。
型番なんですが、**W** が Wifi あり、**WH** がそれに加えて今回必要なピンヘッダありです。

自分は、秋葉原の[ツクモロボット王国](https://robot.tsukumo.co.jp/)で **WH** が売り切れていたので、**W** と [GPIO Hammer Header](https://www.switch-science.com/catalog/3189/)を購入しました。半田付けがいらないかわりにハンマーで押し込むのですが、全然入っていかないので、すごい怖かった。**WH** をおすすめ。

これが私たちの **新しい脳🧠** です。

## OSのインストール

[Raspberry Pi Zero(W, WH)のセットアップ](https://qiita.com/hishi/items/8bdfd9d72fa8fe2e7573) が親切かな、と思います。

自分は Raspbian Buster Lite をインストールしました。不親切な mac 用メモを残します。Wifi 経由で ssh ができるようになっていること、Camera, SPI, I2C あたりを有効にしましょう。

<details><summary>Raspbian インストールメモ</summary><div>

```shell-session
# MicroSD device の特定
mac $ diskutil list
# OS Download 適宜最新版に読み替える
mac$ wget http://ftp.jaist.ac.jp/pub/raspberrypi/raspbian_lite/images/raspbian_lite-2019-09-30/2019-09-26-raspbian-buster-lite.zip
# 展開。2.2G ほどになるので注意
mac$ unzip 2019-09-26-raspbian-buster-lite.zip
# MicroSD に書き込み、それなりに時間がかかります。CTRL+T で途中経過を見ることができます
mac$ sudo dd if=2019-09-26-raspbian-buster-lite.img of=/dev/rdiskXXXX bs=1m 
# 終われば勝手に /Volume/boot にマウントされるはず、だめなら抜き差しする。
# ssh 可能にする。
mac$ touch /Volume/boot/ssh
# Wifi 設定を行う。生で記述が嫌ならハッシュ化する
mac$ cat > /Volumes/boot/wpa_supplicant.conf
country=JP
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
    ssid="XXX"
    psk="XXX"
}
```

これで ssh 可能な OS は作成できたのでラズパイに差して起動した後はログインして設定します。mDNS が設定されているので、`raspberrypi.local` でログイン可能です。

デフォルトで、ユーザ名は `pi`、 パスワードは`raspberry` です。変更しておきましょう。

```shell-session
mac$ ssh pi@raspberrypi.local
# パスワード変更
pi$ passwd
# ホスト名変更
pi$ vi /etc/hostname
pi$ vi /etc/hosts
# パッケージのアップデート
pi$ sudo apt-get update
pi$ sudo apt-get upgrade
pi$ sudo apt-get dist-upgrade
pi$ sudo apt-get install -y rpi-update
# Intefacing Options から Camera, SPI, I2C を enable する
pi$ sudo raspi-config
```

</div></details>

# 3. モータードライバー

さて、フォロくんを自由に動かすためには、ラズパイからコントロールする必要がありますね。

便利なデバイスが売っているので買って繋ぎましょう。接続方法は

* 物理 - 色々なコネクタ、ジャンパピン、Groove 等
* 電気的/プロトコル - PWM、I2C 等

が使われているようです。私はホビー用途では有名らしい Groove+I2C のデバイスを購入することにしました。以下すべて、私は [SWITCH SCIENCE様](https://www.switch-science.com/) から購入しました。

## [ReSpeaker 2-Mics Pi HAT](http://wiki.seeedstudio.com/ReSpeaker_2_Mics_Pi_HAT/)

モータードライバーとは直接関係ないのですが、

 - OnBoard Mic
 - Speaker Out
 - 1 Button (GPIO)
 - 3 LED (SPI)
 - GROVE コネクタの I2C, GPIO

上のようなてんこもりのインターエフィスを増やすことができるので、こいつを購入しました。mic/speaker を USB にする等であれば、直接 I2C で繋ぐのも良いと思います。

未来の **私たちの口👄や耳👂** になってくれる...はずです

## [GROVE I2C ミニモータードライバ](https://www.seeedstudio.com/Grove-I2C-Mini-Motor-Driver.html)

こちらは、GROVE I2C からコントロールできる DRV8830 が2個搭載されており、二つのモーターを駆動できます。GROVEケーブルが付属します(別に買ってしまいました)。

状態表示用の LED もあり、とても便利で簡単です。ただしモーター側コネクタが 2mm ピッチです。

## 接続方法

上のモーター用のケーブルですが、最終的には JST PH 2.0 コネクタでフォロくんのモーターと接続する必要があります。

ただし、いきなり切断して圧着なり半田付けするのは少なくとも自分は怖いので、ジャンプワイヤで動作確認をしました。図の一本線の矢印はジャンプワイヤです。

![Diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180344/55946671-d5e7-c88f-1ea3-cef20a67d298.png)

のように接続して試しました。amazon で [HiLetgo 5個セット](https://www.amazon.co.jp/dp/B073ZDYJQQ) を購入しました。

**動作確認後はモーターと[JST PH 2.0 コネクタ](https://www.switch-science.com/catalog/2215/)を直接接続しました。**

## 動作確認

```shell-session
pi$ sudo apt-get install i2c-tools
pi$ i2cdetect -l
i2c-1	i2c       	bcm2835 I2C adapter             	I2C adapter
pi$ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- 1a -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: 60 -- -- -- -- 65 -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
```

モータドライバは I2C のアドレス `0x60`, `0x65` にいらっしゃるようです。データシートと基板上の半田のブリッジ状態を見ると上のアドレスはわかるはずですが、小さすぎてよくわかりませんでした...。

接続が確認できないときは、raspi-config, ケーブルの接続等をチェックしましょう。

# 4. モーターの API コントロール

Raspbian に標準で導入されている python3 で書きました。

## モータドライバ

DRV8830 のコントロールは[マニュアル](http://www.tij.co.jp/document-viewer/jp/DRV8830/datasheet/detailed_description#SLVSAB2736)を見てください、自分はこんなのを書きました。

- [DRV8830.py](https://github.com/Bugfire/webvr_webrtc/blob/master/pi/DRV8830.py)
  DRV8830 操作用ライブラリ
- [motor_api.py](https://github.com/Bugfire/webvr_webrtc/blob/master/pi/motor_api.py)
  上のライブラリを呼び出す単純な Python 製 HTTP API Server

```shell-session
# Motor API サーバーを起動
pi$ ./motor_api.py
```

## 動作確認

```shell-session
# ブラウザか CLI で動作を確認。 
pi or mac$ curl http://raspberrypi.local:5000/cmd/forward
pi or mac$ curl http://raspberrypi.local:5000/cmd/stop
```

このモータードライバーの場合は、2系統の Forward/Backward にそれぞれ LED が定義されているので確認が簡単です。正常に接続されている場合は、対応する LED が発光しつつモーターが駆動します。

# 5. カメラ

HMD をかぶって頭を振っても視野が狭いとがっかりです、没入感を高めるために視野が広いことが重要です。

## [VR 220 カメラ](https://products.entaniya.co.jp/ja/products/raspberry-pi/)

Entaniya さんのカメラ(正確にはラズパイ用の標準カメラの広角アタッチメントです)を使用しました。180度程度の視野角を持つ魚眼レンズであれば何でもいいと思います。カメラと組み立て済みのものを購入すれば安心です。

お分かりだと思いますが、これが私たちの **新しい目👁** です。

## カメラケーブル

ラズパイZeroは通常のラズパイとカメラとの接続ケーブルが異なるため、ケースキットに付属する短いケーブルを使うか、別途ケーブルを購入する必要があります。

このフレキケーブルの表裏って何なの!?って思いながら、[製品ページ](https://www.switch-science.com/catalog/3195/) をみたら二つの写真で裏表が違って混乱が極まりました。正解は...右側です。ケーブルの銀色の端子露出面が基盤のコネクタの上側になるように差します。

## 動作確認

```shell-session
pi$ vcgencmd get_camera
supported=1 detected=1
```

接続が確認できないときは、raspi-config, ケーブルの接続等をチェックしましょう。

# 6. WebRTC

## [WebRTC Native Client Momo](https://github.com/shiguredo/momo)

時雨堂さんの WebRTC を使って動画・音声を気軽に送受信できる OSS です。 
[ドキュメント](https://github.com/shiguredo/momo/blob/develop/doc/USE_RASPBERRY_PI.md)に従えば一瞬で終わります。
素晴らしい OSS をありがとうございます。

```shell-session
pi$ sudo apt-get install libnspr4 libnss3 libsdl2-dev
pi$ sudo modprobe bcm2835-v4l2 max_video_width=2592 max_video_height=1944
./momo --log-level 4 --resolution VGA --port 8000 test
```

## 動作確認

momo を起動した後は、ブラウザから http://raspberrypi.local:8000/html/test.html を開くだけで test(P2P) モードでカメラ画像を見ることができます。
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180344/f8949a64-deb3-79db-9bc6-49f9e3584a94.png">

# 7. WebVR with WebRTC/Motor

ここからは `HTML` と `JavaScript(TypeScript)` の話になります。

* [github: html](https://github.com/Bugfire/webvr_webrtc/tree/master/html)
* [github: html_src](https://github.com/Bugfire/webvr_webrtc/tree/master/html_src)

に今回作成したソースファイルがあります。TypeScript で記述し、Webpacker で bundle.js にまとめています。ビルドされたこれらの html ファイルを momo の html ディレクトリに置くことで momo 側に寄生して配信できます。

## 描画部分

- [github: webvr.ts](https://github.com/Bugfire/webvr_webrtc/blob/master/html_src/webvr.ts) の setVideo()  
  あたりを参照してください。[three.js](https://threejs.org/) いいですね、簡単に VR で描画できます。
  半球を作成し、テクスチャとして WebRTC の VideoTexture を貼り付けています。LAN (VPN) での使用を想定しているため、momo のTestモードを使用しています。

## コントローラ部分・初期化部分

以下のファイルにボタンの表示と処理があります。  

- [github: html/index.html](https://github.com/Bugfire/webvr_webrtc/blob/master/html/index.html)
- [github: html_src/main.ts](https://github.com/Bugfire/webvr_webrtc/blob/master/html_src/main.ts) 

処理内容は以下の通り

- 操作ボタン入力に対し **4. モーターの API コントロール**で作成したAPIを呼び出す
- WebVR が利用できるなら、WebVR モードに移行するボタンを設置  
  Oculus Quest や chrome で WebVR を on にする (`chrome://flags` で「WebVR」を検索) ことで利用ができます。これらのデバイスでは mDNS が使えなかったので、IP 直接が良いです。  
  **ただし現在はまだ WebVR ではモーターをコントロールできません**
- 非VRモードではドラッグにより視点変更、VRモードではHMDの動きに視点が追従します。


## 設定ファイル

html 以下に config.js ファイルを設置します。

[サンプル github: config.js.sample](https://github.com/Bugfire/webvr_webrtc/blob/master/html/config.js.sample)

カメラのキャリブレーションを自動 or 画面上でできると素晴らしいですが、現在は手で設定してください！  

<details><summary>自分の例</summary><div>

なお、自分のカメラはVGA時220度かつ、やや左に寄っているので、

```js
    "xscale": 0.95 * (480.0 / 640),
    "yscale": 0.95,
    "xofs": -0.04,
    "yofs": 0,
```

これくらいにしてあります。[9. おまけ](#9. おまけ)の正方形化を行った場合は、`"xscale": 0.95`にします。

</div>

# 8. 完成・終わりに

上のパーツにモバイルバッテリーを加えて、新しい頭としてとりつけましょう。結束バンドと両面テープで生きていけます。
<img width="320" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180344/564f3348-c908-821c-0dad-d4708b4af00a.jpeg">
自己責任ですが、HAT 側にのみ給電しても動作しています。

これが新しい **自分🤖** です。

今回の生成物は義体としてはまだまだですが、組み上げたものが動くのは電子部品でもソフトウェアでも楽しいですよね！

---

音声周り等、VRモードでの操作など未完成の部分があるので随時更新していきたいと思っています。

しかし。ありものの物理・ソフトウェア部品を接続するだけで、これだけ楽しめるなんていい時代です。構成のリッチになった Raspberry Pi 4B や、豊富なデバイスを組み合わせることの妄想が広がります。


動画はこちら

スマホ版の操作等、最初の版
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">WebVR+WebRtc(時雨堂さんのOSS momo)の進捗。Raspberry Pi Zero Wで動画をWifiで飛ばして0.31A, さらにモータ一個回して0.41A <a href="https://t.co/p9n1zmtpBC">pic.twitter.com/p9n1zmtpBC</a></p>&mdash; Bugfire (@andobario) <a href="https://twitter.com/andobario/status/1199355069289746433?ref_src=twsrc%5Etfw">2019年11月26日</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/O5acI1LT7w">pic.twitter.com/O5acI1LT7w</a></p>&mdash; Bugfire (@andobario) <a href="https://twitter.com/andobario/status/1199360476716519424?ref_src=twsrc%5Etfw">2019年11月26日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


# 9. おまけ

時雨堂さんの [momo](https://github.com/shiguredo/momo) はソースが公開されているので、好きなように手を入れて使いましょう。
自分は [fork](https://github.com/Bugfire/momo) して、

* SDL を外す (現在は使用していないので。ただし音声出力する時は戻す)
* 任意の解像度指定対応 ([Qiita: momoで任意のビデオ解像度を指定可能にする修正](https://qiita.com/tetsu_koba/items/3ba913e35e9c4ec2aa7f))
* MMAL のログ出力を減らす

など少しだけ手を入れています。