The Randall Museum in San Francisco hosts a large HO-scale model train layout. Created by the Golden Gate Model Railroad Club starting in 1961, the layout was donated to the Museum in 2015. Since then I have started automatizing trains running on the layout. I am also the layout maintainer. This blog describes various updates on the Randall project and I maintain a separate blog for all my electronics not directly related to Randall.
2017-01-16 - Thinking ahead on the Automation SoftwareCategory Randall
Here's a rethink of the automation software.
Right now I have JMRI for sensor management and DCC throttles. Conductor acts as a plug-in that drives the automation purley on sensor+timer event based script.
One useful thing in RocRail is the notion of routes, which JMRI has too of course (but annoyingly complex to setup).
The idea is to describe the layout using a chain of blocks with turnouts on or between them.
The timer/sensor script remains the same, but the goal is to have the software know which engine number is on which block. This in turn will drive the display and make it possible to lock routes.
Example, for the Passenger and Branchline automation:
BL1 ⇒ BL2 [T324] ⇒ void ⇒ BL3 ⇒ BL4
B503b ⇒ B503a ⇒ [T504] ⇒ [T321] B321 [T322] [T326] ⇒ [T330] B330 ⇒ void ⇒ B360 ⇒ B370
[T322] ⇒ B322 [T324] ⇒ [T326]
B310 ⇒ [T320] B320 ⇒ [T330]
B311 [T311] ⇒ [T321]
One difficulty is to express the relation of turnouts and blocks. There are also some void unknown blocks where the software has no visibility but can easily assume that the train is located there.
That's one thing that determinist software like JMRI or RocRail do not handle.
E.g. in the case of the passenger automation, right now the blocks B321 and B330 up to B350 are not detected, but once the automation has started we know that the train must be there somewhere till it reaches B360, at which point the train info can be transferred to B360.
Note that a train can be on two blocks at the same time if they are continuous. That's the case when crossing from one block to the next one, especially if there are lighted cars or push-pull engines.
What is this information good for?
First for display. One goal is to have a summary track representation on the tablet with the blocks and the train number should show up on that where the software think it is. That means if something is wrong, the viewer can notice it and act on it.
Second for emergency. When doing the Passenger automation, we expect the train leaving B503a to reach B330 in a specific amount of time, namely 50 seconds till we reduce the speed past the Sonora turnout. We can add some margin to it, e.g. say 60 seconds max. If we have no detected B330 turning on within 60 second, we can assume something is wrong.
Third for turnout protection. It would be ideal if the automation could prevent from aligning turnouts if their block or the next one is occupied. This would be only for automated routes. Manual operators could always realign turnouts.
Finally for automating train speed under automatic block control. E.g. if the passenger automation is returning to the station, the following would happen:
- T330 (Sonora) needs to be aligned. However this can only be done if all of B330, B320 and B321 are not occupied.
- If B330 is occupied or if T330 cannot be aligned, the train needs to stop before the occupied block. Luckily for us, blocks are long enough that if we stop a train just when it enters a block, it will stay in that block and not stop in the next one. Otherwise we would have to program it to stop 2 blocks before. Also in this example, "before B330" going down is that "void" block but that's OK since we know that a train that passes B360 going enters that void block.
- Finally, when whatever is occupying block B330, B320 and B321 leaves and the 3 blocks are free, the automation can throw the T330 turnout and resume the train.
Knowing in which block the train is, it would not block itself from throwing a turnout. E.g. if the train is itself in B330, that should not prevent it from throwing T330.
One issue we have is that we have no real feedback on turnout position. We can only query JMRI to tell us what the turnout is likely to be at, unless an operator as manually changed it. JMRI has no knowledge of that. The NCE PH Pro command station does but I don't believe JMRI is querying that [Update: it can. Define turnouts in Monitoring mode].
Once we have all this, we could rewrite the automation in a completely different way. For example for the passenger automation, the events could be purely block based and their order forming a route, e.g. something like this:
B503b & Stopped & Start ⇒ Align T504, T322, T321; State Up; Speed Fwd Normal; Expect B321 in 10s.
B321 ⇒ Align T322, T326, T330; After 40s do F3; Expect B330 in 50s.
B330 ⇒ Speed Fwd Restricted; Expect void1
Void1 ⇒ Align T370; Expect B360; After 10s do Speed Fwd Normal; After 15s do Horn
B360 ⇒ Expect B370 in 10s
B370 ⇒ After 8s do Speed Fwd Restricted; After 11s do Stop; After 15s do State Down.
B370 ⇒ Speed Rev Restricted; Expect B360
So this describes the movement from block A to block B. Technically we don't even need to indicate which turnouts to throw, the software can compute that using the map described earlier.
One tricky part is that "void1" block since switching to that state relies on the block B330 going off instead of another sensor going on. Also calling it a "virtual block" instead of "void" may be better.
As far as the block graph is concerned, a train is thus located on a specific block (even if virtual) and with a specific direction within the block graph.
An end-goal of that is to allow "free" automated running. E.g. another train waiting at station track 2 could leave after the PA train once the blocks are free, or one could circle on the mainline and wait for the PA one when needed. For this we need to extend the concept of occupied block to occupied region -- e.g. B330 up to B370 is one region and can only have a single train at a time.