First experiments embedding mruby

The philosophy of mruby is to be a lightweight implementation of the Ruby ISO standard with some limitations. Different from the usual Ruby runtime, specially MRI, mruby, using RiteVM, is designed to be a modular and embedded version of ruby. It’s pretty small and fast, actually, and easily extended with C. A good OO auternative to Lua for embbedded, although lua is way faster today.

code integrations, is easy as hell

clone mruby repo

$ cd ~/Workspace/embbeded
$ git clone https://github.com/mruby/mruby.git

Then install it as explained here

Now, let’s test with a simple inline code (01.c):

#include <mruby.h>
#include <mruby/compile.h>

int
main(void)
{
  mrb_state *mrb = mrb_open();
  if (!mrb) { /* handle error */ }
  // mrb_load_nstring() for strings without null terminator or with known length
  mrb_load_string(mrb, "puts 'hello world'");
  mrb_close(mrb);
  return 0;
}

compile it with:

$ gcc -std=c99 -Imruby/include 01.c -o aaa mruby/build/host/lib/libmruby.a -lm

as expected, the string “Hello world” will be printed. Now, to embbed a small ruby file, I tested this small C code(02.c):

#include <stdio.h>
#include <mruby.h>
#include <mruby/dump.h>

static mrb_value mrb_greet(mrb_state *mrb, mrb_value self) {
  printf("Hey ho mofo!\n");
  return mrb_nil_value();
}

mrb_value mrb_boo(mrb_state* mrb, mrb_value self){
	mrb_int i = 0; // retrieve one arg of type int (see mruby.h)
	mrb_get_args(mrb, "i", &i);
	printf("iiiiiha %d hae hae\n", (int)i);
	return mrb_nil_value();
}

int main(void){
  mrb_state *mrb = mrb_open();
  if (!mrb) { /* handle error */ }
  mrb_define_method(mrb, mrb->object_class, "greet!", mrb_greet, MRB_ARGS_NONE());
  mrb_define_method(mrb, mrb->object_class, "boo!", mrb_boo, MRB_ARGS_REQ(1));
  FILE *fp = fopen("testa.mrb", "r");
  mrb_load_irep_file(mrb, fp);
  mrb_close(mrb);
  return 0;
}

There are two importante things here. First, I had to add <mruby/dump.h> for mrb_load_irep_file and remove <mruby/compile.h> to decrease generated binary file. Second, we have to export any method that we define in C with mrb_define_method.

Now for the testa.rb we have


puts 'helloooo worldi'
greet!
puts 'here we go'
boo! 12
puts 'end'

After that, generate it’s bytecode with:

$ cd ~/Workspace/embbeded
$ mruby/bin/mrbc testa.rb

which will generate `testa.mrb`.

$ cd ~/Workspace/embbeded
$ gcc -std=c99 -Imruby/include 02.c -o aaa mruby/build/host/lib/libmruby.a -lm
$ ./aaa
helloooo worldi
Hey ho mofo!
here we go
iiiiiha 12 hae hae
end

To show that this works.

Also, as we are junt reading from a file, we could store it within an array. That would work as well.
just include <mruby/irep.h> then create an anyarray[] = { 0x45, 0x54..., 0x08 }; and, finally, call with mrb_load_irep(mrb, anyarray);

mruby is easy to integrate with anything and is getting faster everyday. So play with it a little. Enjoy.

My first steps into Ruby and OpenCV(on OSX)

I was writing some robotic code that will run on a mac mini, so I tryied on my macbook for the first time, ruby binding to opencv. It was a weird experience lol.

First, to install OpenCV, brew do the job:

$ brew tap homebrew/science
$ brew install opencv

after a while we see that instalation goes flawlessly:
/usr/local/Cellar/opencv/2.4.13.2: 278 files, 35.6MB
and we have current version: 2.4.13.2. That said, now install ruby gem:

$ gem install ruby-opencv -- --with-opencv-lib=/usr/local/Cellar/opencv/2.4.13.2/lib \
                             --with-opencv-include=/usr/local/Cellar/opencv/2.4.13.2/include/opencv \
                             --with-opencv-include=/usr/local/Cellar/opencv/2.4.13.2/include/opencv2

Fetching: ruby-opencv-0.0.18.gem (100%)
Building native extensions with: '--with-opencv-lib=/usr/local/Cellar/opencv/2.4.13.2/lib --with-opencv-include=/usr/local/Cellar/opencv/2.4.13.2/include/opencv --with-opencv-include=/usr/local/Cellar/opencv/2.4.13.2/include/opencv2'
This could take a while...
Successfully installed ruby-opencv-0.0.18
Parsing documentation for ruby-opencv-0.0.18
Installing ri documentation for ruby-opencv-0.0.18
Done installing documentation for ruby-opencv after 7 seconds
1 gem installed

after that, time to code.

My first try, obviously, is to use HAAR cascade classifier to look for faces.

require "rubygems"
require "opencv"
include OpenCV

window = GUI::Window.new(&quot;grab da face!&quot;)
camera = CvCapture.open
detector = CvHaarClassifierCascade::load('./haarcascade_frontalface_alt.xml')
loop {
  image = camera.query
  detector.detect_objects(image).each { |rect|
    image.rectangle! rect.top_left, rect.bottom_right, :color => CvColor::Blue
  }
  window.show image
  break if GUI::wait_key(100)
}

It didn’t worked as ruby-opencv currently supports only older type format of trained data xml. To solve that, I grabed older version of haarcascade_frontalface_alt.xml from https://raw.githubusercontent.com/Itseez/opencv/2.4.10.4/data/haarcascades/haarcascade_frontalface_alt.xml and it worked as expected.
Sometimes, OSX Facetime camera stop working, but is easy to fix, just run

sudo killall VDCAssistant

wait a little and voilá.

In the end, was a different experience, it worked but was way too slow. I’ll try to tweak a little but python version are way faster and I believe I’ll keep using it.