SSブログ

リスナーの一括登録 [python]

昨日はリスナーは一つ一つのように書いてしまいましたが、1つのリスナーに多くのメモリーを監視させることが出来ました。


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)


たった、これだけ。(リストは既存のスクリプトから)

読み出すためのクラスは

class mListener(java.beans.PropertyChangeListener):

     def propertyChange(self, event):

          if event.newValue != "":

               print event.newValue


event.newValueで新しく入った値を読み出せます。
どれに入ったかは
event.source.systemNameで取り出せます。

print event.source.systemName, "が", event.oldValue, "から", event.newValue, "に変わりました。"
のように使えます。
event.newValueには制御すべき列車のIDがはいってますから、これを使ってスロットル値を変えます。

タグ:Python

リスナーの勉強を [python]

先日、自分で運転できないようなら面白さに欠けるとのコメントを頂き、
http://passingtrainslayout.blog.so-net.ne.jp/2013-05-11
自動運転と手動を併用できるようにやってみようと思い立ちました。出来る目算はないのですが。。。

まずはループを回して列車を見つけてましたが、
http://passingtrainslayout.blog.so-net.ne.jp/2013-05-07
変化を検知して動作するリスナーを使ってみようかと。おっさんには辛い勉強です。。。

先ずはリスナーの勉強からです。
始めてスクリプトを書いたときよりは少々理解が進んでいますので、当時はさっぱり分からなかったサンプルも理解できるようになってました。

import jarray
import jmri
class MyListener(java.beans.PropertyChangeListener):
def propertyChange(self, event):
if event.newValue == "":
print "out"
else:
print event.newValue

m = memories.provideMemory("IM:AUTO:0005")
a = MyListener()
m.addPropertyChangeListener(a)

IM:AUTO:0005のメモリー値(その区間にいる列車ID)に変化があったときに
そのIDを表示する、または、区間を抜けた場合はoutと表示するスクリプトです。
def 以下のところに、動作を書いていきます。信号現示を読み取り、スロットルを制御すれば。。。
でも、これを全区間に設定していく?のかなぁ。
あまりエレガントではないような。。。。
さてどうなりますやら。

タグ:Python DCC JMRI

トレインスコープ [レイアウト]

連休中に買っておいたトレインスコープを、先週買って来た中古のE531系中間台車に乗せました。

IMG_2822.jpg

ボディーを乗せると視界が狭くなるので、むき出しのままですが、自分自身は映りませんので気にしません。

階下のビデオレコーダーまで飛ばしているので、ノイズが乗ってしまってます。



それでもそこそこ楽しめる映像が撮れました。
やっぱり信号機がでかすぎですね。横、裏に光が漏れているのもいけません。遮光しないと。
駅屋根の柱も太すぎ。




カーブはポイントの感じはなかなか(自画自賛)。
直線部でも蛇行して走っているのが、ローカル線っぽいです。(一応幹線なんですが。。。)
こういうのを見ると、早く地形を作らないとと思うのですが、町づくりの構想がないんですよね。


タグ:レイアウト

スロットルのスティール [python]

前回までにご紹介した、信号現示に従って列車を制御するスクリプトですが、この方法では実は運転そのものを楽しむことは出来ません。
つまり自分でレバーを操作して列車を列車を運転しているときに、PC側が勝手に前方の赤現示で減速停止してくれません。

_________self.throttle = self.getThrottle(int(trainList[j]), False)
_________self.throttle.speedSetting = self.sp
のような形で各車両のDCCデコーダーにスピードを指令するわけですが、
デコーダーを制御する権利を複数のコントローラーに持たせることが出来ないのです。

制御権を横取りすることをDCCではスティールと言っています。
PCで持っている制御権はコントローラーからスティール出来ますが、
逆にPCからはうまくスティール出来ません。
「うまく」と書いたのは、コマンドは通るのですが、相手からリリースさせることが出来ないために、コントローラーからの命令が入るとそちらも通ってしまい、結果的に強制的な停止とはならないことを意味します。
PCからスピード0を命令しても、コントローラーでスピード100を入れてしまうと、100になってしまうのです。
ですので、人間が運転しているものの安全を確保することは出来ません。
なんか、PCに任せっきりにしなければならないということで、実は当初の目的とは違ったものが出来上がっています。

もう一点、スクリプトを走らせる前の注意点ですが、
getThrottleコマンドの前に、PC側で一度バーチャルスロットルを起動し、PCで列車を制御できる状態にしておかなければならないようです。
getThrottleコマンドがうまく通らないと、スクリプトはそこで止まってしまいます。

スロットル.png
赤枠で囲んだウィンドウがJMRIのバーチャルスロットルで、制御したい列車のこれを全て開いておく必要があります。(必要はないのかもしれませんが、こうしておくと上手く動きます。)

手作りなので、使い勝手に癖(流儀)がかなりあり、初めての人が簡単にということにはなりませんね。
タグ:DCC Python

センサーディレイによる停止位置の調整 [DCC]


写真は東駅第1、第2場内です。

delay.jpg
赤線のポイントの直後にギャップが切ってあって、そこからホームまで少々距離があります。
ここからブレーキをかけて停車させるには、減速ディレイなどの調整ではとても無理です。
本来は青線あたりにもギャップを切っておき、場内を2つに分けるのが良かったのかと思います。
いつものごとく、後手後手の対応です。(線路を切れば、今からでも出来ますけど。)

苦肉の策ですが、センサーの反応までにディレイをかけることで対応しました。

スクリーンショット 0025-05-09 平成25年5月9日(木)  12.57.32.png
どの列車も進入速度がほぼ同じだろうということで、時間によるディレイです。
この2つのセンサーの反応を4000msec、3800msec遅延させております。
信号機は場内に入ってから4秒後に変わることになり、動作としてはおかしいかもしれませんが、顕著な不都合はありません。

タグ:DCC

黄現示のスピードの個別設定 [python]

前回ご紹介している信号現示による制御スクリプトでは、列車が駅に停車するときは先の出発信号機が赤現示なので
入線する場内信号機の黄現示で駅に侵入し、出発信号機の赤現示で停止することになります。
場内の区間をセットしているギャップ(これはDCCの特性上、導電性フログのポイントを使用するときにギャップを切る必要があります)から、停止位置までの距離は各駅で同じではありませんので、上手くホームに停止させるのは調整が難しいことが分かりました。
(最悪はオーバーランで、開通していないポイントに逆方向から突っ込むとショートします。)

そこで、まず、基本となる車両を選び、DCCのCV値を決めます。

CV.png
Decelerationを大きくすると列車はゆっくりと止まります。ここでは31です。
(以前にもご紹介しましたが、KATOから提供されるマニュアルでは最大値31ですが、JMRIではそれ以上の値も設定できます。)
ST.png
また、黄現示から減速していきますので、スピードテーブルの傾きも影響してきます。
これらをまず固定し、黄現示から駅に侵入させてみますと、どうも感覚的にゆっくりとホームに入ってくる感じです。
ですので、黄現示のときの速度を0.5(最高速度の半分)ではなく、0.7くらいにしてみました。
そうすると、おおむね良いことが分かってきました。しかしこれでは各場内で場内ギャップからホームまでの位置が一定ではないので、調製しきれません。そこで、例によって、各ブロックでの黄現示のときの速度をリストとして与えることにします。

halfList = [0.6, 0.6, 0.6, 0.6, 0.6, 0.71, 0.6, 0.6, 0.6, 0.6, 0.75, 0.6, 0.6, 0.6, 0.6, 0.73, 0.6, 0.6, 0.6, 0.6, 0.6, 0.71, 0.6, 0.6]

こんな感じです。
閉塞信号機や出発信号機のところは、一律0.6で、場内のところだけ、0.71、0.75など微妙に調製できるようにしました。

スピード値の代入のところで、
_________elif self.iro == 'Yellow':
____________self.sp = halfList[i]
とやってやれば、リストの該当する数値を使って減速できるようにしました。

ここまで、1つの代表車両で設定をしておき、あとは各車両間の個体差をDCCのCV値を変えながら調製していきます。

各列車のDecelerationとスピードテーブルをいじります。
Decelerationを大きくすると調整が難しくなりますので、50を超えてくるような場合は
スピードテーブルで最高速度はそのままに、70%くらいのところを上に凸に膨らませてやると、
侵入速度が上がりますので、停止距離が伸びます。
貨物列車では大きなDecelerationにしておくと、実感的になりますね。
このような調子で、全列車のCV値を設定していきました。
あと、1カ所だけ、場内のギャップからホームまで距離が著しく長いところがあります。
ここの調整を何とかしなければなりません。

タグ:DCC Python

信号現示で列車を制御するスクリプトー完成ー [python]

これでversion 1が完成です。


全くエレガントではない、べたべたのスクリプトですが、全容は以下のようになりました。

import jarray
import jmri

class stopHitachi(jmri.jmrit.automat.AbstractAutomaton) :

___def init(self):
______self.c = []
______for self.b in singoList:
_________self.c.append(signals.getSignalHead(self.b))
______print "Go!"
______return

___def handle(self):
______self.waitChange(jarray.array(self.c,jmri.NamedBean))
______self.waitMsec(100)
______for j in range(len(trainList)):
_________for i in range(24):
____________self.ichi = memories.getMemory(memoriList[i]).getValue()
____________if self.ichi == trainList[j]:
_______________if (i == 0) and (memories.getMemory(memoriList[23]).getValue() == trainList[j]):
__________________i = 23
_______________self.singo = singoList[i]
_______________self.iro = signals.getSignalHead(self.singo).getAppearanceName()
_______________break
_________if self.singo == '':
____________self.iro = 'Red'
_________if self.iro == 'Green':
____________self.sp = 1
_________elif self.iro == 'Yellow':
____________self.sp = 0.5
_________elif self.iro == 'Red':
____________self.sp = 0
_________if sensors.getSensor(sensList[i]).state == 2:
____________self.sp = 0
_________print trainList[j], i, self.singo, self.iro, sensors.getSensor(sensList[i]).state, self.sp
_________self.throttle = self.getThrottle(int(trainList[j]), False)
_________self.throttle.speedSetting = self.sp
_________self.singo = ''
______return 1

trainList = ['7', '11', '31', '21', '22']
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']
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"', 'IH47']
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']


a = stopHitachi()
a.setName("stopHitachi")

a.start()


これをRun Scriptで実行してやれば、Thread Monitorに”stopHitachi”という名前でプロセスが走ります。(問題があったらkillできます。)
5つの列車が、前方の信号機が青現示でフルスピード、黄現示で50%、赤現示で停止します。
指令は出発信号機に対して出発許可を出してやるだけです。2区間前に先行列車がいれば黄現示でゆっくりと発車していきます。
場内信号機が全部赤現示なら、2区間前で減速、さらに駅手前で停止、場内が空けば自動的に侵入していきます。
各列車には過減速のdelayが設定されていますので、いきなり100%や0%スロットルを与えても、ゆっくりと加速、減速していきます。
これで5つの列車をひとりで運転できるようになりました。(眺められるようになりました。)

おおむね完成しましたが、細かい問題が出てきました。
次回から、ご紹介していきます。

タグ:DCC Python

センサーの状態を読み込む [python]

これでほぼ完成なんですが、あと1点、発車メロディーがなっているときに列車を止めておきたいので、特定のセンサーがアクティブなときにはスピードを0にしておきたいと思いました。
流儀に大分慣れてきましたので、こちらは簡単でした。
センサーIS1の状態を読み出すには
sensors.getSensor('IS1').state
です。
ここには数値が入ります。
print sensors.getSensor('IS1').state

>>> print sensors.getSensor('IS1').state
2
>>> print sensors.getSensor('IS1').state
4
などと返ってきます。2がactive、4がinactiveです。1はunknownですので、エラー時の対処が可能です。
なので、
_________if sensors.getSensor(sensList[i]).state == 2:
____________self.sp = 0
などとしてやります。
例によってsensListに見るべきセンサー(発車メロディーを管理しているセンサー)のリストを作っておきます。

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']
IS25は発車メロディーのない一般の閉塞、場内信号機用のダミーですが、こいつをactiveにすれば全列車(出発信号機に支配されているものは除く)を止めることが出来るセンサーになります。

これ追加してversion 1が完成です。

タグ:DCC Python

現示変化を待つ [python]

信号現示が変化したときだけの動作には通常はリスナーを使うのでしょうか。
しかし当時はサンプルスクリプトの構文を見ていてもよく理解できませんでしたので、
別の方法を探してみました。

JMRI APIにちゃんと用意されています。
self.waitChange(jarray.array(self.c,jmri.NamedBean))
というやつで、ここのself.cに信号機のリストを代入してやると、その中のいずれかに変化があるまで、waitするというものです。まさにぴったり。

ところが
self.c = ['IH:SE8C:"LT273";"LT274"', …….]
などとしてやっても、全く動きません。なんで。。。

またしても、ネットで検索、なるほどsignals.getSignalHead()で読み込んだコードでないといけないようです。printしてみたところ、わけの分からないコードのようなものでした。
これは手で作成するわけにはいきません。(起動するたびに変わるかも???)

self.a = []
self.c = ['IH:SE8C:"LT273";"LT274"', ……]
for self.b in self.c:
___self.a.append(signals.getSignalHead(self.b))

1行目で空のリストself.aを作って、
self.bをself.cの信号リストに対し、回します。
ループの中はリストself.aにgetSignalHeadで読み込んだコードを追加していきます。
これで、
self.waitChange(jarray.array(self.c,jmri.NamedBean))
とすれば、どれかの信号現示が変わったときまで、プロセスが止まるようになりました。
分かってしまえば、、、なんですが、これはちゃんと動くようになるまで結構苦労しました。

複数の列車を制御 [python]

昨日ご紹介した列車制御を各列車に適応させるには昨日のループを
各列車に対してループjを回せば良いことになります。

for j in range(len(trainList)):
___for i in range(24):
______self.ichi = memories.getMemory(memoriList[i]).getValue()
______if self.ichi == trainList[j]:
_________if (i == 0) and (memories.getMemory(memoriList[23]).getValue() == trainList[j]):
____________i = 23
_________self.singo = singoList[i]
_________self.iro = signals.getSignalHead(self.singo).getAppearanceName()
_________break
___if self.singo == '':
______self.iro = 'Red'
___if self.iro == 'Green':
______self.sp = 1
___elif self.iro == 'Yellow':
______self.sp = 0.5
___elif self.iro == 'Red':
______self.sp = 0
___print trainList[j], i, self.singo, self.iro, sensors.getSensor(sensList[i]).state, self.sp
___self.throttle = self.getThrottle(int(trainList[j]), False)
___self.throttle.speedSetting = self.sp
___self.singo = ''

trainList = ['7', '11', '31', '21', '22']

新しい車両が入線したら、trainListにDCCアドレスを追加すればOKです。
このルーチンが一周すれば、全列車に対して1回、前方の信号現示を確認して、スピードを調整することになります。
ですので、クラスの定義のところにあった
def handle(self):
___……
___return 1
の___……にさっきのループを書けば、クラスを実行したときに無限に回り続けます。
ただ、これでやるとThread monitorで見るとものすごい速さで回り続けていることが分かります。
全列車止まっていても、意味も無く回っています。マシンパワーが。。。。
ですので、このループを回すのは信号が変わったときだけで良いのです。
さて、どうしましょうか。

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。