CS452 - Real-Time Programming - Spring 2017
Lecture 24 - Multiple Trains
Public Service Annoucements
-
Train Control II demo on Thursday, 13 July.
-
The exam will start at 19.30, July 28, 2017 and finish at 22.00,
29 July 2017.
-
Project proposal: Next Wednesday
Multi-Train Control
By the second milestone you will be able to control two trains at
the same time.
Sensor Attribution
To accomplish the first milestone you sorted sensor responses
from the train controller into two categories:
-
ones caused by a train, and
-
ones you ignored.
For the second milestone you split the first case into two: ones
caused by train 1, and ones caused by train 2. In other words,
Which train triggered which sensor?
-
As long as the trains are sufficiently far apart this is not
too hard.
-
What is the meaning of `sufficiently' in practice? This is
important: the closer together you can bring the trains while
maintaining correct sensor attribution, the more trains you can
run at once.
-
Sensor attribution must function correctly in the face of
single failures,
-
of sensors, or
-
of turn-outs.
Only single failures need be handled.
One way of doing this is to plan ahead.
-
The train is expected to pass sensor n, which is a distance
X from where it is now, at time T, with a margin for error
of 2\DeltaT.
-
T comes from the velocity calibration: T = X/v
-
2\DeltaT also comes from the noise in my velocity calibration,
and may not be symmetrical around T.
-
That means that I expect the sensor
- Not to have been triggered before T - \DeltaT
- To have been triggered before T + \DeltaT
-
The requirement that sensor attribution be robust against
single errors increases the number of alternatives your
software must expect.
Communication bandwidth to train controller
This is the scarcest resource.
The symptom that you are trying to use it too much is getting
time-outs for events that have already occurred. Switches switching
too late is another symptom.
-
The usual cause is output to the train queued in a buffer
waiting its turn to be sent to the train UART.
-
For example, if your programme is requesting sensor reports
faster than the train controller can provide them then the
time between asking for a report and getting the corresponding
report lengthens monotonically. Growing buffers and queues
in servers is an early warning of performance problems.
Route Finding and Following
You need to be able to route in the presence of obstacles. Some
obstacles are stationary; others are moving: you should handle
both properly. It's normally a good idea to start with stationary
obstacles. Blocking one or more sections of track by a keyboard
command, then asking for a route is probably the easiest way to
debug route-finding in the presence of obstacles.
You need routes that reverse because they improve the performance
of your project.
-
As you add trains to your project, each train sees more blocked
track when it asks for a route.
-
The demo hits a limit when no train can find a route to its
destination.
-
Thus, more and shorter routes means more success in keeping
your trains moving.
Please remember that it's not enough to find a route; you must
also be able to drive a train along it. Driving over a route to
a destination is not too hard, but it must be very robust because
it's a basic capability required for driving two trains at once.
Train-driving failures usually stop execution dead.
You can try a gradually harder approach.
-
Make sure that you really have the train finding the shortest
route using only one train.
-
Make sure that you can route around one or more obstacles by
manually removing an edge from the graph. You should be able to do
this interactively at the keyboard, and you probably want to
display on the terminal which edge(s) have been removed from the
graph.
-
Drive a second train to some point; make sure that you route
around it automatically.
-
Let the second train move in a simple way; make sure that you
can route around.
-
Make two trains route simultaneously.
When you are testing, calculate mentally, or by hand, the shortest
route before you start the train moving. Why?
The human brain has a pronouced recency bias: you will think the
train is correct unless you are sure that you know the answer.
When calculating the length of a path you might want to add some
extra distance every time the train has to turn around. That is,
you are probably most interested in the time a train takes getting
to its destination, and reversing adds significant time.
Driving a Train
Driving a train along a route seems easy. But maybe I am wrong
to think so, because many students seem to have trouble making
it robust. It's highly desirable to have route following robust
enough that it's not giving you trouble. Here's my suggestion,
based on starting with something that's easy, then making it
harder.
-
The easiest way to follow a route is to put all the switches
into the correct state, then drive the train along the route
at a modest speed, maybe 8, at which the train moves reliably
and your software has no trouble keeping up with it.
-
Then speed up making certain that you don't fall behind in
knowing where the train is.
-
In your project several trains will be using the track at
once, and you can't assume that other trains won't want to
use some of your route before you get to it. To minimize
interference you must switch as you go. (We will see later
that coordinating switching and reserving track is very
natural.) Thus, you need to follow the route, switching switches
as you come to them. Make the switches wrong before you test
to ensure that you are not just being lucky.
Collision Avoidance
This would be hard if the trains stopped instantaneously,
but they don't, which makes it harder.
-
You must look ahead into the unknown, and to some extent
unknowable, future.
Your train program must plan ahead, far enough ahead that two
trains on a collision course will be stopped before they collide.
That means you must modify the routes and/or speeds of trains
when they are as much as two stopping distances apart: this can
be more than a metre.
It is usually your method of collision avoidance that limits the
number of trains that can run simultaneously.
-
N trains start running.
-
Then, after a while they get frozen and won't move.
-
Each is waiting for another to move.
-
If N is large freezing usually occurs because the route finder
can't find a route for any train.
-
In the real world freezing rail systems are not uncommon.
They are usually associated with over-full marshalling yards.
CN was the first railroad successfully to implement a solution,
and it was not until the 1980s. The solution is to schedule
freight trains, keeping the tracks and trains is good enough
mechanical condition that they consistently keep their
schedules.
I like distributed solutions, where each train operates -- plans,
drives, make decisions, etc -- as though there are no other trains
on the track. Why do I like this?
-
Global optimization algorithms are rarely (=never) real-time.
-
The code is simple.
-
Each task has a well-defined role. E.g.
-
Track monitor knows the current state of the track.
-
Route planner uses track monitor input to provide a
feasible route.
-
Train driver gets a route and follows it switching turn-outs
ahead of itself as it drives.
-
Structure of inter-task communication arises naturally from
the roles.
-
The solutions usually scale well, requiring only that the
track length grows at least linearly with the number of trains,
which it doesn't in the trains lab. That's why there are
limits, though we don't know them.
Treating the track as a shared resource
Analogy to pixels in a window environment.
A track server gives out and takes back pieces of track.
What policy should it have?
-
Trains can only occupy track they have obtained from the server.
-
The server never gives out pices of track that are already out.
-
A train can only operate on track it owns. In practice, "operate
on" means switching turn-outs and returning reserved track to
the track server.
-
Track should be returned to the track server as soon as a train
leaves it.
-
When a train stops it should retain a reservation only on track
it currently occupies.
-
To avoid leapfrog deadlock, all the track owned by a train must
be contiguous.
The first three are necessary for correctness. Are they sufficient?
The fourth and fifth avoid bugs and improve performance. The sixth
eliminates a surprisingly common bug.
Return to: