2005/9/18

目指せ完全自動運転(10)−出発進行  VRMスクリプト禅問答
難易度:☆☆☆☆☆

まずは、前回紹介したメソッドStdMtdStationStop内のSetEventAfter命令の頭についているコメント記号(//)を削除してください。続いて、以下のスクリプトを編成スクリプトに加えます。
[編成スクリプト]
//
//出発進行待ちメソッド
//
BeginFunc MtdWaitDeparture
Var TmpSignal
Var TmpSpeed
//現在速度を評価
GetCurrentSpeed TmpSpeed
ifzero TmpSpeed
//信号灯火色を取得
mov TmpSignal StdObjSignal.StdVarSignalPosition
ifeq TmpSignal 1
//R現示の場合、このメソッドを再度タイマー登録
SetEventAfter this MtdWaitRestart TimerID 1000
else
//出発進行
ifeq VarActive 1
DrawMessage "「出発進行!!」"
endif
ifeq VarAutoMode 1
mov VarTargetSpeed VarSpeedY
call this MtdChangeSpeed
endif
endif
else
//信号無視に対する処理はここへ
endif
EndFunc
このメソッドはStdMtdStationStopが列車を3秒で止める=SetTimerVoltage 0.0 3000を実行してから5秒後=SetEventAfter this MtdWaitDeparture TimerID 5000、に初めて実行されます。つまり、その時点で列車は停止位置で停車しているはずです。5-3=2秒の差は、最低でも2秒間は止まるように設けた余裕です。
これ以降、ifeq TmpSignal 1 が成立する=信号がR現示である限り、1秒ごとに実行され続けます。これが、信号待ちに当たることは、以前紹介した閉塞信号からの再出発待ちメソッドとの対比でご理解いただけると思います。ここで評価対象になる信号機は、前回紹介した「停止用センサースクリプト」の中で編成オブジェクトに引き渡されています。後は、出発信号をG現示にしてやれば、列車は自動的に出発します。

出発信号をG現示に遷移させるのは停止用センサーの仕事になります。まずは、出発信号として二灯式信号機を停車位置の運転台視点から見える場所(でないと意味がないよね?)に設置し、以下に紹介するスクリプトを組み込みます。合わせて、前回紹介した停止用センサーのメソッドMtdStopTrainにもコメントアウトしたSetEventAfter命令がありますね。このコメントを外し、以下のスクリプトを組み込んでください。
[信号スクリプト]
//公開プロパティ
Var StdVarSignalPosition
//初期状態
call this StdMtdSignalR
//
//R現示メソッド
//
BeginFunc StdMtdSignalR
set StdVarSignalPosition 1
SetSignal StdVarSignalPosition
EndFunc
//
//G現示メソッド
//
BeginFunc StdMtdSignalG
set StdVarSignalPosition 6
SetSignal StdVarSignalPosition
EndFunc

[停止用センサースクリプト]
//前方の閉塞信号
VarSignal ObjChkSignal
get ObjChkSignal "{駅を出て最初の閉塞信号名}"
//
//G現示待ちメソッド
//
BeginFunc MtdWaitSignalG
Var TmpSignal
mov TmpSignal ObjChkSignal.StdVarSignalPosition
//前方の閉塞信号がG現示であれば出発信号をG現示に
ifeq TmpSignal 6
call ObjPartnerSignal StdMtdSignalG
//そうでなければもう1000ミリ秒待つ
else
SetEventAfter this MtdWaitSignalG TimerID 1000
endif
EndFunc
出発信号をG現示にしてよい条件というのは、レイアウトのトラックプランに依存する話でもあるので一概には言えませんが、ここでは最もシンプルなケースを例として取り上げてみました。
すなわち@列車が停車してから規定の停車時間が経過した、A前方の閉塞が開放されている=先行列車に追いつくことはない、というのが、ここで示したサンプルコードの意味になります。
@は前回示した停止用センサーのメソッドMtdStopTrainのSetEventAfter命令が制御しています。{停車時間+3000}としたのがそれです。ここで3000を加えているのは、停車センサーを列車が踏んでから本当に停止するまでに3000ミリ秒の間があるからですね。
前回、前々回と「減速用センサーと停止用センサーの二段階に分けるのは何故か」という疑問を持ち越してきましたが、その理由がこの方式です。減速用センサーを踏んでから列車が停止位置に至るまでの所要時間は、列車の進入速度によって変わってしまいます。現行のSetEventAfter命令は時間の引数に直値を要求するので、このような変化する値(駅停車時間+進入から停車までの時間)を動的に入れることができません。二段階方式にすると、停車用センサーを踏んでから列車が停止位置に至るまでの所要時間が固定されるので、{停車時間+3000}というような指定が可能になるワケです。

※ SetEventTimerを使ってスクリプトで自前のタイマーを回す、という手もあるが複雑になるので今回は割愛。なお、編成毎に停車時間を変えたいのであれば、MtdStopTrainの中で検知編成の列車種別を示す公開プロパティを取得し、それによる分岐の中で時間指定のそれぞれ異なるSetEventAfter命令を実行すればよろしい。

Aは、メソッドMtdWaitSignalG内のifeq命令がそれに当たります。構造は冒頭に示した出発進行待ちメソッドと似ています。つまり、条件(ここでは前方の閉塞信号がG現示になること)が成立すればある処理をおこない、成立しなければ自分自身(メソッド)がもう1度実行されるようにSetEventAfterをおこなう、というものです。異なるのは、ここでは列車を発車させず、信号の灯火制御のみをおこなっている点です。
ここで@、Aが達成され出発信号のメソッドStdMtdSignalGが実行されれば、出発信号はG現示となり、その公開プロパティStdVarSignalPositionの値は6となります。これは少なくとも1秒以内に実行されるであろう編成側の出発進行待ちメソッドMtdWaitDepartureが「信号がR現示ではなくなった」と判断することを意味します。すなわち、列車は再び走り出すワケです。

このような、SetEventAfterを使った「ある条件が整うまで待つ」というテクニックは、自律的な自動運転を実現する上で欠かせません。明日は、このテクニックをもう少し一般化して説明し、読者のみなさんが各自で応用できるようになることを目指してみましょう。

質問やご要望があれば気軽にコメント欄に書き込んでください。特に「ここの意味がよくわからないのでもっと詳しく」という指摘は大歓迎です、なぜわかりにくいのかの理由が添えられていると特に。
0

コメントを書く

この記事にはコメントを投稿できません




teacup.ブログ “AutoPage”
AutoPage最新お知らせ