LoginSignup
2
2

More than 3 years have passed since last update.

PlatformIOを使ってmruby/cのクロスコンパイル環境を構築する

Last updated at Posted at 2019-09-12

目的

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の初期化

  1. 作業用フォルダを作成、移動
mkdir your_work_space
cd .\your_work_space
  1. 作業フォルダ内で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を動かすための処理を作成

main.cpp
#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ファイルを作成

task1.rb
while true
  Serial_print("task1")
  sleep(1)
end
task2.rb
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に張り付ける。
task.c
/* 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

(後略)
main.cpp
#include "Arduino.h"
#include "mrubyc.h"

// 後ほどmrubyのコンパイラでコンパイルした.rbファイルの処理が格納される配列です。
extern const uint8_t task1[]; <-ここに貼り付け
extern const uint8_t task2[];

(後略)
  • タスクを生成する

以下のようにmrbc_create_task(task1, nullptr)でタスクを追加する。

main.cpp
(前略)

    // マルチタスクを行いたい場合は以下のように追加してください
    // 基本形 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ページ

ESP32×mruby/c IoTハンズオン

GitHub

mrubyc/mrubyc
hasumikin/mrubyc-utils
mruby-esp32/mrubyc-esp32-arduino

書籍

mruby/cの小さな世界 (技術の泉シリーズ(NextPublishing))

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2