来年のETロボコンにmrubyで参加しようと思ってるひとへ(2017年版)

# はじめに

同じタイトルで記事を書き始めて4度目になりました。
これを書くにあたって[去年の記事](https://qiita.com/yamanekko/items/b36bdb5cfbf85f8a4488)を読み返してみました。mrubyの開発環境的には、少しずつではありますが整備されてきつつありますね。

今年のmruby参加チームはおそらく去年と同じ3チーム[^fn1]だったようですが、去年のようにチームへのインタビューができていないので、mruby教材を作成するにあたって得た、mrubyに関する情報を中心に書くことにしました。
ETロボコンに限らず汎用的に使える内容を中心にしましたので、ETロボコン参加者以外のmrubyユーザーさんにも参考にしていただけると幸いです。

## mruby教材はmruby on EV3RT+TECS

mruby版で提供しているコードはmruby on EV3RT+TECSを使用しています。教材の著作権の関係もあってコードを公開することはできませんが、[yamanekko版](https://github.com/yamanekko/mruby-ev3rt)で動作確認後、mruby on EV3RT+TECSに移植するという手順を踏んだので、教材のコードはyamanekko版でも動作します。


## mruby on EV3RT+TECS

春にmruby1.3が出るという噂もあったので、TOPPERS側でも対応する準備はしていたのですが、mrubyのリリースが遅れたため、現時点ではmruby1.2を使用しています。
EV3RTも最新版にアップデートされましたが、mruby on EV3RT+TECS用に作り込んでいる部分の影響でEV3RTの機能の一部[^fn5]は使うことができていません。こちらは対応をお願いしてはいるのですが、大工事になるようでなかなか…。

### カーネルドメインで動作

mruby on EV3RT+TECS はかなり初期のEV3RTを使用して作られている関係上、カーネルドメインでのみ動作します[^fn6]。私はここで保護ドメインの有り難さを実感することになったのですが、アクセス違反があると当然ですが突然落ちます[^fn7]。デバッグがとても辛いです。ということもあって、ユーザードメインでも使用できるように対応をお願いしてはいます。

### 複数タスク対応
実は今まで対応されてなかったんですね。教材作成にあたり必要だったので実装していただきました。
1つの.cdlファイル内にタスクの設定を使用するタスクの数分書くことになります。
詳しくは教材のコードを参照してください。参加者以外の方は、mruby on EV3RT+TECSにもサンプルが同梱されているので、そちらをご覧ください。

（倒立制御のようなシビアなものは現時点では単一タスクverの方が安定するようです。）

### Windowsがおすすめ
開発者がWindowsなので、ツール周りがWindowsから使いやすいようにつくられています。（使い方がWindows向けにカスタマイズされてる傾向）

### スタックサイズ
これはEV3RTの制限事項ですが[^fn2]、
ローカルの.hでなくEV3RTの場合は `hrp2/target/ev3_gcc/ev3.h` 
mruby on EV3RT+TECS の場合は　`hr-tecs/target/ev3_gcc/ev3.h`　
にある #define STACK_SIZE の値を変更する必要があります。

```
/*
 *  タスクのスタックサイズ
 */
#ifndef STACK_SIZE
#define STACK_SIZE  4096 <-ここ
#endif
```

各アプリケーション毎に作成される app.h の中にも同じ#defineがありますが、こちらを変更しても反映されませんので注意してください。[^fn3]

ちなみに、スタックが足らなくなったら突然落ちます。それらしきバグが見当たらないのに何故か落ちる現象で困ったら、スタックサイズを疑ってみるのもよいでしょう。その場合もくれぐれも増やす場所を間違えないように:sweat:

### ヒープだけでなくスタックもたくさん使う!?

mrubyでは一般的にはヒープの大きさに注意とよく言われますが、TOPPERS上で動かす場合はTOPPERSのタスクのスタックの大きさにも注意しましょう。
計測をしたわけではないのですが、教材のようにオブジェクトをたくさん作るとタスクのスタックも増やす必要が出てくるケースもあります。

あくまで個人的な感覚的な見解ですが、処理速度、スタックの使用量からするとmrbgemsをCで作り込むのが良いのではないかなあという感じです。[^fn4]


## randomクラス

[randomクラス](https://github.com/yamanekko/mruby-ev3rt/blob/master/src/ev3_random.c)は教材で使用しているC++のrandom相当のものが必要だったため作成したものです。（教材にも同じものが同梱されています）

### mrubyの変更に伴う注意

2017/07/27 のコミットでrandomクラス内で使用している[RArray周りが修正](https://github.com/mruby/mruby/commit/f26d00d9e81b102fababdd9c0d1b886fab30e35a#diff-263d1900a03e02b7e5cd6d727b254e69)されています。
この影響でそれ以降のmrubyでビルドするとエラーになります。(2017/12/23時点)
[mruby1.3のリリースは2017/07/04](https://github.com/mruby/mruby/releases)なので、mruby 1.3にバージョンアップしても影響はありませんが、[Githubのmruby](https://github.com/mruby/mruby)をご自身でビルドして利用されている方は注意が必要です。
[mrubyのrandom.c相当の修正](https://github.com/mruby/mruby/commit/f26d00d9e81b102fababdd9c0d1b886fab30e35a#diff-772f71f0a9ac7f25c9f8ff2fde7a7612)をすると動くはずなので春までには修正しておきます。

### randomクラスを作った理由

ここまで読んでなぜmrubyのrandomクラスを使用しないの？と思いましたよね。
こちらは内部でtime関数を使用しており、その中からgettimeofday関数を呼んでいますが、EV3RT(HRP2)にはgettimeofdayの実装がありません。
そこで[高田先生のTOPPERS USERS MLでの投稿](http://www.toppers.jp/TOPPERS-USERS-mailman/2012-June/003812.html)を参考にしてget_utmを使用するようにしました。
今回は日付が欲しいわけではなく、単に時間の計測をしたいだけだったので必要なところだけ実装したこともあり、別のクラスとして作成しています。

## 来年度に向けて
### 更新どうするか問題

走行体の変更に伴い、教材も新しい走行体verになることでしょう。
正直なところ、かなりの工数がかかる割には利用者がいないのでmruby版も作成するかどうかは悩ましいところです。もし、来年度は使おうと思っていたというチームがあれば、お知らせいただけるとモチベーションになります！

### テストご協力のお願い

デカタイヤの走行体をお持ちの方でmrubyの動作確認してあげるよーという方がいらしたらお声がけいただけると有難いです。



[^fn1]: もし他にmrubyで参加していたチームがあれば教えてください！
[^fn2]: C/C++で使用する分にはスタックを増やす必要はないので話題になっていないですが
[^fn3]: この罠には随分悩まされました。当然ですが、いくらスタック増やしても改善されないので・・・
[^fn4]: 最初からずっと言ってることですが、経験による裏付けがされていってる感じです
[^fn5]: File I/Oが必要なところ
[^fn6]: mruby on EV3RT+TECSに依存する制約で他の実装は異なります
[^fn7]: ユーザードメインで動作している場合はそのアプリが終了されるだけでOSや他のユーザードメインで動作しているものは生きています