GR-CITRUS+mrubyで書き方によるバイナリサイズの違いを検証してみた


GR-CITRUSのプログラムをmrubyで行うとき、素の状態的に用意されているメソッドを叩くと、見た感じarduinoを触ってる時と変わらなくてeachとか制御構造等でしか恩恵を得られないような気がしたので、オブジェクト指向らしい書き方をするとどうなるのか検証してみた。

本体LEDを点滅させ、ボタンクリックで停止させるプログラムを作って見た。

arduino風に書いたばあい

aruduino_like.rb
#!mruby

pinMode(13,0x02)

console = Serial.new(0)
console.println "running..."

loop do
  if digitalRead(13) == 0
    console.println "exit!"
    System.exit
  else
    [1, 0].each do |sw|
      led sw
    end
    delay 250
  end
end

mrbcして出てきたバイナリは 439bytes。小さい。

Ruby風にボタンをオブジェクトと定義して、かつアプリケーション全体をClassにしてみた

rubish.rb
#!mruby
# coding: utf-8

INPUT = 0x00
OUTPUT = 0x01
INPUT_PULLUP = 0x02

#
# ボード上のピンを定義
#
class Pin
  HIGH = 0
  LOW  = 1

  def initialize(pin, mode)
    if pin.class == Symbol
      @pin = pin.to_s.split("_").last.to_i
    else
      @pin = pin
    end

    pinMode(@pin, mode)
  end

  #
  # ピンをHIGH/ONにする
  #
  def on
    digitalWrite(@pin, HIGH)
  end
  def off
    digitalWrite(@pin, LOW)
  end
  def on?
    digitalRead(@pin) == HIGH
  end
  def off?
    digitalRead(@pin) == LOW
  end
end

#
# Pinを継承してボタンオブジェクトを作成。今回は初期化の引数しか使ってないけど。
#
class Button < Pin
  def initialize(pin, mode=INPUT_PULLUP)
    super
  end
end


class MyApplication
  def initialize
    @console = Serial.new(0)
    @console.println "running..."

    @btn_stop = Button.new(:pin_13)
  end

  def run
    loop do
      if @btn_stop.on?
        @console.println "exit!"
        System.exit
      else
        [1, 0].each do |sw|
          led sw
        end
        delay 250
      end
    end
  end
end

MyApplication.new.run

mrbcして出来たバイナリは 1593bytes.

まとめ

このRuby風にClass定義して、インスタンスをMyApplicationクラスに作っていくやり方で、液晶画面やセンサを組み込んでみたところ8KB以上のバイナリとなり、(2016.12.10現在)ファームウェアでの8KB制限に引っかかってしまう結果となった。

うまいやりかたは思いつかないけど、組み込みという性質上あんまりバリバリにClass定義して容量を食ってしまうと元も子もないので、当面はarduino風の書き方がいいのかもしれない(個人の感想です)