コンテンツにスキップ

サンプル:自動システム#

自動システム#

自動システム

このサンプルは、自動システムの実装例です。Listで自動運転のプログラムを記述、コマンドの実行エンジンの実装例になっています。

編成のイベントハンドラーは、ユーザー定義ハンドラに統一。 ユーザー定義ハンドラは、イベント発生時にListに記述されたコマンドを解釈、実行します。

レイアウトスクリプトに、自動システムのコード、ユーザー定義ハンドラを記述。 レイアウトスクリプトは、ビュワー起動時に最初にPythonにロードされるため、ここに全体で利用するコードを記述します。

このサンプルのコードは、改変自由、発表自由、サポート対象外です。 また、最小構成の実装例のため、クラス、エラー対応、機能拡張、センサー対応など、このコードをベースに拡張してください。

自動システム

サンプルは、先行編成と後続編成の2つの編成があります。後続編成は、3秒後の出発。先行編成に連結します。

先行編成は、Xキーで分割できます。3秒以内に分割した場合、後続編成は、生成された新しい編成に連結します。

また、Wキーでポイントを分岐側に切り替えます。

これらが、Listに記述した簡易コードで実行されます。

サンプルダウンロード#

サンプルレイアウトをダウンロード

ダウンロード後、zipファイルを展開してください。スターターキットの部品のみで構成しています。 システムバージョン 6.0.0.159以降で使用可能です。

コード解説#

コマンド定義#

レイアウトスクリプトで、コマンドを定数定義します。


#コマンド
ADRV_TERM = 0
ADRV_KEYEVENT = 1
ADRV_SPLIT = 2
ADRV_AUTOSPEED = 3
ADRV_TIME = 4
ADRV_TIMER = 5
ADRV_AFTER = 6
ADRV_LOG = 7
ADRV_SETPOINT = 8
ADRV_COUPLE = 9
ADRV_LIST = 10

コマンドは、実装例になっています。イベントの対応、他の部品の制御など実装例を参考に拡張してください。

command guide
ADRV_TERM コマンド実行を終了
ADRV_KEYEVENT キー入力イベントを設定
ADRV_SPLIT 編成を分割します。生成された編成に新しいコマンドリストを割り当てます。
ADRV_AUTOSPEED 速度制御
ADRV_TIME 時間イベントの設定
ADRV_TIMER タイマーイベントの設定
ADRV_AFTER 時間経過イベントの設定
ADRV_LOG ログ
ADRV_SETPOINT ポイント操作。編成以外の部品操作の実装例
ADRV_COUPLE 連結イベントの設定
ADRV_LIST 別のコマンドリストを実行

エンジン#

自動システムのエンジン部分です。

自動システムは、[ステータス、命令、パラメータ]のリストを順次実行します。 現在ステータスに一致する命令を実行、ステータスを+1して、次に一致するステータスの命令を実行します。

ADRV_TERMが実行されると、一連の実行処理を終了します。

ADRV_AUTOSPEEDは、編成オブジェクトに対しての操作実装例です。

trainobj.AutoSpeedCTRL(cmd[2],cmd[3])

trainobjに対して、AutoSpeedCTRL関数をコール、引数は、cmdの#2、#3のデータを設定しています。 エラー処理は省略しています。cmdに設定されている値は、正しいものとします。

ADRV_KEYEVENTは、イベントの設定例です。 ここで設定したイベントは、ユーザー定義ハンドラのkeydownイベントでキャッチされます。

ADRV_SETPOINTは、外部部品操作の実装例です。 IDで部品オブジェクトを取得、オブジェクトに対して、操作します。

ADRV_COUPLEは、特殊イベントの実装例です。 オブジェクトのdictに、パラメータを記述。イベント発生時は、そのパラメータで処理を行います。 連結イベントについては、実装例はすべての連結に対して、無条件で処理を行っています。 イベントに条件づけを行うなど工夫の余地があります。

この他、条件分岐などアイデア次第です。


#exec_statusから実行する
def adrv_exec(trainobj,exec_status):
    dc = trainobj.GetDict()
    if ('adrv_cmdlist' in dc) == False:
        return
    #解析実行
    cmdlist = dc['adrv_cmdlist']
    for cmd in cmdlist:
        if cmd[0] == exec_status:
            dc['adrv_status'] = exec_status
            vrmapi.LOG("OBJID "+str(trainobj.GetID())+" -- CMD->" + str(cmd[1]) + "ST:" + str(exec_status))
            if cmd[1] == ADRV_TERM:
                return
            elif cmd[1] == ADRV_KEYEVENT:
                exec_status+=1
                #キー入力イベント設定
                #ADRV_KEYEVENT, keycode文字, キーを押したときのステータス
                trainobj.SetEventKeyDown(cmd[2],cmd[3])
            elif cmd[1] == ADRV_SPLIT:
                exec_status+=1
                #編成分割
                #ADRV_SPLIT,分割号車番号、分割で生成された編成の自動運転リスト,初期ステータス
                tid = trainobj.SplitTrain(cmd[2])
                nobj = vrmapi.LAYOUT().GetTrain(tid)
                adrv_init(nobj,cmd[3],cmd[4])
            elif cmd[1] == ADRV_AUTOSPEED:
                exec_status+=1
                #出発
                #ADRV_AUTOSPEED,dist,v
                trainobj.AutoSpeedCTRL(cmd[2],cmd[3])
            elif cmd[1] == ADRV_TIME:
                exec_status+=1
                #時間イベント設定
                #ADRV_TIME,発生時刻,発生後のスタータス
                trainobj.SetEventTime(cmd[2],cmd[3])
            elif cmd[1] == ADRV_TIMER:
                exec_status+=1
                #タイマーイベント設定
                #ADRV_TIMER,時間,発生後のスタータス
                trainobj.SetEventTimer(cmd[2],cmd[3])
            elif cmd[1] == ADRV_AFTER:
                exec_status+=1
                #時間経過イベント設定
                #ADRV_AFTER,時間,発生後のスタータス
                trainobj.SetEventAfter(cmd[2],cmd[3])
            elif cmd[1] == ADRV_LOG:
                exec_status+=1
                #ログを記録
                #ADRV_LOG,logtext
                vrmapi.LOG(cmd[2])
            elif cmd[1] == ADRV_SETPOINT:
                exec_status+=1
                #ポイントを操作
                #ADRV_SETPOINT,PointID,param
                pointobj = vrmapi.LAYOUT().GetPoint(cmd[2])
                pointobj.SetBranch(cmd[3])
            elif cmd[1] == ADRV_COUPLE:
                exec_status+=1
                #連結イベント
                #ADRV_COUPLE,event_status
                dc['adrv_couple'] = cmd[2]
            elif cmd[1] == ADRV_LIST:
                exec_status+=1
                #新しいコマンドリストを実行
                #ADRV_LIST,new_list,exec_status
                adrv_init(trainobj,cmd[2],cmd[3])

エンジン初期化#

SetUserEventFunction()でユーザー定義ハンドラを設定。

オブジェクトのdictに自動システムの変数を設定して、初期化コマンドを実行します。

init_statusが、Listにない数値の場合は、初期化コマンドは実行されません。


#編成に自動運転を設定する
def adrv_init(trainobj,cmdlist,init_status):
    #ユーザーハンドラに切り替える
    trainobj.SetUserEventFunction("vrmevent_usertrain")
    dc = trainobj.GetDict()
    dc['adrv_cmdlist'] = cmdlist
    dc['adrv_status'] = init_status
    dc['adrv_couple'] = 0
    adrv_exec(trainobj,init_status)

ユーザー定義ハンドラ#

ユーザー定義ハンドラの実装例です。

この実装例では、連結、分割イベントでログに記録しています。


#user定義ハンドラ        
def vrmevent_usertrain(obj,ev,param):
    if ev == 'init':
        vrmapi.LOG('USER INIT - '+str(obj.GetID()))
    elif ev == 'broadcast':
        dummy = 1
    elif ev == 'timer':
        adrv_exec(obj,param['eventUID'])
    elif ev == 'time':
        adrv_exec(obj,param['eventUID'])
    elif ev == 'after':
        adrv_exec(obj,param['eventUID'])
    elif ev == 'frame':
        dummy = 1
    elif ev == 'couple':
        vrmapi.LOG('CODE HANDLER  userhander')
        vrmapi.LOG('*連結event - '+str(obj.GetID()))
        vrmapi.LOG('消滅編成ID = '+str(param['delid']))
        #連結イベント実行
        dc = obj.GetDict()
        if 'adrv_couple' in dc:
            adrv_exec(obj,dc['adrv_couple'])
    elif ev == 'split':
        vrmapi.LOG('CODE HANDLER  userhander')
        vrmapi.LOG('*分割event - '+str(obj.GetID()))
        vrmapi.LOG('新規編成ID = '+str(param['newid']))
        vrmapi.LOG('成功フラグ = '+str(param['live']))
        #通常は、新規編成には分割元のスクリプトがコピーされる
        #ここで新規編成もユーザーハンドラに変更する
        if param['live'] == 1:
            newobj = vrmapi.LAYOUT().GetTrain(param['newid'])
            newobj.SetUserEventFunction("vrmevent_usertrain")
    elif ev == 'start':
        dummy = 1
    elif ev == 'stop':
        dummy = 1
    elif ev == 'autospeed':
        dummy = 1
    elif ev == 'delete':
        dummy = 1
    elif ev == 'create':
        dummy = 1
    elif ev == 'homekey':
        dummy = 1
    elif ev == 'endkey':
        dummy = 1
    elif ev == 'insertkey':
        dummy = 1
    elif ev == 'spacekey':
        dummy = 1
    elif ev == 'active':
        dummy = 1
    elif ev == 'view':
        dummy = 1
    elif ev == 'keydown':
        adrv_exec(obj,param['eventUID'])

先行編成#

ID=7の編成の実装例です。

autolist7に編成のコマンドを記述しています。

また、autolistNTに分割で生成される編成のコマンドを記述しています。

標準のイベントハンドラでは、initでadrv_init()を実行。 以降、すべての制御は、自動システム側に移ります。

autolist7は、初期化で100から実行。キーイベントの設定などを行っています。

Xキー入力で、1000から実行。編成を分割、新しい編成にautolistNTを割り当てます。


autolistNT = [
[100,ADRV_LOG,"*** 新規編成START ***"],
[101,ADRV_COUPLE,400],
[102,ADRV_TERM],
#couple
[400,ADRV_LOG,"+++ 連結イベント実行 NT編成"],
[401,ADRV_TERM]
]

autolist7 = [
[100,ADRV_KEYEVENT,'X',1000],
[101,ADRV_KEYEVENT,'W',3000],
[102,ADRV_COUPLE,200],
[103,ADRV_TERM],
#couple
[200,ADRV_LOG,"+++ 連結イベント実行 7編成"],
[201,ADRV_TERM],
# x key
[1000,ADRV_SPLIT,1,autolistNT,100],
[1001,ADRV_LOG,"*** 編成分割 ***"],
[1002,ADRV_TERM],
# y key
[3000,ADRV_SETPOINT, 10, 1],
[3001,ADRV_LOG,"*** ポイント変更"],
[3002,ADRV_TERM]
]


def vrmevent_7(obj,ev,param):
    if ev == 'init':
        vrmapi.LOG('INIT - '+str(obj.GetID()))
        adrv_init(obj,autolist7,100)


後続編成#

ID=9の編成の実装例です。

autolist9に編成のコマンドを記述しています。

3秒後にAfterイベントを発生、イベント発生時は、ステータス500から実行します。

ステータス500では、100mmで電圧0.2を目標に自動運転を開始します。

標準のイベントハンドラでは、initでadrv_init()を実行。 以降、すべての制御は、自動システム側に移ります。


autolist9 = [
#init
[100,ADRV_AFTER,3,500],
[101,ADRV_TERM],
#after
[500,ADRV_AUTOSPEED,100,0.2],
[501,ADRV_TERM]
]

def vrmevent_9(obj,ev,param):
    if ev == 'init':
        vrmapi.LOG('INIT - '+str(obj.GetID()))
        adrv_init(obj,autolist9,100)

実行例#

先行編成に後続編成が連結した場合。

ビュワー起動後、3秒で後続編成9が出発、先行編成7に連結します。連結で、停車中の先行編成7に連結イベントが発生します。

実行例のログです。


[2020/5/21 8:48:5][10.549891ns : ID 0] : string : CODE HANDLER  userhander
[2020/5/21 8:48:5][10.549891ns : ID 0] : string : *連結event - 7
[2020/5/21 8:48:5][10.549891ns : ID 0] : string : 消滅編成ID = 9
[2020/5/21 8:48:5][10.549891ns : ID 0] : string : OBJID 7 -- CMD->7ST:200
[2020/5/21 8:48:5][10.549891ns : ID 0] : string : +++ 連結イベント実行 7編成
[2020/5/21 8:48:5][10.549891ns : ID 0] : string : OBJID 7 -- CMD->0ST:201

先行編成を分割、新規編成に後続編成が連結した場合。

ビュワー起動後、Xキーで先行編成を分割。生成された編成に後続が連結します。生成された編成で連結イベントが発生します。

実行例のログです。


[2020/5/21 8:49:5][1.363807ns : ID 0] : string : CODE HANDLER  userhander
[2020/5/21 8:49:5][1.363807ns : ID 0] : string : *分割event - 7
[2020/5/21 8:49:5][1.363807ns : ID 0] : string : 新規編成ID = 1073741824
[2020/5/21 8:49:5][1.363807ns : ID 0] : string : 成功フラグ = 1
[2020/5/21 8:49:5][1.363807ns : ID 0] : string : OBJID 1073741824 -- CMD->7ST:100
[2020/5/21 8:49:5][1.363807ns : ID 0] : string : *** 新規編成START ***
[2020/5/21 8:49:5][1.363807ns : ID 0] : string : OBJID 1073741824 -- CMD->9ST:101
[2020/5/21 8:49:5][1.363807ns : ID 0] : string : OBJID 1073741824 -- CMD->0ST:102
[2020/5/21 8:49:5][1.363807ns : ID 0] : string : OBJID 7 -- CMD->7ST:1001
[2020/5/21 8:49:5][1.363807ns : ID 0] : string : *** 編成分割 ***
[2020/5/21 8:49:5][1.363807ns : ID 0] : string : OBJID 7 -- CMD->0ST:1002

3秒で後続が出発、10秒で連結しています。


[2020/5/21 8:49:7][3.015129ns : ID 0] : string : OBJID 9 -- CMD->3ST:500
[2020/5/21 8:49:7][3.015129ns : ID 0] : string : OBJID 9 -- CMD->0ST:501
[2020/5/21 8:49:15][10.554655ns : ID 0] : string : CODE HANDLER  userhander
[2020/5/21 8:49:15][10.554655ns : ID 0] : string : *連結event - 1073741824
[2020/5/21 8:49:15][10.554655ns : ID 0] : string : 消滅編成ID = 9
[2020/5/21 8:49:15][10.554655ns : ID 0] : string : OBJID 1073741824 -- CMD->7ST:400
[2020/5/21 8:49:15][10.554655ns : ID 0] : string : +++ 連結イベント実行 NT編成
[2020/5/21 8:49:15][10.554655ns : ID 0] : string : OBJID 1073741824 -- CMD->0ST:401