サンプル:自動システム#
自動システム#
このサンプルは、自動システムの実装例です。Listで自動運転のプログラムを記述、コマンドの実行エンジンの実装例になっています。
編成のイベントハンドラーは、ユーザー定義ハンドラに統一。 ユーザー定義ハンドラは、イベント発生時にListに記述されたコマンドを解釈、実行します。
レイアウトスクリプトに、自動システムのコード、ユーザー定義ハンドラを記述。 レイアウトスクリプトは、ビュワー起動時に最初にPythonにロードされるため、ここに全体で利用するコードを記述します。
このサンプルのコードは、改変自由、発表自由、サポート対象外です。 また、最小構成の実装例のため、クラス、エラー対応、機能拡張、センサー対応など、このコードをベースに拡張してください。
サンプルは、先行編成と後続編成の2つの編成があります。後続編成は、3秒後の出発。先行編成に連結します。
先行編成は、Xキーで分割できます。3秒以内に分割した場合、後続編成は、生成された新しい編成に連結します。
また、Wキーでポイントを分岐側に切り替えます。
これらが、Listに記述した簡易コードで実行されます。
サンプルダウンロード#
ダウンロード後、zipファイルを展開してください。スターターキットの部品のみで構成しています。 システムバージョン 6.0.0.159以降で使用可能です。
コード解説#
コマンド定義#
レイアウトスクリプトで、コマンドを定数定義します。
1 2 3 4 5 6 7 8 9 10 11 12 | #コマンド 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に、パラメータを記述。イベント発生時は、そのパラメータで処理を行います。 連結イベントについては、実装例はすべての連結に対して、無条件で処理を行っています。 イベントに条件づけを行うなど工夫の余地があります。
この他、条件分岐などアイデア次第です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | #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にない数値の場合は、初期化コマンドは実行されません。
1 2 3 4 5 6 7 8 9 | #編成に自動運転を設定する 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) |
ユーザー定義ハンドラ#
ユーザー定義ハンドラの実装例です。
この実装例では、連結、分割イベントでログに記録しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | #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を割り当てます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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()を実行。 以降、すべての制御は、自動システム側に移ります。
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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に連結イベントが発生します。
実行例のログです。
1 2 3 4 5 6 | [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キーで先行編成を分割。生成された編成に後続が連結します。生成された編成で連結イベントが発生します。
実行例のログです。
1 2 3 4 5 6 7 8 9 10 11 | [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秒で連結しています。
1 2 3 4 5 6 7 8 | [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 |