2007/5/5

ゆゆぽん☆退避/追越列車とか作っちゃうかMona-(7)−閉塞区間に分けて考える  VRMスクリプト禅問答
<<前回へ

今回から、いよいよ課題(3)“区間閉塞”について解説していきます。この課題は、前回までに触れた課題(1)〜(2)が1つのセンサーと1つの部品の一対一の関係であったのに対し、複数の部品の相互作用を考えなければならないという点において、その難易度が格段に高いです。気合を入れてついてきてください。

振り落とされそうに感じた場合は、ゆゆぽん氏も含めてコメント欄で詳細解説を要求してください。特に声が挙がらないようであれば、ご理解いただけたものと判断して先へと進んでいきます。なお、ゆゆぽん氏のリクエストに従い、信号は三灯式のものに限定して話を進めます(内容が理解できれば、四・五灯式に対しても応用できるはずです)。

クリックすると元のサイズで表示します

区間閉塞とは、単純化すれば上図のように、一定間隔に閉塞信号を設け、信号と信号の間の経路=閉塞区間に1つの編成だけが進入するように信号灯火を制御する、ということです。信号部品自体はレールに対して何の影響も与えませんから、実際には信号と対で配置されるセンサー(上図では白い□)が、閉塞区間の区切りになります。

まず、前回までで実現されたところをおさらいしてみましょう。経路上の4つのセンサーと信号に、それぞれ前回解説したスクリプトが書き込まれているものと考えてください。中身は基本的に同じですが、センサー側の制御対象信号の名称は、センサーの位置に対応した信号のそれになっているものと想定します。

クリックすると元のサイズで表示します

右側から走行してきた編成が最初のセンサーを踏むと、このセンサーと対になる信号が赤になります。ピンクの矢印は、編成を検知したセンサーが、信号の閉塞実施メソッドMtdSectionBlockをcallしていることを示しています。以下、編成が左へ向かって進むと・・・

クリックすると元のサイズで表示します

クリックすると元のサイズで表示します

となっていきます。追突が防止されるという点で、区間閉塞の目的は果たしていますが、後続の列車が進入してくる余地がありませんね。つまり、閉塞信号を実現するということは、

・編成が進入したら信号を赤にする(前回達成した課題)。
・編成が通過し終えたら、信号を赤以外にする(今回以降に達成する課題)。

の2つの課題により成り立つということです。

さて、やや寄り道になりますが、先に“悪い例”を示しておくことにしましょう。

クリックすると元のサイズで表示します

上図は、信号の制御方法としては間違っていないものの、閉塞信号の作り方としては不適切な考え方を示しています。箇条書きにすると・・・

《これは悪い例です》
・センサーが編成を検知したら、隣接する信号を赤にする。
・1つ前の信号を黄(Y現示)にする。
・2つ前の信号を緑(G現示)にする。

この方法は、しばしばネットVRM界隈でも見受けられるほか、困ったことに、製品付属のスクロールまでもがこの考え方で(しかもより悪い実装で)作られています。結論から言うと、この方法では区間閉塞は実現できません。

クリックすると元のサイズで表示します

その理由は、上図のような状況を考えてみるとすぐにわかります。黄色で示した編成と青色で示した編成が、同時にセンサーを踏んだと考えてください。それぞれの編成位置のセンサーが3つの信号に赤・黄・緑の灯火色切替を命じると、オレンジの▼で示した信号は、同時に「赤になれ」「緑になれ」の矛盾する命令を受けることになります。

「いや、同時なんてあり得ないよ」とあなたは思うかも知れません。では、青の編成がセンサーを通過した直後に黄色の編成がセンサーを通過するケースを想定してみてください。青の編成が閉塞した(赤に変えた)信号を、直後に黄色の編成が緑にしてしまうことがわかりますか。これは、青の編成に後続する列車があった場合、追突を許可していることを意味します。

この方法は絶対に駄目、とまではいいません。が、本連載が目指している退避/追越列車の実現は、厳密な編成走行位置の管理が必要となるため、こういうトイライク(おもちゃ的)な手法は使えません。

ではどうすれば良いのか、については次回解説していきます。

次回へ>>
0

2007/5/6  7:56

投稿者:ghost
それが正解です。>MtdRelaySectionBlock
メソッドの命名センスもお見事。

> 出発・場内信号

については、区間閉塞が完成したのち、その応用として実現します。基本的な理屈は閉塞信号と同じです。

何かご自身で試みたいことがあれば、とりあえずはやってみるのがいいんじゃないでしょうか。意図通りに動作するのであれば、ボクの解説する手法に拘泥する理由はありませんから。

2007/5/6  0:06

投稿者:ゆゆぽん☆
[センサー]
Var SigCtrl
SetEventSensor MtdRelaySectionBlock SigCtrl


BeginFunc MtdRelaySectionBlock

call ObjSignal1 MtdSectionBlock

EndFunc

[信号]
//閉塞実施メソッド
BeginFunc MtdSectionBlock
//灯火色切替メソッドを実行
call this MtdSignalR
//
EndFunc

で動きました。
> あと、場内信号のSignal5,6は、今のところ
> 本線用のSignal5連動させています。

は、信号6個とセンサー5個ありますが、
(場内信号機の部分がかぶる為)
1個のセンサーで操作することは考えず、
信号、センサー5組としてすべて閉塞信号の
扱っているという意味です。出発・場内信号は
全くスクリプトを書かない状態でいたほうがいい
ですか?説明が下手ですみません。

2007/5/5  22:01

投稿者:ghost
最初よりも悪くなりました...orz

ここを自力で突破しないことにはこの後の課題は絶対に解決できないので、敢えてサンプルコードは示しません。以下の説明を読んで再挑戦しましょう。

1. 今やりたいことは、センサーを編成が通過したら何か(信号の閉塞)が起こる、です。
2. センサーが編成を検知した際、何かを起こすには、SetEventSensor命令をつかって、センサーのメソッドを実行します。
3. が、信号の閉塞処理自体は、センサーではなく信号側のスクリプト(メソッド)でやらなくてはなりません。
4.そこで、センサー側に中継用のメソッドを作ります。名前は何でもいいです。
5. この中継用のメソッドの中から、信号側の閉塞処理のメソッドを実行(call)しましょう。

以上です、頑張って。


ちなみに。

> あと、場内信号のSignal5,6は、今のところ
> 本線用のSignal5連動させています。

まったく意図がわかりません。場内/出発信号については12回目以降に解説する予定です。基礎を理解しないうちに、結果を焦るのはお奨めできません。

ボクにはゆゆぽん☆殿が今作っているレイアウトが見えていない、ということを忘れないでください。あなたが基礎を押さえないままに独自に書いたスクリプトがおかしな動作を起こしても、ボクにはそれを解決することは出来ません。

2007/5/5  20:59

投稿者:ゆゆぽん☆
すみません、訂正です。
SIG1の変数はObjSignal1〜6です。

2007/5/5  20:57

投稿者:ゆゆぽん☆
[センサー]
//Var命令で宣言
VarSignal SIG1
get SIG1 Signal1

call SIG1 MtdSectionBlock
[信号]
//閉塞実施メソッド
BeginFunc MtdSectionBlock
//灯火色切替メソッドを実行
call this MtdSignalR
EndFunc

だと最初から赤になってしまうので、
信号のスクリプトをセンサーに移して
thisを変数に変えたうえ、
SetEventSensorを使うと動きはするのですが、
後からのスクリプトに支障をきたさないか心配
です。あと、場内信号のSignal5,6は、今のところ
本線用のSignal5連動させています。

2007/5/5  16:47

投稿者:ghost
第一に、SetEventSensor命令は、自分自身(つまり、この命令を含むセンサー)に所属するメソッドしか実行できません。

第二に、センサースクリプトで宣言した信号オブジェクト変数ObjSignalは、宣言しただけで使ってないですよね。これは、call ObjSignal MtdSectionBlock とすることで“このセンサーが担当する信号の閉塞メソッドを実行する”ための準備だったはずです。

以上のヒントで考えてみましょう。

ちなみに信号スクリプトの、

> Var VarSignal
> set VarSignal SIG1

は要らない(使ってないですよね、実際)ので消しておいた方が後で混乱しなくて良いかも。黄/緑点灯用のメソッドはそれで正しいです。

2007/5/5  16:41

投稿者:ゆゆぽん☆
やっぱりセンサーを踏んでも赤に変わりません。

[センサースクリプト]
//Var命令で宣言
VarSignal ObjSignal
get ObjSignal Signal1

Var SigCtrl
SetEventSensor MtdSectionBlock SigCtrl

[信号スクリプト]
//Var命令で宣言
Var VarSignal
set VarSignal SIG1

//信号灯火色管理変数
Var VarSignalColor
call this MtdSignalG

//灯火色設定メソッド
BeginFunc MtdSignalR
set VarSignalColor 1
SetSignal VarSignalColor
EndFunc

BeginFunc MtdSignalY
set VarSignalColor 3
SetSignal VarSignalColor
EndFunc

BeginFunc MtdSignalG
set VarSignalColor 6
SetSignal VarSignalColor
EndFunc

//閉塞実施メソッド
BeginFunc MtdSectionBlock
//灯火色切替メソッドを実行
call this MtdSignalR
EndFunc

赤に変えるメソッドはできていると思うのですが
何が足りないのでしょう?

2007/5/5  11:27

投稿者:ghost
KSMaster殿の実装は、スクリプトを読んだので存じ上げています。

この連載で紹介するのは、言わば“別解”で「列車が区間に入るとき1を足して、出るときに1を引く」のような、恣意的な変数を用いずに、閉塞を実現する方法です。必要な変数は、各信号の灯火色を記録するそれと、イベント変数1つだけでいけます。

分岐後の処置については、連載12〜13回あたりで書きますので、それを読んでください。すくなくとも、この課題については、恣意的な管理変数を使うよりも、ghost流の方が格段にスマートに記述できると思います。

ただ、誤解のないように明言しておきますが、ボクのスタンスはあくまでも「意図通り動けばOK」です。他のロジックで同じことを実現する人を否定するつもりはありません。それぞれの実装の長所短所は遠慮なく論じます。が、優劣を論じるつもりはありません。

でも・・・製品付属のスクロールはいくらなんでもあんまりだと思ってる(苦笑)

2007/5/5  11:14

投稿者:KSMaster
 僕は、列車が区間に入るとき1を足して、出るときに1を引くという方法で閉塞に対する矛盾は解決しましたが、待避を行うようにすると分岐される手前の信号の動作が気になります。
 列車が待避線に止まっている状態で、停まっていない本線にポイントを切り替えても、後ろの信号は待避線に列車が止まっていることを表示するので、本線に入る列車からみるとおかしな現象が生じます。。

http://ksmaster.sblo.jp/

2007/5/5  10:41

投稿者:ghost
これはボクの言葉足らずですね。>call this MtgSignalG には意味があるのでしょうか?

VRMの信号機はビュワー起動時に無灯火です。
何もしなければ、センサーが編成を検知し、メソッドMtdSignalRが実行されるまで、どの色も灯火していない状態になります。

それだと不自然なので、とりあえず信号を青にしておきましょう、が、メソッドの外側(宣言部)にあるcall this MtdSignalGの意図です。

で、肝心のメソッドMtdSignalGは、MtdSignalRからの類推で自分で作ってみてね、というのが意図だったのですが、改めて読み直すと、これはちとわかりにくかったですね。

要するにMtdSignalGは、MtdSignalRとメソッド名、および変数VarSignalColorに代入する値が異なるだけで、他は同じメソッドです。

同様に、MtdSignalYも用意しておいてください。次回以降で必要になりますので。

コメントを書く

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




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