R-BASIC 入門・実践チュートリアル

このチュートリアルでは、自律建築ロボットを制御するスクリプト言語 R-BASIC (Robot BASIC) の書き方を、基礎から実践的な複数台協調プログラミングまでステップ形式で解説します。


0. はじめに: R-BASIC の世界

Robot Building Simulator (RBS) のロボットたちは、R-BASIC スクリプトによって思考し、自律的に材料を運んで巨大な建造物を組み上げます。

画面上での確認方法

最も重要な原則: 1 Tick = 1 アクション

R-BASIC は、ロボットが 物理アクション(動く・拾う・置くなど)を 1 回行うごとに 1 Tick(シミュレーションの1コマ)を消費 します。 計算や条件判定、ジャンプなどの非物理命令は、同一 Tick 内で瞬時に実行されます。


Step 1: はじめてのロボットプログラミング(前進と旋回)

まずは、前進と旋回を繰り返して四角形に巡回する最もシンプルなコードを書いてみましょう。

; 四角形巡回パトロール
*loop
    step
    step
    step
    turn RIGHT
    goto *loop

コードの解説:

  1. *loop: ラベルです。ジャンプの目印になります。
  2. step: 正面に向かって 1 歩前進します(1 Tick 消費)。
  3. turn RIGHT: 右(時計回りに90度)を向きます(1 Tick 消費)。
  4. 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

ポイント:


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

ポイント:


Step 4: 自律探索と移動 (find と go)

マップが広くなると、自力で歩き回って材料を探すのは大変です。そこで便利なのが find と go です。

標準建築ロボット (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


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

Step 8: マーカーを活用した協調作業

マップ上に Marker ツールでマーカー(赤コーン、青キューブ等)を設置すると、ロボットはそれを道しるべや集合場所として認識できます。

例: 作業完了後に赤コーン(待機所)へ帰還する

*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) エラーが出る

2. ロボットがその場で空回り・停止する

3. [P] キーオーバーレイを活用する

座標を記憶して移動する

デバッグには 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 で柱を建築します。