Routing Decisions

How does the software decide on how to route a train from A to B?

Before looking at routing, lets take a quick look at how the track is configured.   At this stage in development there is no graphical user interface to add pieces of track and create the layout, instead it's configured by a text file.  Here's an example of a single defined piece:

[piece]
type=curve
direction=right
angle=18
length=15  #measured
sensor=TopStationExit
sensorpin=139
sensorcm=15
block=midstationplatform1
reference=L3FA

A "piece" is relatively arbitrary, especially as i'm using flexitrack everywhere.  If a piece of track is an S bend, it would be several pieces in the software, a curve left, a curve right, etc.

Each piece configures:

  • Type (curve, straight, points, crossover)
  • Information to draw it like length, angle, radius.  A curve can either be defined by angle and radius, or length and radius.
  • Sensor information
  • Motor information for points
  • Which block it belongs to (most pieces are not in a joined block, they just form their own individual one)
  • A unique reference that helps to refer it from elsewhere, for example when you have to connect up the thrown side of points
  • Routing information - a piece can be configured as "one way" or "out of service".   You can also configure a piece as "destination only" which means it can't be used as an en-route bypass, only as an end point.

So..... once it's all configured, the system reads all the pieces in, and then has a complete cross reference of where everything interconnects.

A mission contains a route target which could be an individual piece (for example "Top Station Platform 1"), or multiple pieces (for example "Top Station Platform 1" and "Top Station Platform 2") or it could contain a wildcard (for example "Top Station Platform *")

When it works out a route it will try every single combination of possibilities, taking each possible turnout.  It stops itself getting into infinite loops by never allowing the same piece twice - so if you're in a circle and you start at piece AAAA, it will abort once it hits that piece once again.

Having built a table of every possible route, usually only a very small number of those routes will actually hit one of the targets, so it discards all the rest.   It then looks through the good ones and gets the shortest.  Length is calculated by taking the actual length and adding penalties.  A penalty can be custom defined on a piece, or more commonly it's just automatically applied.  The main penalty is points - they cost an extra few centimetres to take the thrown route.  This ensures that secondary turnoff platforms are always biased against.

Once we have the shortest route, it is not necessarily chosen.  It just acts as a benchmark for what the route should be.  It's likely that there are a bunch of very similar length routes when you are going to multiple targets - for example in my "Top Station" there are 5 platforms, and they will always be slightly different distances from the departure point due to the points configuration at that station.   So the system has a tolerance, all routes within a certain distance are considered the same length.

Final route choice then comes down to "how available" the different routes are.   So it looks at all of the routes selected above, and looks at how close to the destination we can get.  This serves two distinct purposes - firstly it allows routing around a blocked line mid-route.  It will do this because the current selected route is now blocked, but routing around it gets us closer to the target, so the route is switched.  The second purpose of this logic is to allow changes in platform choice - because we might set off planning to go to Platform 1, but when we get there the train ahead got it first, so we now change to platform 2, which is "more available" because it gets us all the way there.

Comments