R-BASIC 入門・実践チュートリアル
このチュートリアルでは、自律建築ロボットを制御するスクリプト言語 R-BASIC (Robot BASIC) の書き方を、基礎から実践的な複数台協調プログラミングまでステップ形式で解説します。
0. はじめに: R-BASIC の世界
Robot Building Simulator (RBS) のロボットたちは、R-BASIC スクリプトによって思考し、自律的に材料を運んで巨大な建造物を組み上げます。
画面上での確認方法
- プログラムオーバーレイ ([P] キー): 3Dビュー上でロボットを選択し、キーボードの
[P]を押すと、現在実行中の R-BASIC ソースコードが表示されます。黄色くハイライトされている行が、直前に実行されたアクションです。 - プログラムエディタ: 画面右上の
[Program Editor]ボタンをクリックすると、全32スロットのプログラムの作成・編集・インポート・エクスポート・ロボットへの割り当てが行えます。
最も重要な原則: 1 Tick = 1 アクション
R-BASIC は、ロボットが 物理アクション(動く・拾う・置くなど)を 1 回行うごとに 1 Tick(シミュレーションの1コマ)を消費 します。 計算や条件判定、ジャンプなどの非物理命令は、同一 Tick 内で瞬時に実行されます。
Step 1: はじめてのロボットプログラミング(前進と旋回)
まずは、前進と旋回を繰り返して四角形に巡回する最もシンプルなコードを書いてみましょう。
; 四角形巡回パトロール
*loop
step
step
step
turn RIGHT
goto *loop
コードの解説:
*loop: ラベルです。ジャンプの目印になります。step: 正面に向かって 1 歩前進します(1 Tick 消費)。turn RIGHT: 右(時計回りに90度)を向きます(1 Tick 消費)。goto *loop:*loopラベルの位置へ戻ります。
3歩進んで右を向く動作を繰り返すことで、ロボットはその場を正方形にパトロールし続けます。
Step 2: 目の前を調べるセンシング (check と if)
目の前にブロックがあるか、空き空間かを調べて障害物を回避してみましょう。
; 障害物回避パトロール
*start
; 正面が空き空間 (EMPTY) なら前進
if check(FRONT) == EMPTY then goto *forward
; 正面が塞がっていたら右を向く
turn RIGHT
goto *start
*forward
step
goto *start
ポイント:
check(FRONT): ロボットの正面のセルの状態を返します(EMPTY: 空き、MATERIAL: 材料、ORDER: 建築指示、など)。if <条件> then <文> [else <文>]: 条件に応じてgoto、gosub、ロボット命令などの1文を実行します。- これにより、ロボットは壁や障害物にぶつからずに自動で曲がるようになります。
Step 3: 材料を拾って運ぶ (get と put)
ロボット建築の基本サイクルは、「手ぶらなら材料を拾い、持っていれば現場へ運んで置く」 です。
手持ちの状態は carrying 変数で確認できます。
; 資材運びの基本ステートマシン
*start
; 手に材料を持っていなければ取得処理へ
if carrying == NONE then goto *fetch
*place
; 目の前が建築指示 (ORDER) なら投入
if check(FRONT) == ORDER then goto *do_put
turn RIGHT
goto *start
*do_put
put
goto *start
*fetch
; 目の前が材料スタック (MATERIAL) なら拾う
if check(FRONT) == MATERIAL then goto *do_get
turn RIGHT
goto *start
*do_get
get
goto *start
ポイント:
carrying: 手に持っている材料の種別を表します(何も持っていなければNONE)。get: 目の前の材料スタックから 1 ユニットを拾い上げます。put: 手持ちの材料を目の前の建築指示(または地面)に投入します。
Step 4: 自律探索と移動 (find と go)
マップが広くなると、自力で歩き回って材料を探すのは大変です。そこで便利なのが find と go です。
find(<対象>): マップ上にある最寄りの対象物(最短経路)を自動検索し、ロボットのナビゲーションにロックします(見つかれば 1、見つからなければ 0 を返します)。go: ロックされた対象に向かって最短経路で 1 歩進みます。
標準建築ロボット (default.bas) の完成形
ゲームに初期同梱されている default.bas は、この find と go をフル活用して作られています。
; ==============================================================================
; R-BASIC: 汎用割り当て建築ロボット (default.bas)
; ==============================================================================
*start
; 材料を持っていれば建築現場へ
if carrying != NONE then goto *do_put
*do_get
; 目の前に担当材料があれば拾う
if check(FRONT) == MATERIAL && material(FRONT) == assigned_mat then goto *take
; 担当材料が見つかればそちらへ歩く
if find(assigned_mat) then goto *walk
; 見当たらなければ旋回して周囲を探す
turn RIGHT
goto *start
*take
get
goto *start
*do_put
; 目の前に担当部材の指示があれば設置
if check(FRONT) == ORDER && order(FRONT) == assigned_part then goto *place
; 担当部材の現場が見つかればそちらへ歩く
if find(assigned_part) then goto *walk
; 見当たらなければ旋回
turn RIGHT
goto *start
*place
put
goto *start
*walk
go
goto *start
assigned_mat と assigned_part
assigned_mat: UI右側のパネルでロボットごとに設定された「担当材料」(HEAVYやBALANCEDなど)が入っています。assigned_part: 同様に設定された「担当部材」(PILLAR,FLOOR,STAIR,WALLなど)が入っています。 これらを使うことで、スクリプトを書き換えずにUI操作だけで各ロボットの役割を変更できます。
Step 5: 変数と計算で作業数をカウントする
R-BASIC では、アルファベットで始まる任意の名前を変数として自由に使えます。
; 柱を 5 本分(計20ユニット)材料を運んだら終了する
*init
total_delivered = 0
*loop
if carrying == NONE then goto *fetch
*deliver
if check(FRONT) == ORDER then goto *put_mat
if find(PILLAR) then goto *walk
turn RIGHT
goto *loop
*put_mat
put
total_delivered = total_delivered + 1
print total_delivered
; 20ユニット設置完了したら待機
if total_delivered >= 20 then goto *finish
goto *loop
*fetch
if check(FRONT) == MATERIAL then goto *grab
if find(HEAVY) then goto *walk
turn RIGHT
goto *loop
*grab
get
goto *loop
*walk
go
goto *loop
*finish
print 9999 ; 完了シグナル
end ; ロボットをスリープ停止
print <式> の活用
print 命令を実行すると、ロボットの内部ログ(UIの Robot Logs に直近20行表示)に出力され、3Dビュー上のロボット頭上にもフキダシとして表示されます。数値だけでなく文字列や計算結果の連結も表示できるため、状態の把握やデバッグに最適です。
Step 6: メモリー配列 (mem[]) によるマルチタスク
R-BASIC には、mem[0] 〜 mem[63] の メモリー配列(0〜63番の番号がついた共通の記録スペース)が用意されています。
変数と同じように数値を代入・参照できますが、「番号(添字)を使って管理できる」ため、作業フェーズの切り替えや複数データの記録・集計にとても便利です。
たとえば、「第1段階として柱を4本建て、第2段階として床を張り、第3段階として階段を作る」といった一連の工程を、メモリー番号で管理してみましょう。
; 工程管理ロボット
; mem[0]: 現在のフェーズ (0:柱, 1:床, 2:階段)
; mem[1]: 設置完了カウント
*init
mem[0] = 0
mem[1] = 0
*loop
; 現在のフェーズに応じた目標部材を決定
phase = mem[0]
target_part = PILLAR
target_mat = HEAVY
if phase == 1 then target_part = FLOOR
if phase == 1 then target_mat = BALANCED
if phase == 2 then target_part = STAIR
if phase == 2 then target_mat = TENSILE
if carrying != NONE then goto *building
*fetching
if check(FRONT) == MATERIAL && material(FRONT) == target_mat then goto *grab
if find(target_mat) then goto *walk
turn RIGHT
goto *loop
*grab
get
goto *loop
*building
if check(FRONT) == ORDER && order(FRONT) == target_part then goto *build
if find(target_part) then goto *walk
turn RIGHT
goto *loop
*build
put
mem[1] = mem[1] + 1
print mem[1]
; 柱4本(16ユニット)完了でフェーズ1(床)へ
if phase == 0 && mem[1] >= 16 {
mem[0] = 1
mem[1] = 0
}
; 床8枚(16ユニット)完了でフェーズ2(階段)へ
if phase == 1 && mem[1] >= 16 {
mem[0] = 2
mem[1] = 0
}
goto *loop
*walk
go
goto *loop
Step 7: サブルーチン (gosub と return)
よく使う共通処理は、サブルーチンにまとめることでコードの見通しが良くなります。
*main
gosub *step_three
turn RIGHT
gosub *step_three
turn RIGHT
goto *main
; --- サブルーチン: 3歩進む ---
*step_three
step
step
step
return
gosub <ラベル>: 戻り先を記録してジャンプします。return: 呼び出し元の直後の命令に戻ります。- コールスタックは最大 128 段までネスト可能です。
Step 8: マーカーを活用した協調作業
マップ上に Marker ツールでマーカー(赤コーン、青キューブ等)を設置すると、ロボットはそれを道しるべや集合場所として認識できます。
find(MARKER): 最寄りのマーカーを探してロックします。marker(FRONT): 正面にあるマーカーの形状番号を取得します。MK_RED_CONE(1)MK_BLUE_CUBE(2)MK_GREEN_SPHERE(3)MK_YELLOW_DIAMOND(4)MK_PURPLE_CYLINDER(5)
例: 作業完了後に赤コーン(待機所)へ帰還する
*rest_area
; 赤コーンの前に着いたら待機
if check(FRONT) == MARKER && marker(FRONT) == MK_RED_CONE then goto *sleep
if find(MARKER) then goto *walk
turn RIGHT
goto *rest_area
*walk
go
goto *rest_area
*sleep
wait
goto *sleep
よくあるトラブルとデバッグのコツ
1. Instruction limit reached (500) エラーが出る
- 原因: 1 Tick の間にアクション命令(
step,turn,get,put,go,wait)を一度も実行せず、計算やgotoだけの無限ループに陥っています。 - 対処: 探す対象が見つからなかった分岐などに
waitやturn RIGHTを追加して、必ず毎 Tick 物理アクションを実行するようにしてください。
2. ロボットがその場で空回り・停止する
- 原因: 手持ちの材料(例:
LIGHT)と、現場が求めている材料(例:HEAVY)が一致していない場合、putが失敗します。 - 対処:
carryingやmaterial(FRONT)の条件判定を見直すか、地面にputして手持ちを一旦空にするロジックを検討してください。
3. [P] キーオーバーレイを活用する
- 3Dビューでロボットをクリックし、
[P]キーを押すと、プログラムの実行行がリアルタイムに表示されます。 - ロボットがどのステート(
*do_get,*do_put,*walkなど)で止まっているかをひと目で特定できます。
座標を記憶して移動する
デバッグには print で説明文と値を連結できます。実行ログとロボット頭上に表示され、Pauseすると頭上の表示時間も止まります。
print "位置=(" + pos_x + "," + pos_y + "," + pos_z + ")"
print "次の工程=" + (mem[0] + 1)
print "所持数=" + units
"値=" + 1 + 2 は 値=12 になります。数値として足したい部分は (1 + 2) のように括弧で囲んでください。文字列変数は使わず、文字列はprint内に直接書きます。頭上には最新1件を3秒間表示し、長文は省略します。過去の出力はプログラムダイアログのログで確認できます。
find成功後の target_x/y/z は対象物の座標、dest_x/y/z はロボットが立つ作業位置です。
if find(HEAVY) then goto *remember
end
*remember
mem[0] = target_x
mem[1] = target_y
mem[2] = target_z
if target_at(mem[0], mem[1], mem[2]) then goto *walk
end
*walk
go
if go_result == GO_MOVED then goto *walk
if go_result == GO_FAILED then goto *failed
if material(FRONT) == HEAVY then goto *take
goto *failed
*take
get
end
*failed
wait
end
対象物のない待機地点なら ok = move_to(4, 6, pos_z) を使い、成功後に同じgoループで移動します。関数を毎歩呼び直すと探索コストが増えるため、設定は移動開始時だけにします。
座標指定失敗は古い目標も解除します。find失敗は古い目標を残すため、必ず戻り値を確認します。移動先が現在位置なら最初のgoで到着します。
実行可能なマップサンプルは hsp/data/map/test-rbasic-navigation.txt です。CLIでは hsp3cl hsp/sim_cli.ax hsp/data/map/test-rbasic-navigation.txt 120 で柱を建築します。