Mac OS X Yosemite 10.10 [レイアウト]
信号不調 [DCC]
リスナーを使ったスクリプトー完成? [python]
しばらく更新をサボっておりましたが、
先週末に作成中のスクリプトの修正を行い、何とか動くようになりましたので、ご報告申し上げます。
スクリプト中の
self.throttle.speedSetting = self.sp
で列車の速度を変えるのですが、どうも空振りすることがあることが判明しました。
このときJMRIのスロットルは、100%の速度になっているのですが、実際には列車にこのコマンドが通らず、列車が動き出さないという事例が極々稀に発生しました。
100%の時はまだましなのですが、赤現示で0%(=ストップ)がスルーされると大事故になります。
実際に試運転時に2,3回起こってしまいました。
理由は全く分かりません。全くのお手上げ状態。
多くのLogixなどが走っているせいでしょうか。
そこで、苦肉の策ですが、
self.spo = self.throttle.getSpeedSetting()
self.throttle.speedSetting = 0.95*self.sp+0.05*self.spo
self.throttle.speedSetting = self.sp
変化分の95%と100%を2段階で入れることにしました。どっちかは通るだろうと。
何となく場当たり的な対策ですが、これにより30分くらいの運転でしたが、コマンドがスルーされることはなくなりました。
完全に安全な自動運転に出来ないところが、どうにも弱いです。
綺麗なスクリプトをと思ってリスナーに挑戦してみましたが、結局はなんだか後手後手のものが出来てしまいました。
前照灯•尾灯用デコーダーFL12 の搭載 [DCC]
E653系、入線しました [レイアウト]
リスナーの削除 [python]
リスナーのスクリプトをテストしていて困ったことに、設定したリスナーは自分で消さない限り、スクリプトを実行するたびにどんどんと蓄積されていきます。
kill出来ないので。
スクリプトを実行し、不具合など訂正、再度実行すると前のスクリプトの動作も残ってしまっていて、多重に動作します。
そのたびにアプリを起動し直すのは手間ですので、センサーを取り除くスクリプトを追加しました。
リスナーを追加したスクリプトに加えておかないと上手く動作しないようです。
sensors.provideSensor(i).addPropertyChangeListener(d)
addを
sensors.provideSensor(i).removePropertyChangeListener(d)
removeにかえて、登録したのと同じforループを回します。
これをIS26センサーのリスナーにしておきます。
class delListener(java.beans.PropertyChangeListener):
def propertyChange(self, event):
if event.newValue == 2:
sensors.provideSensor("IS26").setState(4)
for i in singoList:
signals.getSignalHead(i).removePropertyChangeListener(b)
for i in memoriList:
memories.provideMemory(i).removePropertyChangeListener(a)
for i in sensList:
sensors.provideSensor(i).removePropertyChangeListener(d)
sensors.provideSensor("IS26").removePropertyChangeListener(e)
print "remove all listener!"
e = delListener()
sensors.provideSensor("IS26").addPropertyChangeListener(e)
リスナーの使い方をご紹介してきました。
これで各パーツは出来上がりましたので、これらをマージして実際の制御に使ってみます。
と言いますのも、実は動作するかはバーチャルモードでprintの出力で見ていただけなんです。
ある程度動く状態まで持っていかないと、列車が制御不能になると怖いですから。。。
明日からは、怖々の実車でのテストです。
JMRI 3.5.5 [DCC]
信号機、センサーのリスナー [python]
スクリプトにトライされる方で、私のようにプログラミングに不慣れなものはJMRIのスクリプトサンプルを見ての解読になると思いますが、例が少なく情報を求めてネット上をさまよい歩きましたので、どなたかの参考になればと思っています。
今回は信号機のリスナーで、現示が変わったときに動作するリスナーです。
class sListener(java.beans.PropertyChangeListener):
def propertyChange(self, event):
basho = singoList.index(event.source.systemName)
train = memories.getMemory(memoriList[basho]).getValue()
if train != "": #(1) そこに列車がいるときのみ以下の動作をする。
genji = signals.getSignalHead(singoList[basho]).getAppearanceName()
print "signal", train, basho, genji
c.cont(train, basho, genji)
#以下、リスナーの登録
singoList = ['IH:SE8C:"LT273";"LT274"', 'IH:SE8C:"LT275";"LT276"', 'IH:SE8C:"LT287";"LT288"', 'IH:SE8C:"LT285";"LT286"', 'IH:SE8C:"LT283";"LT284"', 'IH43', 'IH:SE8C:"LT261";"LT262"', 'IH:SE8C:"LT263";"LT264"', 'IH:SE8C:"LT301";"LT302"', 'IH:SE8C:"LT303";"LT304"', 'IH45', 'IH:SE8C:"LT265";"LT266"', 'IH:SE8C:"LT267";"LT268"', 'IH:SE8C:"LT305";"LT306"', 'IH:SE8C:"LT307";"LT308"', 'IH46', 'IH:SE8C:"LT257";"LT258"', 'IH:SE8C:"LT259";"LT260"', 'IH:SE8C:"LT277";"LT278"', 'IH:SE8C:"LT279";"LT280"', 'IH:SE8C:"LT281";"LT282"', 'IH44', 'IH:SE8C:"LT269";"LT270"', 'IH:SE8C:"LT271";"LT272"']
b = sListener()
for i in singoList:
signals.getSignalHead(i).addPropertyChangeListener(b)
信号現示が変化したらその場所を信号機リストから探し出し、場所を特定、
そこの列車IDをメモリー値から読み出します。
(1)で列車がいるときのみ、信号現示を読み出し、c.contの列車を制御する関数をコールします。
分かってしまえば特段難しくはありません。
同様にセンサーのリストです。
センサーリストはIS25は場内または閉塞区間のセンサーです。これらのセンサーは今のところなんの機能も持たせてないのですが、
緊急停止みたいなことをやってみようかと思っています。現在は設定していませんので、ifで飛ばしてます。
センサーの値はactiveのときは2、inactiveのときは4が入っていました。(スクリプトを書いて調べました。)
センサーがactiveのときは現示を赤に、それ以外のときは、参照すべき信号機を見るようにして、c.contの列車を制御する関数をコールします。
class sensListener(java.beans.PropertyChangeListener):
def propertyChange(self, event):
if (event.source.systemName != "IS25"):#イベントが起こったセンサー名がIS25以外の時
basho = sensList.index(event.source.systemName)
train = memories.getMemory(memoriList[basho]).getValue()
if (event.newValue == 2):
genji = "Red"
elif (event.newValue == 4):
genji = signals.getSignalHead(singoList[basho]).getAppearanceName()
print "sensor", train, basho, genji
c.cont(train, basho, genji)
sensList = ['IS25', 'IS25', 'IS133', 'IS134', 'IS25', 'IS25', 'IS25', 'IS25', 'IS132', 'IS131', 'IS25', 'IS25', 'IS25', 'IS130', 'IS129', 'IS25', 'IS25', 'IS25', 'IS136', 'IS135', 'IS25', 'IS25', 'IS25', 'IS25']
d = sensListener()
for i in sensList:
sensors.provideSensor(i).addPropertyChangeListener(d)
たぶん同じようにポイントのリスナーも作れると思います。
メモリーのリスナー [python]
class mListener(java.beans.PropertyChangeListener):
def propertyChange(self, event):
if event.newValue != "": #(1)
basho = memoriList.index(event.source.systemName)
train = event.newValue
genji = signals.getSignalHead(singoList[basho]).getAppearanceName()
print "memory", train, basho, genji
c.cont(train, basho, genji)
memoriList = ['IM:AUTO:0005', 'IM:AUTO:0004', 'IM:AUTO:0020', 'IM:AUTO:0019', 'IM:AUTO:0018', 'IM:AUTO:0014', 'IM:AUTO:0013', 'IM:AUTO:0012', 'IM:AUTO:0021', 'IM:AUTO:0022', 'IM:AUTO:0011', 'IM:AUTO:0010', 'IM:AUTO:0009', 'IM:AUTO:0023', 'IM:AUTO:0024', 'IM:AUTO:0001', 'IM:AUTO:0002', 'IM:AUTO:0003', 'IM:AUTO:0015', 'IM:AUTO:0016', 'IM:AUTO:0017', 'IM:AUTO:0008', 'IM:AUTO:0007', 'IM:AUTO:0006']
a = mListener()
for i in memoriList:
memories.provideMemory(i).addPropertyChangeListener(a)
自動運転スクリプトの構想 [python]
自動運転のスクリプトをいじっています。
自動で速度を制御しながら、場合によっては手動でもできる、という具合に改良中です。
ControlTrainというクラスの定義の部分だけお示しします。
import jarray
import jmri
class ControlTrain(jmri.jmrit.automat.AbstractAutomaton) :
def __init__(self, train, basho, genji):
print "OK"
def cont(self, train, basho, genji):
self.tr = int(train)
self.throttle = self.getThrottle(self.tr, False)
self.sp = self.throttle.getSpeedSetting()
self.syudo = self.throttle.getF4() #F4を読み込む
if self.syudo == 0: #F4がオフの時のみ速度調整をする
if genji == 'Red':
self.sp = 0
elif genji == 'Yellow':
self.sp = halfList[basho]
elif genji == 'Green':
self.sp = 1
else:
self.sp = 0
self.throttle.speedSetting = self.sp
if self.syudo == 1 and self.sp > 0.8:#手動でスピードが80%以上になったら手動を解除
self.throttle.setF4(0)
print self.tr, self.sp
train = ""
basho = ""
genji = ""
c = ControlTrain(train, basho, genji)
こんかいはstart()で回し続けるのではなく、リスナーからcontをコールするようにしてます。
最終行で
c = ControlTrain(train, basho, genji)
とすることで、インスタンスが出来ますので、(理解が正しいか怪しいですが。。。)
あとはリスナーで現示が動いたときに
c.cont(train, basho, genji)
などと、列車のID(train)列車の場所(basho)信号現示(genji)の3つを引数としてコールしてやれば速度を変えてくれます。
(この文はリスナーの動作のところに書いておきます)
bashoは今は使ってませんが、将来場所ごとに動作を変えたり出来るように考えています。
#例えば出発信号機と閉塞信号機で動作を変えるなど。
自動と手動の切り換えは、スロットルのファンクション4(F4)のオンオフでやります。
self.syudo = self.throttle.getF4()
でF4の状態をself.syudoに格納、これが0、ファンクションがオフの時にはスピードを信号現示に合わせて変えます。
つまり自動運転です。
これが1、オンのときはスピード調節はしません。つまり手動運転となります。
いつまでも手動だと、忘れて事故を起こすので、
手動でスロットル速度を80%以上にすると、一旦手動を解除します。
黄現示などで速度が低下した場合に、ファンクション4をオンにすると手動に変更できます。
閉塞信号機で赤現示でもファンクション4を押して侵入できます。本物っぽい?
まだ、このスロットル制御のクラスだけしか出来てませんので、リスナーからコールして上手く動くかは分かりませんけど、構想だけはなんとか出来つつあります。