4/15(火)~17(木) 第5回量子コンピューティングEXPO春(東京ビッグサイト)に共同出展します☆彡
量子アニーリング

New!! Pythonでプラレールのシミュレータを作る

AI要約

プラレールの制御に向け、Pythonで簡易的なシミュレータを開発しました。レール配置や車両の挙動を仮想空間で再現し、動作テストの基盤を整えました。実機に触れずに動作検証ができ、開発の効率化に貢献します。

やること

前回、マイクロサーボでターンアウトレールのポイント切り替えを行いました。

これから車両の制御をやっていきたいのですが、何をやるにもまずはシミュレータが必要です。今回はプラレールの簡易的なシミュレータを作ってみます。

参考文献

こちらのサイトでプラレールの様々なレイアウトが公開されています。見ているだけで楽しいですね!

プラレール レイアウト・コツの紹介で、お父さんお母さんを徹底サポートします! - 青いレール.com(プラレールレイアウト)
弊サイト(青いレール.com)へお越しいただき誠にありがとうございます。 管理運営者の「あい」です。 肩書的には「プラレータ」(プラレールオペレータ)を名乗っています。 このサイトは 「プラレールのつ...

テストコース

このようなコースを考えます。

次のようにIDを割り当てました。

電車を遷移させていくため、有向グラフとしてパスを定義します。

#パスの定義
path = {0:1, 1:2, 2:3, 3:4, 4:5, 5:6, 6:7, 7:[8, 14], 8:[9, 20], 9:10, 10:11, 11:12, 12:13, 13:0,
        14:15, 15:16, 16:17, 17:18, 18:19, 19:6, 20:21, 21:13}

#分岐の状態
switch = {7:0, 8:0}

#線路の座標、可視化のため
xy_set = {0:[30, 0], 1:[20, 0], 2:[10, 0], 3:[5, 7], 4:[5, 13], 5:[10, 20], 6:[20, 20], 7:[30, 20],
          8:[40, 20], 9:[50, 20], 10:[55, 13], 11:[55, 7], 12:[50, 0], 13:[40, 0], 14:[35, 27],
          15:[35, 33], 16:[30, 40], 17:[20, 40], 18:[15, 33], 19:[15, 27], 20:[45, 13], 21:[45, 7]}

分岐の状態は「0=直進」「1=曲がる」です。各レールの座標は後で可視化のために使うので本質的には不要です。

電車クラス

電車クラスを作っておき、3台走らせるなら3インスタンス立ち上げるようにすると良いと思います。train1.pos のように電車1の位置を取得できてシンプルです。

#電車のクラス
class TrainClass:
    def __init__(self, name='a', speed=0.2, pos=0, color='yellow'):
        self.name = name
        self.speed = speed
        self.pos = pos
        self.color = color
        
        #レール進行率
        self.progress = 0.0
    
    #1フレーム進める
    def move(self):
        
        #レール進行率を加算
        self.progress += self.speed
        
        #次のレールに移った場合
        if self.progress >= 1.0:
            self.progress = self.progress - 1.0
            #分岐からの遷移なら
            if self.pos in switch.keys():
                s = switch[self.pos]
                self.pos = path[self.pos][s]
            #そうでないなら
            else:
                self.pos = path[self.pos]
        #まだこのレールにいる場合
        else:
            pass

電車は「どのレールに乗っているか」「レールの中で何%進行したか」という2つの値で位置情報を持っています。そして、電車のスピードは「1フレームで何%進行するか」を意味しています。

例えば、スピード0.17の電車がレール0の0.9(90%)にいる場合、次のフレームではレール1の0.07(7%)に移ります。(伝われ)

カラーと名前は可視化のために用意しています。

試しに電車を作って10フレーム進めてみましょう。

train1 = TrainClass(name='a', speed=0.17, pos=0, color='yellow')
print(train1.pos, train1.progress)

for i in range(10):
    train1.move()
    print(train1.pos, train1.progress)
0 0.0
0 0.17
0 0.34
0 0.51
0 0.68
0 0.85
1 0.02
1 0.19
1 0.36
1 0.53
1 0.7

いい感じですね。

可視化関数

レールと電車の状態を可視化する関数を作ります。これはどこまでこだわるかによります。テクニック的なことで何か言うとすれば、ax.set_aspect(‘equal’) は座標軸を1:1のアスペクト比にしてくれるので便利です(マス目が正方形になるという意味、伝われ)。

import matplotlib.pyplot as plt

#可視化関数
def show(time=0):
    fig = plt.figure(figsize=(8, 8))
    ax = plt.axes()
    #パス
    for i, (key, value) in enumerate(path.items()):
        if type(value) is list:
            for v in value:
                plt.plot([xy_set[key][0], xy_set[v][0]], [xy_set[key][1], xy_set[v][1]], '-', color='gray')
        else:
            plt.plot([xy_set[key][0], xy_set[value][0]], [xy_set[key][1], xy_set[value][1]], '-', color='gray')
    #レール
    for i, (key, value) in enumerate(xy_set.items()):
        x, y = value
        plt.plot(x, y, 'o', color='w', mec ='k', markersize=20)
        plt.text(x + 1.4, y + 0.6, f'{key}')
    #分岐の状態
    for i, (key, value) in enumerate(switch.items()):
        plt.text(xy_set[key][0] + 1.6, xy_set[key][1] - 1.8, f'to {path[key][value]}')
    #電車
    for train in trains:
        x, y = xy_set[train.pos]
        plt.plot(x, y, 'o', color=train.color, mec ='k', markersize=20)
        plt.text(x - 0.4, y - 0.4, f'{train.name}')
    plt.title(f'time = {time}')
    ax.set_aspect('equal')
    plt.xlim(0, 60)
    plt.ylim(-5, 45)
    plt.show()
    plt.close()

複数の電車を配列に入れることを想定して作ってしまったので、1台でも配列に入れる必要があります。動作を確認してみましょう。

#電車の作成
trains = []
trains.append(TrainClass(name='a', speed=0.17, pos=0, color='yellow'))

#確認
show(time=0)

#シミュレーション開始
for i in range(1, 100):
    
    #電車を進める
    for train in trains:
        train.move()
    
    #確認
    show(time=i)

良さそうですね。

3台の電車

3台で走らせてみましょう。

#電車の作成
trains = []
trains.append(TrainClass(name='a', speed=0.17, pos=0, color='yellow'))
trains.append(TrainClass(name='b', speed=0.23, pos=4, color='orange'))
trains.append(TrainClass(name='c', speed=0.41, pos=19, color='green'))

良さそうですが、電車ぶつかってすり抜けています。

衝突判定

衝突判定を追加しましょう。同じレールに複数の電車が乗ったら「Crash!!」と表示して終了させます。set() を使った重複判定が便利ですね。

#シミュレーション開始
for i in range(1, 100):
    
    #電車を進める
    for train in trains:
        train.move()
    
    #確認
    show(time=i)
    
    #衝突チェック
    all_pos = [train.pos for train in trains]
    #重複があれば衝突なので終了
    if len(all_pos) != len(set(all_pos)):
        print('Crash!!')
        break

35フレーム目で衝突して終わりました。いい感じです!

おわりに

分岐はずっと直進でやりましたが、曲がることもできるので試してみてください。

次回に続きます。

リアクションのお願い

「参考になった!」「刺激された!」と思ったらぜひリアクションをしましょう。エンジニアの世界はGive and Takeによって成り立っています。これからも無料で良質な情報にアクセスできるよう、Giveする人への感謝をリアクションで示しましょう!

この記事をシェアする

自身のブログ等で使用する場合は引用を忘れずに!

また、寄付も受け付けています。コーヒー1杯でとても喜びます(*˘︶˘*)

 Amazonでギフト券(アマギフ)を贈る

こちらのリンク から金額を指定してお贈りください。(デフォルトで10000円になっているのでご変更ください)

配送:Eメール
受取人:staffあっとvigne-cla.com
贈り主:あなたのお名前やニックネーム
メッセージ:◯◯の記事が参考になりました。など

のようにご入力ください。見返りはありませんのでご了承ください。

 Amazonで食事券(すかいらーく優待券)を贈る

500円 1000円 2000円 5000円 からお贈りください。

配送:Eメール
受取人:staffあっとvigne-cla.com
贈り主:あなたのお名前やニックネーム
メッセージ:◯◯の記事が参考になりました。など

のようにご入力ください。見返りはありませんのでご了承ください。

 その他、ギフト券やクーポン券をメールで贈る

デジタルのギフト券/クーポン券はメールアドレス(staffあっとvigne-cla.com)までお送りください。受領の返信をいたします。
紙のギフト券/クーポン券は 「郵便物はこちらへ」の住所 まで送付してください。名刺やメールアドレスを同封していただければ受領の連絡をいたします。
余った株主優待券等の処理におすすめです。
いずれも見返りはありませんのでご了承ください。

不明点はSNSでお気軽にご連絡ください

ビネクラのTwitter・Youtubeでコメントをください!


Slack・Discordの場合はこちらの公開グループに参加してShoya YasudaまでDMをください!


※当ブログに関することは何でもご相談・ご依頼可能です。

この記事を書いた人
Yasuda

博士(理学)。専門は免疫細胞、数理モデル、シミュレーション。米国、中国で研究に携わった。遺伝的アルゴリズム信者。物価上昇のため半額弁当とともに絶滅寸前。

タイトルとURLをコピーしました