最近息子と一緒にBBC micro:bitを触って遊んでいます。
今日はこのmicro:bit上でmruby/cを動かしてみましたのでメモを残しておきます。
(写真撮ったあとにBBCをBCCにtypoしてるのに気付きました。。。)
はじめに
micro:bitとは
micro:bitはBBC(英国放送協会)が主体となって開発されたシングルボードコンピューターです。学校での情報教育(プログラミング)などで利用されているとのことです。
MICRO-BIT V2 (マイクロビット)バージョンアップ版 正規品!
- メディア: エレクトロニクス
こちらのスイッチエデュケーションさんのサイトに特徴がまとめられています。
micro:bit の特徴
- LEDやボタン、センサーなどをあらかじめ搭載しています
- パソコンやタブレット、さまざまな環境でプログラミングできます
- 段階的にプログラミングを学ぶことができます
- 拡張パーツをつなげれば、さまざまな作品を作ることができます
値段も2,000円程度(執筆時点)と手ごろな価格になっており、手軽に触り始めることが出来ます。
こちらはRaspberry Piと比べてみた写真です。手のひらサイズですね。
ブロックを用いたビジュアルプログラミングができるMakeCodeやMicroPythonを利用可能なので子供のプログラミング&電子工作入門に良さそうと思い購入しました。
mruby/cとは
mruby/cとは、軽量Rubyであるmrubyをさらに組み込み機器向けに軽量化したmrubyの実装とのことです。
こちらの記事でWio LTE上で動かしているのを読んでmicro:bit上でも動かせるんじゃないか?と思ったのが今回のきっかけです。
magazine.rubyist.net
ということで早速micro:bit上でmruby/cを動かしてみます。
準備
先ほどのRubyist Magagineの記事を参考に、開発環境にはArduino IDEを利用します。
必要なもの
Arduino IDEでmicro:bit v2を使えるようにする
まずはArduino IDEでmicro:bit v2を使えるようにするためにsandeepmistry/arduino-nRF5をインストールします。
Arduinoの環境設定ダイアログを開き、追加のボードマネージャのURL
に以下を入力します。
https://sandeepmistry.github.io/arduino-nRF5/package_nRF5_boards_index.json
注: 既に他のURLが入力されている場合、カンマ区切りで後ろに追記してください。
これでツール -> ボード -> Nordic Semiconductor nRF5 boards
という項目の中からBBC micro:bit V2
が選べるようになっているはずです。
mruby/cをmicro:bit v2へ移植
次にmruby/cをmicro:bit v2へ移植します。
- mruby/cのソースを取得
- HALを実装
- Arduinoのライブラリにする
mruby/cのソースを取得
次にmruby/cのソースを取得します。
git clone https://github.com/mrubyc/mrubyc.git
今回は何も考えずmasterを利用しました。エラーが出るようならタグが付けられたバージョンを使おうと思ったのですが、幸い特にエラーは起きなかったのでそのままmasterを使いました。
HAL(Hardware Abstraction Layer)の実装
mruby/cにはHALとして以下のものが用意されていました。
- hal_esp32
- hal_pic24
- hal_posix
- hal_psoc5lp
これらを参照しつつmicro:bit(nRF52833)向けにHALを実装します。
実装手順
既存のsrc/hal_*
ディレクトリを削除
まずsrc/hal_*
ディレクトリを削除してしまいます。
(残しておくとArduino IDEでエラーが出たため。原因を調べるのが面倒だったので削除しちゃいました)
既存のsrc/hal_selector.h
の修正
次にsrc/hal_selector.h
を以下のように修正します。
/*! @file <pre> Copyright (C) 2016-2020 Kyushu Institute of Technology. Copyright (C) 2016-2020 Shimane IT Open-Innovation Center. This file is distributed under BSD 3-Clause License. </pre> */ // 以下をごっそり削りhal/hal.hのincludeだけにする #include "hal/hal.h"
本来はどのHALを使うのかの判定が入っているのですが、今回はごっそり削ってhal/hal.h
を決め打ちしました。
src/hal
ディレクトリの作成 & hal.h
/hal.c
/hal.cpp
の作成
次にsrc/hal
ディレクトリを作成し、その中にhal.h
/hal.c
/hal.cpp
を作成していきます。
hal.h
/*! @file https://github.com/mrubyc/mrubyc/blob/master/src/hal_posix/hal.hを参考に実装 オリジナルのライセンス表記は以下のとおり Copyright (C) 2016-2020 Kyushu Institute of Technology. Copyright (C) 2016-2020 Shimane IT Open-Innovation Center. This file is distributed under BSD 3-Clause License. */ #ifndef MRBC_SRC_HAL_H_ #define MRBC_SRC_HAL_H_ #ifdef __cplusplus extern "C" { #endif /***** Macros ***************************************************************/ #if !defined(MRBC_TICK_UNIT) #define MRBC_TICK_UNIT_1_MS 1 #define MRBC_TICK_UNIT_2_MS 2 #define MRBC_TICK_UNIT_4_MS 4 #define MRBC_TICK_UNIT_10_MS 10 // You may be able to reduce power consumption if you configure // MRBC_TICK_UNIT_2_MS or larger. #define MRBC_TICK_UNIT MRBC_TICK_UNIT_1_MS // Substantial timeslice value (millisecond) will be // MRBC_TICK_UNIT * MRBC_TIMESLICE_TICK_COUNT (+ Jitter). // MRBC_TIMESLICE_TICK_COUNT must be natural number // (recommended value is from 1 to 10). #define MRBC_TIMESLICE_TICK_COUNT 10 #endif #if !defined(MRBC_NO_TIMER) // use hardware timer. # define hal_init() ((void)0) # define hal_enable_irq() ((void)0) # define hal_disable_irq() ((void)0) # define hal_idle_cpu() ((void)0) #else // MRBC_NO_TIMER # define hal_init() ((void)0) # define hal_enable_irq() ((void)0) # define hal_disable_irq() ((void)0) # define hal_idle_cpu() ((void)0) #endif /***** Function prototypes **************************************************/ int hal_write(int fd, const void *buf, int nbytes); int hal_flush(int fd); #ifdef __cplusplus } #endif #endif // ifndef MRBC_SRC_HAL_H_
本来はhal_*()
達を実装すべきなのですが、今回はとりあえず動かすことが目的なので((void)0)
で済ませてます。
動作確認のためにシリアル出力は行いたいのでhal_write()
とhal_flush()
だけは実装します。
hal.c
/* https://github.com/kishima/libmrubycForWioLTEArduino/blob/master/src/hal/hal.cを参考に実装 オリジナルのライセンス表記: https://github.com/kishima/libmrubycForWioLTEArduino/blob/master/LICENSE */ #include "hal.h" int hal_write(int fd, const void *buf, int nbytes) { char* t = (char*)buf; char tbuf[2]; if(nbytes==1){ tbuf[0]=*t; tbuf[1]='\0'; hal_write_string(tbuf); return nbytes; } hal_write_string(t); return nbytes; } int hal_flush(int fd) { hal_serial_flush(); }
前述のRubyist Magazineの記事を参考に実装してみました。
hal_write_string()
とhal_serial_flush()
はこのあとhal.cpp
で実装します。
hal.cpp
/* https://github.com/kishima/libmrubycForWioLTEArduino/blob/master/src/hal/hal.cppを参考に実装 オリジナルのライセンス表記: https://github.com/kishima/libmrubycForWioLTEArduino/blob/master/LICENSE Copyright (c) 2018, katsuhiko kageyama All rights reserved. */ #include <Arduino.h> extern "C" void hal_write_string(char* text){ Serial.write(text); } extern "C" void hal_serial_flush(char* text){ Serial.flush(); }
こちらも最低限の実装となってます。
とりあえずこれで最低限動くはずです。
Arduinoのライブラリにする
次にmruby/cをArduinoから使うために先ほど移植したソースをArduinoのライブラリにします。
ここもほぼ前述のRubyist Magazineの記事の通りに進めます。
Arduinoのライブラリディレクトリ(macの場合~/Documents/Arduino/libraries
、Windowsの場合はC:¥Users¥ユーザー名¥Documents¥Arduino¥libraries
など)にlibmrubyc
などという名前でディレクトリを作成します。
そのディレクトリ内に先ほど修正したソース達とlibrary.properties
というテキストファイルを格納します。
library.properties
の作成
以下のような内容にします。
name=mruby/c for Micro:Bit v2 version=0.0.1 author=yamamoto-febc maintainer=yamamoto-febc sentence=mruby/c implementation for BBC Micro:Bit v2. paragraph= category=Communication url=https://github.com/yamamoto-febc/libmrubyc architectures=* includes=mrubyc.h
修正したmruby/cのsrc
ディレクトリをコピー
次にmruby/cのsrc
ディレクトリをコピーします。
最終的に以下のようなファイル構成になっているはずです。
(~/Documents/Arduino/など)/libraries/ ├── library.properties // 作成したファイル └── src // mruby/cのsrcからコピーしたもの
これでArduino IDEを再起動するとライブラリとして認識されているはずです。
mruby/cのコード作成〜バイトコード生成〜Arduinoのスケッチ作成
Arduinoの準備が出来たのでいよいよmruby/cのコードを書いてみます。
今回は以下のようにputs
するだけです。
puts "hello mruby/c from BBC micro:bit v2!"
これをhello.rb
として作成します。
そしてこのファイルをmrbc
コマンドに渡してmruby/cに渡すバイトコードを生成します。
$ mrbc -E -B code hello.rb
これでカレントディレクトリにhello.c
が作成されているはずです。
これを後ほどArduinoスケッチに貼り付けます。
TIPS: mrbcコマンドで-e/-E option no longer needed
というエラーが出る
おそらくmruby v2.1.2以降を利用しています。
参考: https://github.com/mruby/mruby/commit/48c473a0c4abc67614a00d282d24d18089908449
mruby v2.1.1を利用するようにしてください。
次にArduinoのスケッチを作成します。
/* https://github.com/kishima/libmrubycForWioLTEArduino/blob/master/examples/controlLED/controlLED.inoを参考に実装 オリジナルのライセンス表記: https://github.com/kishima/libmrubycForWioLTEArduino/blob/master/LICENSE */ #include <mrubyc.h> /* ここに先ほど生成したhello.cの内容を貼り付ける */ void setup() { delay(100); Serial.begin(9600); Serial.println("microbit is ready!"); mrbc_init(mempool, MEMSIZE); if(NULL == mrbc_create_task( code, 0 )){ Serial.println("mrbc_create_task error"); return; } Serial.println("--- run mruby script"); mrbc_run(); } void loop() { delay(1000); }
スケッチの中に先ほど生成したhello.c
の内容をそのまま貼り付けてください。
私の手元の環境では最終的なスケッチは以下のようになりました。
/* https://github.com/kishima/libmrubycForWioLTEArduino/blob/master/examples/controlLED/controlLED.inoを参考に実装 オリジナルのライセンス表記: https://github.com/kishima/libmrubycForWioLTEArduino/blob/master/LICENSE */ #include <mrubyc.h> #include <stdint.h> const uint8_t code[] = { 0x52,0x49,0x54,0x45,0x30,0x30,0x30,0x36,0xef,0x0a,0x00,0x00,0x00,0x7a,0x4d,0x41, 0x54,0x5a,0x30,0x30,0x30,0x30,0x49,0x52,0x45,0x50,0x00,0x00,0x00,0x5c,0x30,0x30, 0x30,0x32,0x00,0x00,0x00,0x78,0x00,0x01,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x0c, 0x10,0x01,0x4f,0x02,0x00,0x2e,0x01,0x00,0x01,0x37,0x01,0x67,0x00,0x00,0x00,0x01, 0x00,0x00,0x24,0x68,0x65,0x6c,0x6c,0x6f,0x20,0x6d,0x72,0x75,0x62,0x79,0x2f,0x63, 0x20,0x66,0x72,0x6f,0x6d,0x20,0x42,0x43,0x43,0x20,0x6d,0x69,0x63,0x72,0x6f,0x3a, 0x62,0x69,0x74,0x20,0x76,0x32,0x21,0x00,0x00,0x00,0x01,0x00,0x04,0x70,0x75,0x74, 0x73,0x00,0x45,0x4e,0x44,0x00,0x00,0x00,0x00,0x08, }; #define MEMSIZE (1024*50) static uint8_t mempool[MEMSIZE]; void setup() { // 省略 } void loop() { // 省略 }
実機で動かしてみる
あとはmicro:bitに転送して動かすだけです。 うまくいけばシリアルモニタに文字が表示されるはずです。
TIPS: Error: Illegal bytecode
というエラーが出る
hello.c
のコピペミスやmrubyのバージョン違いの可能性があります。
最初mrubyの最新版(2.1.2)を使ってたらこのエラーが出ました。
mruby/c側が(記事執筆時点のmasterでは)mruby v2.1.1のバイトコード(RITE0006)を期待してるんですね。
参考: https://github.com/mrubyc/mrubyc/blob/228645971e0005cc743cfa653c99ff2b78ae02a0/src/load.c#L54-L57
終わりに
ということでmicro:bit v2上でmruby/cを動かしてみました。
このままだとシリアル出力しか出来ないのでもうちょっと色々書く必要がありますが、とりあえずmruby/cを使っていくためのスタートラインには立てたんじゃないかなと思います。
参考にした記事/サイト
- mruby/c | しまねソフト研究開発センター
- mruby/cで始めるオリジナルIoTデバイス作り
- GitHub - sandeepmistry/arduino-nRF5: Arduino Core for Nordic Semiconductor nRF5 based boards
↓↓この辺はこの記事書いてる時に見つけました。書き始める前に読みたかった。。。
以上です。
MICRO-BIT V2 (マイクロビット)バージョンアップ版 正規品!
- メディア: エレクトロニクス