本記事は mrubyファミリ (組み込み向け軽量Ruby) Advent Calendar 2025 の17日目の記事です。
本記事ではPicoRubyとブレッドボードで試せる回路とプログラムのサンプル集を掲載します。
私が R2P2-ESP32 のコントリビューターであることから、ESP32を用いる前提で記載します。冬休みの電子工作ネタとしてもおすすめです👍️
準備物
全サンプル共通で準備すべき物は次の通りです。
- 開発用PC
- USB Micro-Bケーブル
-
ESP32-DevKitC
- Espressif Systems社以外の会社が販売している類似品はピンアサインが異なることがあるので、間違えて購入しないようご注意ください
-
ブレッドボード
- 持ち運びやすいコンパクトなものも販売されていますが、初心者の方ほど大きめなものからはじめることをおすすめします
- ブレッドボードをはじめて使う方は こちらの記事 に目を通しておくと安心です
各回路で必要な部品は、以降個別に記載します。
開発環境の構築
R2P2-ESP32を使った開発環境の構築方法をこちらの記事にまとめています。記事に沿って開発環境を構築ください。
サンプル1: LEDを点滅(通称: Lチカ)させる(picoruby-gpio)
「Lチカとはいわば情操教育」という名言も生まれた2025年。まずはここからやっていきましょう。
必要な部品
-
LED
- 赤、緑、青などのバリエーションがあるのでお好きな色のものを選んでください
-
抵抗
- 厳密にはLEDの種類に応じて、流せる電流の量が決まっていて、それに応じた抵抗値を計算する必要があります
- が、330ΩくらいにしておけばだいたいのLEDでうまくいくと思います
回路
次の写真のようにLEDをESP32-DevKitCの26番ピンに接続します。LEDは2本の足の長さが異なっており、足が長い方を上流側(つまりESP32-DevKitCの26番ピン側)とする必要があるのでご注意ください。
LEDの下流側に抵抗を取り付け、その先がESP32-DevKitCのGNDピンとなるように接続します。
プログラム
開発用PC上で次のようなプログラムを準備しましょう。
1秒ごとにLEDが接続されたピンの値を1(HIGH)→0(LOW)→1...と切り替えています。
require 'gpio'
require 'machine'
led = GPIO.new(26, GPIO::OUT)
loop do
led.write(1)
Machine.delay_ms(1000)
led.write(0)
Machine.delay_ms(1000)
end
動作確認
開発用PCで rake します。
$ cd R2P2-ESP32
$ rake
PicoRubyのshellに接続できたら、プログラムを起動します。
$> ./gpio_out.rb
I (19593) gpio: GPIO[26]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
LEDが1秒ごとに点滅していれば成功です。
サンプル2: スイッチの値を読み取る(picoruby-gpio)
出力ができたら入力もしてみたいですよね。これができるだけでも簡単なゲームが作れるようになります。
必要な部品
回路
タクトスイッチは「押すと対角に位置するピン同士が繋がる」と覚えておくと間違いがないです(隣同士のピンは繋がっていたり、いなかったりする)
次の写真のように、ESP32-DevKitCのVCC(5V)をタクトスイッチを介して13番ピンに接続します。
プログラム
開発用PC上で次のようなプログラムを準備しましょう。
1秒ごとにボタンの状態をポーリングし、標準出力しています。
require 'gpio'
require 'machine'
button = GPIO.new(13, GPIO::IN | GPIO::PULL_DOWN)
loop do
puts "Button: #{button.high? ? 'Pressed' : 'Released'}"
Machine.delay_ms(1000)
end
動作確認
開発用PCで rake します。
$ cd R2P2-ESP32
$ rake
PicoRubyのshellに接続できたら、プログラムを起動します。
$> ./gpio_in.rb
I (5953) gpio: GPIO[13]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
Button: Released
Button: Released
Button: Pressed
Button: Pressed
Button: Released
Button: Pressed
Button: Released
1秒ごとにボタンの状態が出力されます。ブレッドボード上のタクトスイッチを押して、表示が変化することを確認ください。
余力のある人はプログラム中の「PULL_DOWN(プルダウン)」の意味を調べてみると、より理解が深まるかもしれません。
サンプル3: 波形を出力して音を出す(picoruby-pwm)
次は単純な出力ではなく、波形を出力します。波形を出力することでLEDの明るさを変化させたり、サーボモーターを制御したりといったことが可能になります。
今回は、RubyKaigi 2025で注目を集めた「音」の入門編として、圧電スピーカーから音を出してみましょう。
必要な部品
回路
13番ピンとGNDに圧電スピーカーを接続します。圧電スピーカーに極性はないので、赤黒線は逆になっても大丈夫です。
プログラム
picoruby-pwm を使うことで周波数とデューティ比、ピン番号を指定するだけで波形を出力することができます。
261, 294,...と記載された配列はドレミファソラシドの周波数を表しています。
require 'pwm'
pwm = PWM.new(2, frequency: 330)
loop do
[261, 294, 330, 349, 392, 440, 494, 522].each do |f|
pwm.frequency(f)
pwm.duty(50)
sleep_ms(800)
pwm.duty(0)
sleep_ms(100)
end
end
動作確認
開発用PCで rake します。
$ cd R2P2-ESP32
$ rake
PicoRubyのshellに接続できたら、プログラムを起動します。
$> ./pwm.rb
圧電スピーカーからド→レ→ミ→ファ→ソ→ラ→シ→ドという音が鳴れば成功です。
サンプル4: アナログ値を読み出す(picoruby-adc)
スイッチのような1 or 0の入力であればGPIOで読み出せるのですが、例えば「0V→0.5V→1.0V→...」のように刻々と変化する電圧を読み取る方法としてAD変換(ADC)が用いられます。
本来であればジョイスティックやボリュームを使って動作確認ができると良いのですが、自分の手元には無いので抵抗を使った分圧値を読み取ってみます。
必要な部品
回路
抵抗を2つ直列に繋いで、中継ポイントを13番ピンに接続します。理論上、13番ピンは5/2=2.5Vとなるはずです。
プログラム
ADCクラスを使ってADCのRaw値を読み取ります。
require 'adc'
input = ADC.new(13)
loop do
puts "Input: #{input.read_raw}"
sleep 1
end
動作確認
開発用PCで rake します。
$ cd R2P2-ESP32
$ rake
PicoRubyのshellに接続できたら、プログラムを起動します。
$> ./adc.rb
Input: 2858
Input: 2859
Input: 2859
Input: 2864
ESP32のADCはざっくり0〜3.3Vを0〜4096の値で返します。厳密には推奨レンジはもう少し狭く、その間の変化は直線とは限らないといった制約があります。
3.3 / 4096 * 2859 = 2.3839599609V ということでおおよそ近い電圧値が読み取れてそうではあります。
サンプル5: シリアル通信する(picoruby-uart)
デバイス側の通信の代表例であるシリアル通信(UART)を試してみましょう。
必要な部品
回路
ちょっとわかりにくいですが、
- モジュール側のTX → ESP32-DevKitC側のRX
- モジュール側のRX → ESP32-DevKitC側のTX
- モジュール側のGND → ESP32-DevKitC側のGND
- モジュール側の3V → ESP32-DevKitC側のVCC 3.3V
- モジュール側の5V → 接続せず
という具合に接続しています。
プログラム
UARTクラスを使って、1文字読み出してそれを書き込む(つまりechoする)というプログラムを用意してみました。
require 'uart'
uart = UART.new(unit: 'ESP32_UART0', txd_pin: 1, rxd_pin: 3)
loop do
str = uart.read
unless str.nil?
uart.write(str)
end
sleep_ms(10)
end
動作確認
開発用PCで rake します。
$ cd R2P2-ESP32
$ rake
USBシリアル変換モジュールのUSBをPCに接続します。
PC側で次のようなコマンドを実行することで、もう1つシリアル接続がされた状態となります。
$ screen /dev/tty.usbserial0001
この状態で、rakeを実行した方のターミナル(PicoRubyのshell)でプログラムを起動します。
$> ./uart.rb
screenでシリアル接続した方のターミナルを開き、キーボード入力をするとその文字がechoされるはずです。
abcde # 入力した文字がそのまま表示される
サンプル6: I2C通信してOLEDディスプレイを表示する(picoruby-i2c)
デバイスで用いられる通信のうち2番目のものとして、I2C通信をします。
必要な部品
回路
VCC(3.3V), GND, SCL(22番ピン), SDA(21番ピン)という4つのピンをOLEDディスプレイに接続します。
プログラム
OLDEを出力するためにはコマンドやデータを仕様に沿って送信する必要があり、プログラムは若干複雑です。
IC2クラスを使って、初期化コマンドを流し込んだ後、自分が出したい模様をデータとして出力していきます。
require "i2c"
ADDR = 0x3C
CTRL_CMD, CTRL_DATA = 0x00, 0x40
CHUNK = 16
CELL_W = 16 # px
CELL_H = 2 # pages (1page=8px) => 16px
i2c = I2C.new(unit: :ESP32_I2C0, sda_pin: 21, scl_pin: 22, frequency: 400_000)
def cmd(i2c, addr, *bytes) bytes.each { |b| i2c.write(addr, CTRL_CMD, b & 0xff) } end
def data(i2c, addr, bytes) i2c.write(addr, CTRL_DATA, bytes) end
cmd(i2c, ADDR,
0xAE, 0xD5,0x80, 0xA8,0x3F, 0xD3,0x00, 0x40, 0x8D,0x14, 0x20,0x00,
0xA1, 0xC8, 0xDA,0x12, 0x81,0xCF, 0xD9,0xF1, 0xDB,0x40, 0xA4, 0xA6, 0xAF
)
# full screen range (horizontal addressing)
cmd(i2c, ADDR, 0x21,0x00,0x7F, 0x22,0x00,0x07)
buf = Array.new(CHUNK, 0)
8.times do |page|
pb = (page / CELL_H) & 1
(128 / CHUNK).times do |blk|
col0 = blk * CHUNK
CHUNK.times do |i|
cb = ((col0 + i) / CELL_W) & 1
buf[i] = (pb ^ cb) == 0 ? 0xFF : 0x00
end
data(i2c, ADDR, buf)
end
end
動作確認
開発用PCで rake します。
$ cd R2P2-ESP32
$ rake
PicoRubyのshellに接続できたら、プログラムを起動します。
$> ./i2c.rb
次の画像のように、OLEDディスプレイに市松模様が表示されれば成功です。
サンプル7: SPI通信してドットマトリックスLEDを点灯させる(picoruby-spi)
最後にSPI通信です。 私のRubyKaigi 2025の発表 のデモ動画で使ったのはこれです。
必要な部品
回路
少しわかりにくいので2枚写真を貼っています。次のように接続しました。
- モジュール側のVCC → ESP32-DeVKitC側の5V
- モジュール側のGNND → ESP32-DeVKitC側のGND
- モジュール側のDIN → ESP32-DeVKitC側の23番ピン(VSPI_MOSI)
- モジュール側のCS → ESP32-DeVKitC側の5番ピン(VSPI_SS)
- モジュール側のCLK → ESP32-DeVKitC側の18番ピン(VSPI_SCLK)
プログラム
OLEDと同様ドットマトリックスLEDモジュールもデータシートにコマンドが定義されています。
最初に初期化のためのコマンドを流し、その後ビット単位の1 or 0の並びによって各LEDの点灯・消灯を切り替えています。
require 'spi'
spi = SPI.new(unit: 'ESP32_VSPI_HOST', frequency: 10_000_000, sck_pin: 18, cipo_pin: 19, copi_pin: 23, cs_pin: 5, mode: 0, first_bit: 0)
spi.write([0x0c, 0x01])
spi.write([0x09, 0x00])
spi.write([0x0a, 0x0f])
spi.write([0x0b, 0x07])
[
0b01010101,
0b10101010,
0b01010101,
0b10101010,
0b01010101,
0b10101010,
0b01010101,
0b10101010,
].each_with_index do |val, i|
spi.write([i + 1, val])
end
loop { sleep_ms(500) }
動作確認
開発用PCで rake します。
$ cd R2P2-ESP32
$ rake
PicoRubyのshellに接続できたら、プログラムを起動します。
$> ./spi.rb
次の画像のように、ドットマトリックスLEDに市松模様が表示されれば成功です。
おわりに
自分にとって2025年はPicoRubyに始まり、PicoRubyに終わった年でした。
年明け1月4日から義実家近くのあるコワーキングスペースに丸一日籠もって、PicoRubyをESP32上で動かすための作業をしていましたし、年末が近づいた今もこうして記事・コードをを書いています。
さて、7月に大阪で開催された PicoRuby Overflow会議 の懇親会で、「PicoRubyを始めたい(もしくは最近始めた)けど、ドキュメントを読んでも何から始めたらよいかよくわからない」といった話が出ました。特に用意されたクラスの使い方と回路がよくわからない、と。
そうした背景もあり、こういった記事を書いてみることにしました。
自分はPicoRubyをポーティングしていて、動作確認のときに簡単な回路とサンプルプログラムを作成しています。サンプルプログラムはGitHubにpushするほどのものでもないしどうしたものかなと悩んでいたところで、2025年が終わる前にこうした形で公開できてよかったです。










