USBメモリにESP32向けの軽量Ruby(mruby/c)環境を構築してみた

# はじめに

本記事は、USBメモリにUbuntuを入れて、そこでESP32向けの軽量Ruby環境を構築した際の記録です。  

# 特徴  
今回構築した環境の特徴は以下の通りです。  
  
### メリット
 * USBメモリ上が主戦場となるので、失敗しても軽傷で済む
 * PCにrubyやpythonといった必要なものを色々インストールしなくても良い
 * Arduinoやwindowsのmsys環境と比較して、体感的にビルド＆プログラム書き込みする時間が短い
 * rubyの恩恵に授かることができる（配列の操作や数学関数など）
 * 並列処理をコーディングしやすく、メモリ消費量が少ない※

※今回用いたmruby/cという開発言語の特徴です。(mrubyの実装)
　詳しくは、[こちら](https://www.s-itoc.jp/activity/research/mrubyc/)や[こちら](https://magazine.rubyist.net/articles/0059/0059-original_mrubyc_iot_device.html)をご覧いただけると大変参考になります。
### デメリット
 * Ubuntuのハードディスク容量が限られている（後述するUNetbootinの制約）  

# サンプルプログラム

この手順では、最終的に以下の図のようにサンプルプログラムを動作させています。
operator1, operator2のスレッド(緑色の四角)から一定時間おきにprinterクラス(青色の四角)のPrintメソッドを実行して標準出力(puts)します。    
図：サンプルプログラムの動作
![図_サンプルプログラム2_half.png](https://qiita-image-store.s3.amazonaws.com/0/155449/a45244ed-0e12-d212-61ae-14d91e763008.png)


# 手順  

それでは実際に行った手順です。
※トライする方は自己責任でお願いします  
			
### 使用したもの

* [ESPr Developer 32](https://www.switch-science.com/catalog/3210/)（下記の手順では「ESP32」と表記しています）
* PC (USBメモリとESP32接続のためにUSBポートが2つ必要です)  
　※OS、スペックは下記の通り  
　　  OS：Windows7 Pro 64bit  
　　  RAM：8GB  
　　  CPU：Intel Core i5-3340M  
　　  SSD：500GB  
* USBケーブル(PCとESP32を接続します)
* [USBメモリ](https://www.amazon.co.jp/%E3%80%90Amazon-co-jp%E9%99%90%E5%AE%9A%E3%80%91-Transcend-USB%E3%83%A1%E3%83%A2%E3%83%AA-%E3%82%AD%E3%83%A3%E3%83%83%E3%83%97%E5%BC%8F-TS32GJF700E/dp/B007ACYRM8)  

### 手順１：USBメモリにUbuntuをインストールする

１. [Ubuntu 18.04 LTS 日本語 Remix(64bit)](https://www.ubuntulinux.jp/News/ubuntu1804-ja-remix)をダウンロードする
２. UNetbootinを使用してUSBメモリにUbuntuをインストールする　  
UNetbootinの入力内容（※使用したUNetbootinのバージョンは6.61です）：
![UNetbootin_windows661.png](https://qiita-image-store.s3.amazonaws.com/0/155449/8cf999ed-13d8-98f8-0f20-73120aff50e2.png)

３. パソコンを再起動してBIOSメニューでUSBブートを先頭にした後、USBメモリを接続して再起動する  
４. Ubuntuの起動後、基本的な環境設定を行う(Wi-Fi、キーボードレイアウト、タイムゾーン設定)
※[キーボードレイアウト設定の参考記事](http://takafumi-s.hatenablog.com/entry/2014/09/29/141140)
※[タイムゾーン設定の参考記事](https://qiita.com/zaki-lknr/items/cd9844fa6a1efa58cab1)  

### 手順２：mrubyをインストールする  
Ubuntuのターミナル上で以下の順でコマンドを実行します
　
１. gitをインストールする

```
sudo apt-get update  
sudo apt install git  
```
２. pyhon関連を入れる  

```
sudo apt install gcc git wget make libncurses-dev flex bison \
gperf python python-pip python-setuptools python-serial \
python-cryptography python-future python-pyparsing
```
３. esp32のlinux開発環境をインストールする  

```
mkdir $HOME/esp  
cd $HOME/esp  
wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz  
tar -xzf xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz  
rm xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0.tar.gz  
echo 'export PATH="$HOME/esp/xtensa-esp32-elf/bin:$PATH"' >> $HOME/.profile  
echo 'export IDF_PATH="$HOME/esp/esp-idf"' >> $HOME/.profile  
source $HOME/.profile  
cd $HOME/esp  
git clone --recursive https://github.com/espressif/esp-idf.git  
```
４. python製の関連ツールをインストールします。  

```
python -m pip install --user -r $IDF_PATH/requirements.txt  
```
５. 自ユーザをdialoutグループに追加する(USBシリアルポートの権限のため)  

```
sudo usermod -a -G dialout $USER  
```
６. mrubyをインストールする  

```
cd $HOME  
git clone https://github.com/rbenv/rbenv.git $HOME/.rbenv  
echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> $HOME/.profile  
echo 'eval "$(rbenv init -)"' >> $HOME/.profile  
source .profile  
mkdir -p "$(rbenv root)"/plugins  
git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)"/plugins/ruby-build  
sudo apt-get install -y libssl-dev libreadline-dev zlib1g-dev  
rbenv install 2.6.1  
rbenv global 2.6.1  
ruby --version  
rbenv install mruby-1.4.1  
```

### 手順３：プロジェクトを作成する

１. サンプルソースファイル一式をクローンする  

```
　git clone --recursive https://github.com/bigw00d/mrubyc-esp32-threadsample.git  
```
２. プロジェクトを作成する  

```
　cd mrubyc-esp32-threadsample  
　chmod +x ./newproject.sh  
　./newproject.sh thread-sample  
```
  ※「thread-sample」はプロジェクト名です(好きな名前を付けてよい)

プロジェクト作成後のプロジェクトファイル一式は以下の通りです。

図：プロジェクトファイル一式
![projects.png](https://qiita-image-store.s3.amazonaws.com/0/155449/8ed906dc-3228-129f-2505-ac4ba20db078.png)



### 手順４：実機にサンプルプログラムを書き込んでモニターする
１. makeする  

```
　make  
```
  ※初回の実行時に設定画面が出てくるが、設定はそのままで良いはずなので、「Exit」を選択してその画面を抜ければよいです
      （それ以降でCOMポート等のコンフィグを変更したい場合は「make menuconfig」を実行する)  
２. ESP32にプログラムを書き込む   

```
　make flash  
```
  ※エラーになる場合はESP32を抜き差ししてみるとよい  
３. プログラムの動作状況をモニターする  

```
　make monitor  
```
  ※終了する際は「Ctrl+]」を入力する  
画像：モニターの様子(各スレッドからputsした文字列がterminalに表示される※)
![monitor.png](https://qiita-image-store.s3.amazonaws.com/0/155449/1a38fbbe-935d-32ca-633f-965232c3795b.png)
※それぞれのスレッドでputsしている文字列：
　operator1：「Hello!」(1秒間隔)
　operator2：「Bye!」(2秒間隔)

# 終わりに

mrubyのインストールの辺りは結構時間がかかりますが、一度環境が出来てしまうとサクッとmake＆書き込みができて使いやすく感じました。

ESP32の真骨頂といえばWi-FiやBluetoothなので、その辺りをどうrubyで実現できるかを今後色々試してみようと思います。

見ていただいてありがとうございました。
тнайк чoμ_〆(・ω・｡)			
			
# 参考記事

hitoshi HASUMIさんのgithubページ
https://github.com/hasumikin?tab=repositories

本家mruby/cのgithubページ
https://github.com/mrubyc/mrubyc

# おまけ

### プログラム実行にまつわる話

サンプルプログラムを含めたプロジェクト内の各ファイルの関係は以下の図の通りです。

図：サンプルプログラムの各ファイル間の関係
![図_サンプルプログラム2.png](https://qiita-image-store.s3.amazonaws.com/0/155449/c916e8bc-1b51-d108-5b8e-d5fc043472c2.png)

mruby/cでRubyのバイトコードを実行するVMが提供されており、mainを通してコンパイルしたRubyのバイトコードをVMに渡してRubyのプログラムを実行します。

※自分の理解のためにざっくり作成した図ですので、正確でない部分があるかもしれません。また、クラス図としての形式はあまり気にせずに作成しています。

### プロジェクト作成について

今回はシェルスクリプト(newproject.sh)を用いて、プロジェクト作成と称してmakeに必要な最終調整を行っています。

[シェルスクリプトの処理内容]
・ 指定されたプロジェクト名を使用してトップのMakefileを作成する
・ mrubycにcomponent.mkをコピーする
・ mrubyc内にesp32用のhalをコピーする
　※mrubycは外部リポジトリからcloneするため、mrubyc内への操作もここで行っています

図：シェルスクリプト動作
![script.png](https://qiita-image-store.s3.amazonaws.com/0/155449/7bcbb6fb-abce-b532-d189-592b7f053b3e.png)



### makeの話 

本環境ではESP32のmake環境であるESP-IDFを使用してビルド(make)しています。

そしてESP-IDFは、make時にmainとcomponentsのディレクトリとそのサブディレクトリを見て、そこにcomponent.mkという名前のファイルがあれば、それをmake時に実行します。

今回はそれを利用して、ESP-IDFのmakeと合わせてmruby/cのmakeも行っています。

参考記事：
https://kazkojima.github.io/esp-idf-components.html

### atomのインストール

手順には必要ありませんが、エディタはatomをインストールしました。
(下記の参考記事の通りに取得してdebファイルを右クリックしてインストールしました)  

参考記事：
https://www.leo-leo.uno/2018/08/18/392/  

						
# 更新履歴
* 2019-03-20：細かい説明を「おまけ」に移動＆追記