PicoRuby向けのM5Unified/GFX mrbgemを作る話

PicoRuby向けのM5Unified/GFX mrbgemを作る話

この記事は、mrubyファミリ (組み込み向け軽量Ruby) Advent Calendar 2025に参加しています。

本日の記事では、先日のTokyuRuby会議16 でLTした内容をブログ記事としても残しておきたいと思います。

ESP32とPicoRuby

PicoRubyはもともと、@hasumikin さんがRaspberry Pi Picoをターゲットとしてスタートしたプロジェクトです。

その後、ESP32への対応も@Yuuuさんの尽力もありなされています。(picoruby-esp32)

PicoRubyをESP32のcomponentsとしてビルドしてリンクするような形でポーティングされています。

現在は主なESP32シリーズで、PicoRubyを動かすことができるようになっています。

M5Stackシリーズを使いたい

ESP32を使いたい理由の一つとして、市場にいろいろなバリエーションのESP32をコアとしてパッケージングされた製品があるという点があると思います。

M5Unified/GFXを使いたい

M5シリーズにはディスプレイやボタンやスピーカーなど色々なデバイスが標準搭載されていますが、機種を変えるたびにAPIの仕様が微妙に異なることがあったのを解決するために、機種をまたいだAPIとして、M5Unified(グラフィクスはM5GFXが担当)というライブラリがあります。Arduino以外にもESP-IDF環境でも利用可能です。言語はC++です。

機種を違いを意識しないでプログラミングするには、これを利用しない手はないわけです。

しかし当然PicoRubyには対応していないので、PicoRubyから使うには各メソッドのバインディングを書く必要があります

どうやって大量のバインディングをさばくか

メソッドの数が少なければ、手作業でバインディング書けばよいところではあるのですが、幅広い機能を抽象化しているため、メソッドの数が数百もあります。

これを手作業で書くのはあまり現実的ではないというか、あまりやりたくない作業です。

たとえばCRubyであれば、Ruby-FFIというものがあり、C言語のライブラリをダイナミックリンクして、各関数のインタフェースを自動で定義する機能があります。

こういう場面で役に立つ機能なのですが、マイコン上で動くmrubyではそのままではFFIを動かすことはできません。

そのため、Claude Codeでどこまでやれるか試してみることにしました。

AIに仕事をやらせるための手順

これまでClaude Code使ってきた感覚として、漠然と大量の仕事をやらせても、途中でコンテキストが切れて、一貫性のある作業が難しくなります。

そのため、作業をステップに分割しつつ、進捗もドキュメントに書きつつ、途中でとまって再開できるようなことを意識しつつ、作業してもらう必要あります。

今回は以下のような手順でやってもらいました。

  1. 実装対象の関数をC++ヘッダからスクリプトで抽出
  2. 抽出した結果をYAMLにまとめる
  3. YAMLからmrubyバインディングのスケルトン関数を生成
  4. スケルトン関数を段階的に実装

中間生成物

作業する中で、各メソッドは以下のようなYAMLで抽出されます。

classes:
- name: M5Unified
  namespace: m5::m5
  file: M5Unified.hpp
  methods:
  - name: getPin
    return_type: int8_t
    parameters:
    - type: pin_name_t
      name: name
    modifiers: []
    line: 250
  - name: getButton
    return_type: Button_Class&
    parameters:
    - type: size_t
      name: index
    modifiers: []
    line: 252
  - name: getDisplay
    return_type: M5GFX&
    parameters:
    - type: size_t
      name: index
    modifiers: []
    line: 256
  - name: getDisplayCount
    return_type: std::size_t
    parameters:
    - type: void
      name: ''
    modifiers:
    - const
    line: 260
...

これベースにをCのmruby/c用のバインディングの作法に則った形のスケルトン関数にします。

結果

まずは一番ニーズがあるであろう描画系を試してみました。

よく使うであろうメソッドから対応して、100メソッドほど実装しました。

全体: 99/180 (55%)

M5Unified Core: 20/20 (100%) ✅
  • M5GFX Color: 12/12 (100%) ✅
  • M5GFX Draw: 30/30 (100%) ✅
  • M5GFX Fill: 3/13 (23%)
  • M5GFX Text: 9/31 (29%)
  • M5GFX Image: 2/13 (15%)
  • M5GFX Display: 9/29 (31%)
  • M5GFX Low-level: 4/18 (22%)
  • M5GFX Utility: 0/13 (0%)

サンプルコード

以下のコードを、/home/m5.rb として保存して、R2P2を起動させて実行してみます。

r# M5Unified Basic Display Example
# Based on actual C extension implementation

require 'm5unified'

puts "Initializing M5Unified..."

# Initialize M5
M5.begin

disp = M5.Display

w = disp.width
h = disp.height
puts "Display: #{w}x#{h}"

# Clear screen to black
disp.fill_screen(0x000000)

# Set text properties and display title
disp.set_text_color(0xFFFFFF)  # White
disp.set_text_size(2)
disp.set_cursor(10, 10)
disp.print("Hello M5!")

# Draw shapes with RGB888 colors
puts "Drawing shapes..."

# Red rectangle
disp.fill_rect(10, 40, 100, 60, 0xFF0000)

# Green circle
disp.fill_circle(w/2, h/2, 40, 0x00FF00)

# Blue line
disp.draw_line(0, 0, w-1, h-1, 0x0000FF)

# Yellow triangle (now implemented!)
disp.fill_triangle(w-80, h-40, w-30, h-60, w-10, h-20, 0xFFFF00)

# Cyan text label
disp.set_text_color(0x00FFFF)
disp.set_text_size(1)
disp.set_cursor(10, h-20)
disp.print("PicoRuby on M5")

puts "Drawing complete!"
puts "Press Ctrl+C to exit"

loop do
  M5.update
  sleep 0.1
end

m5.rb

ターゲットデバイス

M5Stack FireとM5StickC Plust2でさっきのサンプルコード試してみました。

無事、同じコードで、同じような描画がされましたね。

M5Unifiedは自動でデバイス認識する機能があるため、特に機種を指定することなく違うLCDでも正しく動作します。

課題

おそらくこの調子でやれば、全メソッド制覇もできそうではあるのですが、そのメソッドのコードレビューと動作確認をするのがかなり大変です。

また何かバージョンアップがあった時の追従も大変そうです。

個人的に使う分にはいいのですが、継続的なメンテナンスが厳しそうなので、今後どうしたものか悩ましいです。

またFFI的なアプローチもあるかなと思ったのですが、M5UnifiedがC++なので、Cと違って、シンボルテーブルを解析して、FFI的なものを自作するのも厳しそう、となっています。

以下は、現在のPicoRuby mrbgem実装です。一応、導入方法も記載したので、試して頂くこともできるかと思います。

GitHub - kishima/mruby-m5unified
Contribute to kishima/mruby-m5unified development by creating an account on GitHub.

R2P2-ESP32に統合したブランチはこちら

GitHub - kishima/R2P2-ESP32 at m5unified_dev3
PicoRuby shell for ESP32. This project runs PicoRuby on ESP32 using picoruby-esp32. - GitHub - kishima/R2P2-ESP32 at m5unified_dev3

Read more

2025年の振り返りと2026年の抱負

2025年の振り返りと2026年の抱負

明けましておめでとうございます。今年も無事新年を迎えられてありがたい限りです。 昨年は色々対外的な活動も増やしたり、自分の趣味プロジェクトも新しく始めたりしたので、活発な一年だったと思います。 今年は仕事始めて20周年でもありますし、色々頑張り時な年だと思うので、抱負と合わせて、昨年の振り返りを残しておきたいと思います。 2025年振り返り 2025年は、4月までは仕事のほうがかなり忙しく、日々仕事で忙殺される日々でした。 2/2 Tokyu.rb新年会2025 まだ忙しい季時期でしたが、地方出張前に荷物抱えて参加した記憶があります。 Tokyu.rbは、みんなで美味しいもの(主に肉)をいただく集まりなのですが、そこで関西Ruby会議のことを聞いたことが、この後の動きの伏線になりました。 5月になって仕事が落ち着いてきたので、一念発起して久しぶりに地域Ruby会議へのプロポーザルを送ったのでした。 5/26 PicoPicoRuby #1 待望のmruby関連の勉強会!ということでウキウキで参加しました。 以降も月イチで安定して開催されており、私の活動のモチ

By kishima
電子工作遍歴をたどる(2)

電子工作遍歴をたどる(2)

前回の話のつづきです。 作例5 ラズパイとGroveによる音楽プレーヤ 2017/08ごろ ラズパイで遊び始めて、そろそろ単なるミニPCとしてではなく、いろいろ電子工作っぽいことをやってみたくなってきました。 そのころSeeedのGroveというものを知って、これなら初心者でも色々電子デバイス試せる!となって色々買ってきて作ったのがこちらです。 A first step to Raspberry Pi project | Kishima blogThis was a first step to Raspberry Pi project done in last year. RaspiMusicServer This an…Kishima blogkishimaGitHub - kishima/RaspiMusicServer: An music server on Raspberry pi and ArduinoAn music server

By kishima
Family mruby OS:FreeRTOSベースのMicroRubyマルチVM構想

Family mruby OS:FreeRTOSベースのMicroRubyマルチVM構想

この記事は、mrubyファミリ (組み込み向け軽量Ruby) Advent Calendar 2025の12/25の記事です。25日の枠が空いていたので、滑り込ませていただきました。 今日は私が最近取り組んでいる個人プロジェクトであるFamily mrubyとそこから発展したFamily mruby OSについて紹介したいと思います。 開発に至る経緯 Family mrubyは2019年から開発着手したプロジェクトです。2020のRubyKaigi Takeoutでも初期型について発表しました。 Family mrubyとは? Family mrubyKishima’s projectsKishima Craft Works 今は昔、子供が最初に触れるプログラミング言語といえば、BASICという時代がありました。 制約は多いですが、パソコン以外にも、MSXやファミコンでBASICができるFamily BASICという製品もあり、そこからプログラミングの面白さを知り、プログラマーになった方もたくさん居られると思います。 そして現在は無料で大抵のプログラミング言語の開発環境

By kishima