← UIAPduino WebHID Lab
All in Browser — Ruby Parser 同梱 Ruby × 電子工作

URB Lab

数百円のマイコンで始めるRuby電子工作。
コンポーネントを選んで .ino をダウンロード、 ブラウザでRubyをコンパイルしてSDへ転送するだけ。
独自の TinyVM がバイトコード(.urb)を実行。インストール不要。クラウド不要。

Powered by Wakayama.rb — 和歌山発Rubyコミュニティ
⚠️ このページのデバイス接続機能は Chrome または Edge でのみ動作します。
WebHID API は Firefox・Safari では利用できません。Chrome / Edge で開き直してください。
(Ruby のコンパイルと .ino / .urb のダウンロードはこのブラウザでも利用できますが、デバイス接続・SD 転送・HID コンソールは利用できません)
UIAPrubyとは? — はじめての方へ
数百円から始めるRuby電子工作

「Rubyで電子工作をやってみたい」——そう思っても、 高価なボード、複雑なセットアップ、専用ソフト… とハードルを感じていませんか?

UIAPruby は、そのハードルをぐっと下げます。
UIAPduino(290円、CH32V003ベース)に microSDカードアダプタ(300円ほど)を合わせて、ハードウェアは数百円。 あとは手持ちのChrome/Edgeブラウザだけ。 普段書いているRubyの文法でLEDを光らせ、ブザーを鳴らし、センサーを読み、 電源を切っても消えない変数($count)やドット絵の配列まで扱えます。

マイコンで Ruby といえば mruby。でも mruby のビルドには Ruby と rake が必要で、 Arduino IDE だけでは完結しません。 URB Lab は、その rake の役割をブラウザに移しました。 コンポーネント(mruby の mrbgems に相当)を選ぶと、 必要な機能だけを組み込んだ単一の .ino が生成され、Arduino IDE でそのまま書き込めます。 PC に mruby のビルド環境(rake の構成やクロスコンパイラ)を整える必要はありません。

Rubyコードのコンパイルもブラウザの中——@ruby/prism でコードを解析し、 独自の軽量バイトコード(.urb)に変換。 WebHIDでSDカードへ直接転送し、マイコン上のTinyVMが実行します。
インストール不要・クラウド不要。すべてブラウザの中で完結。

Rubyist が電子工作へ踏み出す入口を、 Wakayama.rb が作りました。mruby ボード GR-CITRUS に続く、二つ目の扉です。

✏️ Rubyコードを書く ⚙️ ブラウザ内コンパイル 📤 SDカードへ転送 ▶ TinyVMが実行

⚡ クイックスタート(4ステップ)

  1. 1
    スケッチをダウンロードして書き込む(初回のみ)
    この下の「コンポーネント選択」で使いたい機能を選び、 UIAPrubyVm***.ino をダウンロード。 Arduino IDEでUIAPduinoに書き込みます。
    書き込み時は、UIAPduino のボタンを押しながら USB ケーブルを挿し、 ブートローダーを起動した状態にしてから書き込んでください。
    FQBN: UIAP_HID:ch32v:CH32V003:pnum=V14,usb=webhid,opt=oslto
  2. 2
    Rubyコードを書く
    エディタにRubyコードを入力します。サンプルボタンですぐ試せます。
    例:led = GPIO.new(2, GPIO::OUT) → D2ピンをLED出力に設定
    loop do led.toggle; sleep(0.5); end → 0.5秒ごとに点滅
  3. 3
    「コンパイル」ボタンを押す
    ブラウザ内でRubyコードをAST解析し、TinyVM用 .urb バイトコードへ変換します。
    ✓ OK と表示されれば生成完了です。
  4. 4
    SDカードに送信 → RUN
    USBケーブルでUIAPduinoを接続し「📤 SDカードに送信」をクリック。 未接続ならデバイス選択ダイアログが自動で開きます。転送後「▶ RUN」で実行開始。
    💡 ファイル名を main.urb にしておくと、 電源投入から 5 秒後に自動実行されます。

🔧 必要なハードウェア

  • UIAPduino SD版(CH32V003ベース、microSDスロット搭載)
  • MicroSDカード(FAT32フォーマット)
  • USBケーブル(Micro-B または Type-C)
  • LED / タクトスイッチ / ブザーなど(実験用)

💻 必要なソフトウェア

  • Google Chrome または Microsoft Edge(最新版)
  • このページ — WebHID対応ブラウザのみ動作
  • Arduino IDE(スケッチ初回書き込み時のみ)
  • UIAP_HID ボードパッケージ v1.2.7 以降(必須)
    ボードマネージャURL: https://raw.githubusercontent.com/tarosay/board_manager_files/main/package_uiap_hid_index.json
📌 ピン配置リファレンス
UIAPduino SD 版 対応ピン一覧(クリックで開く)
Arduinoピン番号 CH32V003ポート PWM ADC 用途・備考 UIAPruby記法
2 PC0 LED出力(基板上LED) GPIO.new(2, GPIO::OUT)
3 PC1 SDA (I2C) / HC-SR04 TRIG Ultrasonic.new(3, 4)
4 PC2 SCL (I2C) / HC-SR04 ECHO Ultrasonic.new(3, 4)
5 PC3 PWMブザー(圧電ブザー推奨) Tone.new(5)
11 PD1 タクトスイッチ(PULL_UP使用) GPIO.new(11, GPIO::IN | GPIO::PULL_UP)
0, 1, 12, 15, 16 PA1/PA2/PD2/PD5/PD6 アナログ入力(ADC対応ピン) ADC.new(0)
6 PC4 ✅* ✅* ⚠ SDカード SS専用 — 使用不可
7 / 8 / 9 PC5 / PC6 / PC7 ⚠ SDカード SCK/MOSI/MISO専用 — 使用不可
6(SS)・7(SCK)・8(MOSI)・9(MISO) はSDカードのSPI通信に専用です。GPIOには使用できません。
ピン6はPWM・ADC対応ですが、SDカード搭載版では使用不可です(* 印)。
コンポーネント選択

選択内容が下のエディタのサンプルと .ino ファイルに反映されます。

BASE
GPIO / 制御フロー / Print
デジタル入出力・ループ・条件分岐・文字列出力
常時含む
Flash 使用量(CH32V003: 16384 bytes)
12,816 / 16,384 bytes (78%) — BASE のみ
サンプルコード — クリックすると下のエディタに読み込まれます(選んだコンポーネントに応じて増えます)
BASE
Ruby ソースエディタ
⏳ @ruby/prism WASM 読み込み中...

UIAPruby — Ruby構文を @ruby/prism でAST解析し、UIAPduino TinyVM用 URB1 バイトコードへ変換します。
UIAPduino 上では Ruby VM を実行しません。
.rb ファイルをエディタにドラッグ&ドロップするか、「開く」ボタンで読み込めます。

ライブラリ管理 (require / require_relative)
登録されたライブラリを require "name" または require_relative "name" で読み込めます。
コンパイル結果
— 未コンパイル
命令数
URB サイズ (bytes)
推定実行時間 (ms)
最大 26 文字 / 自動実行は main.urb
URB ファイル操作
LED: D2 (PC0) / PWM Buzzer: D5 (PC3) / Button: D11 (PD1 PULL_UP) から試してください。
⚠ D7(SCK) D8(MOSI) D9(MISO) D6(SS) は SD カード SPI 専用のため GPIO に使用できません。
💡 ファイル名を main.urb にすると、UIAPduino に電源を入れるだけで自動実行されます。
自動実行が始まるのは、電源オンから 5 秒待ってからです。
USB 接続・RUN ボタン操作なしで単体動作するので、完成したスクリプトの運用に便利です。
SD カード — ファイル管理
デバイスに接続すると SD カードのファイル一覧が表示されます。
Device Log
未接続
UIAPrubyVm***.ino を書き込んだ UIAPduino SD を USB 接続し、「デバイスに接続」を押してください。
HID Console
💻 UIAPruby print / puts / p / putc 出力
URB1 フォーマット

ファイルヘッダー(8 バイト)

オフセット
サイズ
内容
0x00
4 bytes
magic "URB1" (0x55 0x52 0x42 0x31)
0x04
1 byte
version = 1(SD変数なし) / 2(SD変数メタデータあり)
0x05
1 byte
flags = 0
0x06
uint16 LE
code_size (bytecode のバイト数)

SD変数メタデータ(version = 2 のみ、ヘッダー直後)

フィールド
サイズ
内容
var_count
1 byte
変数の個数(最大6)
type
1 byte
0=数値 1=文字 2=数値配列 3=文字配列。bit7=永続($var: 電源を切っても値を保持)
count
uint16 LE
要素数(数値/文字は1)
name
可変
変数名(null終端、最大16文字)。実行時 {プログラム名}_{変数名}.urv に保存

TinyVM 命令セット(リトルエンディアン)

Opcode
命令
引数
サイズ
0x00
END
1
0x01
WAIT_MS
uint16 ms
3
0x02
GPIO_MODE
uint8 pin, uint8 mode (0=IN 1=OUT 2=IN_PULLUP 3=IN_PULLDOWN)
3
0x03
GPIO_WRITE
uint8 pin, uint8 value
3
0x04
GPIO_READ
uint8 pin, uint8 reg
3
0x05
TONE_FREQ
uint8 pin, uint16 freq
4
0x06
JMP
int16 relative_offset
3
0x07
JZ
uint8 reg, int16 relative_offset
4
0x08
JNZ
uint8 reg, int16 relative_offset
4
0x09
GPIO_TOGGLE
uint8 pin
2
0x0A
LOAD_Q16
uint8 reg, int32 value
6
0x0B–0x0E
ADD/SUB/MUL/DIV_Q16
uint8 dst, uint8 src
3
0x0F–0x11
CMP_LT/GT/EQ_Q16
uint8 lhs, uint8 rhs, uint8 out_reg(>= <= != はコンパイラが補命令 + JNZ に変換)
4
0x12
WAIT_MS_REG
uint8 reg, uint16 mul — delay(mul) をレジスタ整数部の回数だけ繰り返す(変数の時間待ち)
4
0x15
LOAD_BOOL
uint8 reg, uint8 value
3
0x16
PRINT_STR
uint8 flags, uint8 len, byte[len] str (flags: 0x01=newline 0x02=inspect)
3+N
0x17
HALT
uint8 error_code
2
0x18
ADC_READ
uint8 pin, uint8 reg → 整数 0〜255(Q16.8 整数部)ピン: 0,1,12,15,16
3
0x19
PRINT_REG
uint8 flags, uint8 reg → Q16.8 を "n.nn" 形式で出力 (flags: 0x01=newline)
3
0x1A
ULTRASONIC_READ
uint8 trig, uint8 echo, uint8 reg → Q16.8 cm (0=タイムアウト) HC-SR04
4
0x21
RAND
uint8 min, uint8 max, uint8 dst_reg → Q16.8 整数 (min〜max-1) max=0 は 0〜255
4
0x22
SRAND
uint16_le seed — 乱数シード設定 (0 → 1 に補正)
3
0x23
PWM_DUTY
uint8 pin, uint8 duty (即値 0〜255)
3
0x24
PWM_BASE_FREQ
uint8 pin, uint16 freq — PWM 基準周波数 (PSC 設定)
4
0x25
VAR_LOAD
uint8 var_idx, uint8 reg — SD変数(.urv) → レジスタ
3
0x26
VAR_STORE
uint8 var_idx, uint8 reg — レジスタ → SD変数(.urv)
3
0x27
VAR_LOAD_IDX
uint8 var_idx, uint8 idx_reg, uint8 reg — 配列要素 → レジスタ
4
0x28
VAR_STORE_IDX
uint8 var_idx, uint8 idx_reg, uint8 reg — レジスタ → 配列要素
4
0x29
TO_S
uint8 src_reg, uint8 var_idx — Q16.8 → 文字列変数(.urv)
3
0x2A
PWM_DUTY_REG
uint8 pin, uint8 reg — duty = レジスタ Q16.8 の整数部 (Q1 必須)
3
0x32
WARN_REG
uint8 reg — レジスタ生値(Q16.8 下位24bit)を DEVICE LOG へ送信(warn デバッグ出力・文字列化はブラウザ側。Q1+Sv 構成のみ Flash 不足のため非搭載 → puts/p で代替)
2
JMP/JZ/JNZ の offset は命令直後位置からの相対バイトオフセット (int16)。
レジスタ R0–R3 は int32_t。Q16.8 固定小数: 1.0=256, 0.5=128。
MUL_Q16 は int32 乗算 — 積が ±32768 未満まで正確(2026-07-12 以前のファームは int16 制限で ±128 以上のオペランドが壊れるバグあり。要再書き込み)。
UIAPruby API リファレンス

GPIO / PWM / I2C / その他

Ruby 記法変換後命令Phase
led = GPIO.new(2, GPIO::OUT)GPIO_MODE pin=2 OUTPUT1
button = GPIO.new(11, GPIO::IN | GPIO::PULL_UP)GPIO_MODE pin=11 INPUT_PULLUP1
led.on / led.high / led.write(1)GPIO_WRITE pin, 11
led.off / led.low / led.write(0)GPIO_WRITE pin, 01
led.toggleGPIO_TOGGLE pin1
buzzer = Tone.new(5)GPIO_MODE pin=5 OUTPUT1
buzzer.frequency(440)TONE_FREQ pin, 4401
buzzer.off / buzzer.frequency(0)TONE_FREQ pin, 01
buzzer.tone(440, 0.2)TONE_FREQ 440 → WAIT_MS 200 → TONE_FREQ 01
button.low? / button.high?GPIO_READ pin, R0 + JNZ/JZ2
sleep(0.2) / wait_ms(200)WAIT_MS 2001
wait_ms n * 100 / sleep(n) — 変数の時間待ちWAIT_MS_REG reg, 100(掛け算はファームウェア側)1
print / puts / p / putcPRINT_STR3
warn d / warn sonar.read — DEVICE LOG へデバッグ出力(Sv 不要。Q1+Sv 構成のみ使用不可)WARN_REG reg3
raise "msg" / raise unless condPRINT_STR + HALT4
def name … endインライン展開5
break / nextJMP loop_end / loop_start6
g = 0.1 * 0.5 / Q16.8 演算LOAD_Q16 + MUL_Q16 …7
if d < 15 — 比較演算(< > == >= <= !=)※Q1 必須CMP_LT/GT/EQ_Q16 + JZ/JNZQ1
case d / when 0, 10 — 値の列挙 ※Q1 必須CMP_EQ_Q16 + ジャンプ(OR 展開)Q1
when 0...15 / when 1..3 — レンジ ※Q1 必須CMP_LT/GT_Q16 ×2 + ジャンプ(範囲比較)Q1
f = ->(x) { x < 15 } — ラムダ式の定義コンパイル時登録(バイトコードなし)
f.call(d) / when f / when ->(x){…} — ラムダ呼び出し本体をインライン展開(下記参照)
require_relative "path"compile-time include8
motor = PWM.new(2)GPIO_MODE pin=2 OUTPUTPw
motor.frequency(500) — 基準周波数(省略時 1kHz)PWM_BASE_FREQ pin, 500Pw
motor.duty(255) — リテラル 0〜255PWM_DUTY pin, 255(即値)Pw
motor.duty(speed) — 変数 ※Q1 必須PWM_DUTY_REG pin, regPw
servo.angle(90) — リテラル 0〜180 ※要 frequency(50)(50Hz・0.5〜2.4ms、分解能約7°)PWM_DUTY pin, 19(コンパイル時計算)Pw
servo.angle(pos) — 変数 ※Q1 必須・要 frequency(50)Q16 演算 + PWM_DUTY_REG pin, regPw
sensor = ADC.new(0) ピン: 0,1,12,15,16 (初期化なし)Ad
puts sensor.read / print sensor.readADC_READ pin,R0 + PRINT_REGAd
sonar = Ultrasonic.new(3, 4) 第1引数=TRIG, 第2引数=ECHO(任意のGPIOピン)GPIO_MODE trig OUT + GPIO_MODE echo INUs
puts sonar.read / print sonar.readULTRASONIC_READ trig,echo,R0 + PRINT_REGUs
$count = $count + 1$変数は SD に永続保存 ※Q1 必須VAR_LOAD + ADD_Q16 + VAR_STOREVe
数値変数の3つ目以降(R0/R1 あふれ)— SD に自動配置 ※Q1 必須VAR_LOAD / VAR_STOREVe
数値配列 arr = Array.new(10) / arr[i]$付きで永続) ※Q1 必須VAR_LOAD_IDX / VAR_STORE_IDXVe
puts $count / puts g — 数値出力 ※数値変数は Q1 必須(デバッグなら warn が Ve だけで使える)VAR_LOAD + PRINT_REG / PRINT_REGSv
n = rand(6) — 0〜5 の整数RAND 0,6,RnRn
n = rand(1..6) — 1〜6 の整数RAND 1,7,RnRn
srand(42) — シード設定SRAND 42Rn

ラムダ式(コンパイル時インライン展開)

TinyVM にクロージャは存在しません。ラムダ式はコンパイル時に呼び出し位置へインライン展開され、 展開結果は通常の比較・演算命令になります(実行時オーバーヘッドなし・追加 Flash なし)。
使い方説明必要
near = ->(x) { x < 15 }定義。本体は式1つだけ。バイトコードは出力されない
case d
when near / when ->(x) { x < 15 }
case 対象 d が引数 x に渡り、本体が条件として展開されるQ1
if between.call(d, 5, 10)if / while / until / unless / 三項演算子の条件で使用可。複数引数・&& / || も OKQ1
y = double.call(n)数値式として使用(戻り値 = 本体の式の値)Q1
wait_ms half.call(500)引数がすべて定数ならコンパイル時に計算され、リテラルを書ける場所(sleep / servo.angle 等)ならどこでも使える
制約: 本体は式1つのみ(複文は不可)/引数は数値リテラル(定数式)または変数のみ/ 再帰呼び出し不可/デフォルト値・可変長・キーワード引数は不可。いずれもコンパイルエラーで案内されます。