目的
PlatformIOに自作ライブラリとしてmruby/cを組み込み、マルチタスクを行う。
概要
pio initで生成されたlibフォルダの中でmruby/cをgit cloneすると、PlatformIOでmruby/cが使用できます。
PC環境
- OS: windows 10 1903
- IDE: VS Code, CLion
- PlatformIO: ver4.0.3
- Python: ver3.7.4
- mruby/c: ver1.2
- mruby: 2.0.1
- マイコンボード:HiLetgo ESP32 ESP-32S NodeMCU
PlatformIO,mruby/cはWindows,Linux,Mac対応なので、コードを使いまわせると思います。
mrubyコンパイラのダウンロード(Windowsユーザー向け)
このページのmrubyコンパイラ2.0ダウンロードリンクからコンパイラがダウンロードできます。
PlatformIOについて
複数のOSで動作する、統合開発環境です。
ESP32やPIC32、Arduino unoなど複数のマイコンの開発環境を構築することができます。
詳細は以下のページを見てください。
https://platformio.org/
mruby/cについて
センサーネットワークや、ウェアラブルなどの小型端末向けの開発言語「mruby/c」
mruby/cは、Rubyの特徴を引き継ぎつつ、プログラム実行時に必要なメモリ消費量が従来のmruby(福岡で開発された組込み向けの軽量Ruby)より少ないmrubyの実装です。
国立大学法人九州工業大学(田中和明准教授)と共同で研究開発を行っています。
しまねソフト研究開発センターより引用
実装例は以下の記事が参考になると思います。
https://www.s-itoc.jp/activity/research/mrubyc/mrubyc_tutorial/ESP32/
mruby/c with PlatformIO 環境構築手順(本題)
PlatformIOの初期化
- 作業用フォルダを作成、移動
mkdir your_work_space
cd .\your_work_space
- 作業フォルダ内でPlatformIOで開発環境の設定
cd ..
pio init --ide your_ide_id --board your_board_ide
ここまでで、作業フォルダ直下は以下のようになります。
なお、OS、使用IDEによって追加でフォルダが作成されます。
your_work_space
|- include
|- lib - 個人用のライブラリを入れるフォルダ
|- src - メイン処理を書くフォルダ
|- platformio.ini - ボード、シリアルモニタの速度などの設定
PlatformIOにmruby/cをライブラリとして組み込む
libフォルダの中に個人用のライブラリを入れます。
- libフォルダ内でmrubycのリポジトリをクローン
cd ./lib
git clone https://github.com/mrubyc/mrubyc.git
- mrubyc/srcにあるhal_*ファイルの内、使用するボードに対応するものをhalにリネーム
REN ./lib/mrubyc/src/hal_you_use ./lib/mrubyc/src/hal
- hal_*ファイルを削除
rm ./lib/mrubyc/src/hal_*
- 作業フォルダ内でPlatformIO開発環境の初期化
pio init --ide your_ide_id --board your_board_ide
※注:libディレクトリを編集した後は毎回pio initを行う必要があります。
mruby/cを動かすための処理を作成
#include "Arduino.h"
#include "mrubyc.h"
// 後ほどmrubyのコンパイラでコンパイルした.rbファイルの処理が格納される配列です。
extern const uint8_t task1[];
extern const uint8_t task2[];
// for esp32
#define MEMORY_SIZE (1024*30)
static uint8_t memory_pool[MEMORY_SIZE];
// ruby側で使用したいメソッドを実装します。
// 基本形は以下の通りです。
// 引数を取る場合は第1引数v[1],第2引数v[2]であることに注意してコーディングします。
// 第1引数に整数を使用する場合 int value_name = GET_INT_ARG(1);
// 第2引数に浮動小数を使用する場合 float value_name = GET_FLOAT_ARG(2);
// サンプルです。
void c_sample_method(VM *VM, mrbc_value *v, int arg){
}
void c_Serial_println(VM *VM, mrbc_value *v, int arg){
uint8_t *character_array = GET_STRING_ARG(1);
String str = String((char *)character_array);
Serial.println(str);
}
// 実装したメソッドを登録します。
// 基本形はmrbc_define_method( nullptr, mrbc_class_object, "Rubyで使いたいメソッド名", メソッドの実装);
static void mrbc_define_methods(){
mrbc_define_method( nullptr, mrbc_class_object, "sample_method", c_sample_method);
mrbc_define_method( nullptr, mrbc_class_object, "Serial_print", c_Serial_println);
}
void setup() {
// replace Serial.begin( here! )
// ex) esp32 can use Serial.begin(115200)
Serial.begin(9600);
delay(1000);
// initialize mruby/c
Serial.println("--- begin setup");
mrbc_init(memory_pool, MEMORY_SIZE);
mrbc_define_methods();
// マルチタスクを行いたい場合は以下のように追加してください
// 基本形 mrbc_create_task(5行目あたりで宣言した配列, nullptr);
mrbc_create_task(task1, nullptr);
mrbc_create_task(task2, nullptr);
Serial.println("--- run mruby script");
// mruby/cのVMを動かします
// なお、内部は無限ループとなっているため、これ以降のコードにはたどり着けません。
mrbc_run();
}
void loop() {
// setup()が終わらないためたどり着けない。
}
srcフォルダにRubyファイルを作成
while true
Serial_print("task1")
sleep(1)
end
while true
puts 'task2'
sleep(0.5)
end
Rubyファイルをmrubyでコンパイル
Windowsユーザー向け
以下の手順で、Rubyファイルをコンパイルします。
- mrubyコンパイラのダウンロード(Windowsユーザー向け)で紹介したファイルの中のmrbc.batとmrbc.exeをsrcフォルダに移動
- mrbc.batを実行
task1.rbという名前のファイルがあった場合、task1.cという名前のファイルが生成されます。
生成された.cファイルをmain.cppで読み取れるようにする
- 生成されたtask1.cの中に以下のような配列の宣言があるので、このコードをmain.cppに張り付ける。
/* dumped in big endian order.
use `mrbc -e` option for better performance on little endian CPU. */
#include <stdint.h>
extern const uint8_t task1[]; <-この一文をmain.cppに貼り付け
const uint8_t
(後略)
#include "Arduino.h"
#include "mrubyc.h"
// 後ほどmrubyのコンパイラでコンパイルした.rbファイルの処理が格納される配列です。
extern const uint8_t task1[]; <-ここに貼り付け
extern const uint8_t task2[];
(後略)
- タスクを生成する
以下のようにmrbc_create_task(task1, nullptr)でタスクを追加する。
(前略)
// マルチタスクを行いたい場合は以下のように追加してください
// 基本形 mrbc_create_task(5行目あたりで宣言した配列, nullptr);
mrbc_create_task(task1, nullptr); <-ここでタスクを追加
mrbc_create_task(task2, nullptr);
Serial.println("--- run mruby script");
// mruby/cのVMを動かします
// なお、内部は無限ループとなっているため、これ以降のコードにはたどり着けません。
mrbc_run();
(後略)
マルチタスクで動かす
他に動かしたいタスクをRubyで記述し、
- Rubyファイルをmrubyでコンパイル
- 生成された.cファイルをmain.cppで読み取れるようにする
の項目を繰り返す。
PlatformIOでbuild&upload
ここまでで、コードは完成したので、PlatformIOでBuildボタンを押します。
エラーが出なければ、マイコンをつないで、Uploadをして作業終了です。
お疲れさまでした。
参考文献
Webページ
GitHub
mrubyc/mrubyc
hasumikin/mrubyc-utils
mruby-esp32/mrubyc-esp32-arduino