ETロボコン開発をクラウドサーバーで支えるお話

前説
=====
@beakmark さんの[前記事](http://qiita.com/beakmark/items/4ab20a54a954e28548e9)を受けて、ETロボコンの開発プロジェクトにクラウドサーバー環境を提供したお話をさせていただきます。

うちの会社の参加形態などは前の記事を参照していただきたいのですが、若手の研修を兼ねたヤングチームと、熟練者が任意参加する部活動であるシニアチームの2つに分かれています。
この内シニアチームは本当に自由気ままにやっている(前向きな表現)ので開発環境やプロセスも毎回自由に選択することができます。これはエンジニアとしては色々新しい事を試すチャンスでもありまして、普段業務では取り入れる事が難しい「趣味に走った」実験的な開発環境や手法を試せる絶好の機会となります。
クラウド開発環境を提供することは ETロボコンの開発そのものではないのですが欄外として書いてみようと思います。

解決したい問題
=====
そもそもでクラウドに力を入れる様になったきっかけとしては、色々とチームの形態に問題があったところがあります。

他の所はどうだかわかりませんが、うちの会社の場合勤務先のオフィスが何カ所かにあり ETロボコンに参加しているメンバー全員が同じ場所にいないという状況がありました。また、ロボコン用に作業場所を用意してもらったのですが、そこに集まるということは普段の勤務先から移動しなければならないという人が結構いることになります。
その状況ではロボコン部屋に移動したときに、普段の主力作業PCが手元に無いという場面が多々ありました。自分のPCでなくても任意のPCでロボコン開発ができればきっと捗るに違いありません。

そういった場所とマシンの問題を解決するスマートな手法としてサーバーサイドに開発環境をおいて任意のPCからネットワーク経由で利用する、いわゆるクラウドが有効なのではないかと考えたわけです。

クラウドを利用した開発へのチャレンジ
=====
実際にクラウドで導入したあれこれです。

## 開発環境を Docker container で提供
普段業務で使っている Windows や MacOS のマシンにクロスコンパイル環境を構築するのは結構な作業となります。じゃあ Linux なら楽かというとそう簡単にもいかず、色々な物をインストールし環境変数を設定しなくてはいけない煩わしさがあります。
そんな状況故、予め環境構築済みの仮想環境を作ってみんなでそれを利用すれば即座にロボコン開発に入れるのではないかと考えたわけです。ちょうど Docker container がそのパッケージングに最適だったため採用してみました。
container の具体的な作りかたについては後述。

## WEB IDE でどこでも開発
上記でクロスコンパイル環境を含んだ Docker container ができたのですが、さらにそこに WEB ブラウザで利用できるブラウザIDE ["Codiad"](http://codiad.com/) と http server 環境を加えた container を作成しました。
この container を起動すると WEBサーバーになり、そこにブラウザでアクセスすると IDE が表示されます。
![ide.png](https://qiita-image-store.s3.amazonaws.com/0/50737/79ff1152-f218-0051-fa57-8b6f144ce1cd.png)

このIDE の上でソースコードの編集ができることはもちろんですが、クロスコンパイル環境を含んでいるのでブラウザの中でビルドしバイナリイメージを生成するところまでブラウザで完結させることができました。後はWEBブラウザと社内ネットに繋がっているPCがあればどこでも開発ができます。
![container.png](https://qiita-image-store.s3.amazonaws.com/0/50737/b1a08af4-6368-221d-19f3-9f2b30f4b1eb.png)

このcontainerを TCP port 番号を変えながら利用する人数分起動し、各人に1つクラウドIDEと仮想ビルド環境を割り当てます。実際には16個ほどのcontainerを起動していました。

2015年は社内のGitサーバーを使っていた事もあり、WEB IDE も社内ネットワークに置いてありました。シニアチームは部活的な活動ということもあり勤務時間外でも開発がしたいという要求はあったのですが、自宅からのアクセスは通常できないため今ひとつ振るわないところがありました。
これを受けて2016年は Git 共々外部にクラウドサービスを用意しています。WEB IDE 等の開発クラウド環境は Azure を利用しました。
この改善は試走会時特に有効で、ネットワーク回線があれば WEB IDE が利用できましたし、試走会会場にいないメンバーがコード編集、提供をするといった状況を作り出していました。

## ロボットへの転送一歩手前まで
クラウド上の WEB IDE で開発＆ビルドまでできるようになったのは良いのですが、できあがったバイナリをロボットにダウンロードするためにはクラウドから手元のマシンに持ってきて、さらにBluetoothなりSDカードなりでロボット本体に持っていく手順が発生します。
このビルド後 Bluetooth 転送用PCにダウンロードする部分をなんとか自動化できないものでしょうか。

ちょっと大仰ですが以下の様なシステムを構築しました。
![downloader.png](https://qiita-image-store.s3.amazonaws.com/0/50737/91bb4b8f-3118-96c8-38d4-3a71b69617d0.png)

IDE 上の Makefile(実際にはRakefileを使用)でビルドが成功したら、できあがったバイナリファイル名を slack に「ダウンロードしてね」と投稿させるようにしました。
Bluetooth転送用PCでは slack bot が channel を見張っており、ダウンロード要求があったらその要求に従って自動的にダウンロードします。

これだけのものですが、IDEから手を離すことなく転送手前まで持って行けるので開発効率は格段に向上しました。

本当は Bluetooth 経由で ZModem 転送する部分も自動化させようとしていたのですが、ちょっとうまくいかなくて諦めてしまいました。ラストワンインチ問題です。

なんで slack を介したのかというと、chat ops と言う奴を実践してみたかったからです。2016年度の目標は「誰でも chat bot を提供できるクラウド環境の構築」だったのですが、これは割りとうまくいってたくさんのbotが作られました。

## chat ops が流行なので
chat ops という言葉がありますが、実際にどういったことをさせると有用なのか今ひとつわかりません。そこで Dockerベースのクラウド環境を提供し、メンバーの誰でもbotを作成できる素地を提供しました。
これのおかげで色々なbotが開発と遊びの両方で生み出されていきます。

ここでは一部の機能紹介までに

- 試走会、大会までの日数を表示するbot(超不評でした)
- slack 上から gitlab の issue が登録できる bot (slackで相談しながらissueの追加が可能)
- gitlab の issue で残っているものを毎朝リスト表示するbot
- 現在のリポジトリに ruby-lint をかけてレビューしてくれるbot
- gitlab の commit 回数をカウントして1日のcommit数が多いメンバーを褒めてくれるbot
- ロボコン部屋の輝度センサー値を通知して誰かいるか教えてくれるbot
- そして先のダウンロードbot(これも誰が作業中かを可視化してくれる)

などなど。

これ以外にも会話等お遊びbotも多くいましたが、それらも含めてロボコン開発を支える存在として可愛がられていました。

## 実機なしでどこまで開発が進められるか
これは直接的なクラウドではないのですが、部分的にクラスをシミュレートしてソースコードから大雑把な挙動を見れないかと挑戦していました。
場所を選ばずに開発ができるようになったその次のターゲットはロボット実機がなくても開発ができる環境というわけです。

モータークラスと光センサークラスの同名クラスを作り、モーターのPWM値から時間当たりの回転数と自己位置推定式から現在の位置をプロットします。
![output.png](https://qiita-image-store.s3.amazonaws.com/0/50737/f16cc2f3-0fe5-446b-fa83-adf544ab358e.png)

これが結構それっぽい結果を出してくれたため、初期のライントレース調整やショートカットの実装などに効力を発揮しました。ブロックやソナー、土俵(板)などはシミュレートしていませんのでできることは限定されていますが、初期の開発立ち上げ次期には効果がありそうです。

これによって実機が無くても、離れたオフィスに居るメンバーでもクラウド環境のみで開発に参加でき、走行部分の動作確認ができるわけです。
参加への敷居を下げることでもっと多くのメンバーがETロボコンに参加してくれると良いなあと思っています。

Docker container の構築手順
=====
実際にクロスコンパイル環境を Docker 上に構築する Dockerfile を記載します。

EV3 の c++ で開発していたのは2015年度ですので、使用しているEV3RTはβ５版となります。2016年度のβ６版では workspace ディレクトリの位置と make の指示子が異なります。必要に応じて読み換えてください。

```Dockerfile:Dockerfile
FROM debian:jessie

RUN echo 'deb http://ftp.jp.debian.org/debian/ jessie main' > /etc/apt/sources.list
RUN echo 'deb http://security.debian.org/ jessie/updates main' >> /etc/apt/sources.list

ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update; \
    apt-get -y upgrade; \
    apt-get -y dist-upgrade; \
    apt-get -y install gcc g++ make ruby rake; \
    apt-get -y install gcc-arm-none-eabi u-boot-tools libboost-all-dev; \
    apt-get clean; \
    rm -rf /var/lib/apt/lists/*

RUN useradd robodev -s /bin/bash
RUN mkdir -p /home/robodev
RUN chown -R robodev.robodev /home/robodev

ADD hrp2.tar.xz /home/robodev/
RUN chown -R robodev.robodev /home/robodev/hrp2
RUN su - robodev -c "cd /home/robodev/hrp2/cfg; make"

ADD devenv /home/robodev/
ADD ev3-build /usr/local/bin/
run chmod 755 /usr/local/bin/ev3-build
RUN mkdir /ev3src
RUN mkdir /ev3image
RUN chmod 777 /ev3image
ADD auto-build /root/
RUN chmod 755 /root/auto-build

CMD ["/bin/bash", "-c", "/root/auto-build"]
```

以下は Dockerfile がコンテナ内に仕込むシェルスクリプトです、これらと EV3RT の hrp2.tar.xz を Dockerfile と同じ場所に置いてください。

```bash:devenv
HRP2PATH=/home/robodev/hrp2/
OUTPUTPATH=/ev3image
if [[ ! -v BUILDFORMAT ]]; then
  BUILDFORMAT=app
fi
```
```bash:auto-build
#!/bin/sh
su robodev -c "cd /ev3src; ev3-build"
```
```bash:ev3-build
#!/bin/bash -e

source ${HOME}/devenv
HERE=`pwd`
PROJECTNAME=`basename ${HERE}`
BUILDTIME=`date +%Y%m%d%H%M`

ARTIFACTNAME=uImage
if [ ${BUILDFORMAT} = 'mod' ]; then
  ARTIFACTNAME=app
fi

cp -a ${HERE} ${HRP2PATH}/workspace/${PROJECTNAME}

pushd ${HRP2PATH}/workspace/
make ${BUILDFORMAT}=${PROJECTNAME}
if [ -f ${ARTIFACTNAME} ]; then
  cp ${ARTIFACTNAME} ${OUTPUTPATH}/${ARTIFACTNAME}_${BUILDTIME}
fi
make realclean
rm -rf ${PROJECTNAME}
popd
```

hrp2 開発環境とプロジェクトは workspace ディレクトリ(β6では sdk/workspace/)の下で make を実行する事を期待しています。ev3-build は現在のディレクトリをプロジェクトとして、workspace 下にコピー、そこでビルドして完成した uImage を /ev3image に渡します。
この Docker container ではビルドするプロジェクトは /ev3src にあることを期待します。

Docker container 実行時、このコンテナ内の /ev3src, /ev3image にホストのディレクトリをボリュームマウントしてやるとビルドができる事になります。
いま、`/home/you/dev/ev3develop/` で開発していて、バイナリを `/home/you/dev/image/` に出力したい場合、上記コンテナ名が devcontainer だった場合

```
docker run -t --rm -v /home/you/dev/ev3develop:/ev3src -v /home/you/dev/image:/ev3image devcontainer
```

とすることでビルドが完了します。

おわりに
=====
ETロボコンと言えば組み込み開発とモデリングなためサーバーサイドエンジニアリングは遠い世界のものと思われるかもしれませんが、直接的ではなくても間接的に開発プロジェクトを支えてくれるものになり得ます。

クラウドを使ったら環境がどう変わるのか。変わった環境ではロボコン開発がより楽しいものになるのか。その答えはまだ見えていませんが、ETロボコンを通じて色々試す良い機会を与えて貰っています。