Mikko Rasa [Tue, 24 Mar 2015 10:28:40 +0000 (12:28 +0200)]
Avoid unnecessary wait time with shared destinations
If a train gets blocked by another train which has already arrived but
has a trip duration, a step must be processed when the blocking train
departs again. Otherwise the next step might be a long time off (in case
all other trains have long departure delays) and would get an overly
inflated cost.
Mikko Rasa [Sun, 22 Mar 2015 15:58:41 +0000 (17:58 +0200)]
Give zones a preferred running direction
It's also reflected in tracks as a preferred exit endpoint to avoid
having to look up zones while routing. Weird things may happen if a
track belongs to multiple zones.
Mikko Rasa [Mon, 2 Mar 2015 21:16:20 +0000 (23:16 +0200)]
Retain addresses of previously seen locomotives
It may happen that a locomotive gets re-enumerated, e.g. after visiting
another layout. Since they are identified by their address, it's useful
to keep the same address.
Mikko Rasa [Mon, 23 Feb 2015 14:42:00 +0000 (16:42 +0200)]
Rewrite goal initialization for TrainRouteMetric
The previous code incorrectly added all tracks as goals when a direction
was specified, instead of only the ends. This caused cost estimate creep
in the route planner, resulting in suboptimal performance.
Mikko Rasa [Mon, 23 Feb 2015 10:17:27 +0000 (12:17 +0200)]
Follow the same path until another is significantly better
This replaces the cost penalty for routing steps. In the penalty approach
it was possible to get two or more steps with the same penalty, which
would then race with each other. In the new approach, all other steps are
sorted by their unpenalized cost and only the preferred one gets special
treatment.
Mikko Rasa [Sat, 21 Feb 2015 19:05:28 +0000 (21:05 +0200)]
Robustify sequence handling while applying route plans
Setting current_sequence of all participating routers to zero beforehand
will make sequence points involving them not cleared and avoid the need
to special case everything.
Mikko Rasa [Fri, 20 Feb 2015 16:40:54 +0000 (18:40 +0200)]
Clear the critical flag one track earlier
Check_arrival is called when the train reaches the end of its current
track. The flag should be cleared when the track it is entering is no
longer critical.
Mikko Rasa [Thu, 19 Feb 2015 09:18:02 +0000 (11:18 +0200)]
Improve ArduControl task scheduling
The new scheduler can handle multiple tasks with the same priority, so
other things won't get blocked by the priority command queue for too
long. It also handles sleeping at the scheduler rather than individual
tasks.
Mikko Rasa [Mon, 16 Feb 2015 00:17:03 +0000 (02:17 +0200)]
Turn ArduControl command_queue into a Task
It seems that I was thinking of this back in d5d8ee8, but left it
unfinished probably because it was simpler to use a Queue directly. Now
some upcoming task management improvements call for it to be a Task.
Mikko Rasa [Sun, 15 Feb 2015 08:40:37 +0000 (10:40 +0200)]
Correct TrackAttachment entry endpoint
Since endpoint direction points outwards from the endpoint, we want to
find one that's as close to opposite to the TrackAttachment's direction
as possible.
Mikko Rasa [Thu, 12 Feb 2015 16:11:06 +0000 (18:11 +0200)]
Be more permissive when checking route continuity
In some cases more than one consecutive route may end on the same track,
or a route might only go one track past the previous one, with that track
being a turnout with undetermined path. Allow skipping routes to deal
with these situations, as long as we don't go completely off route.
Mikko Rasa [Thu, 12 Feb 2015 14:46:45 +0000 (16:46 +0200)]
Fix critical block logic
First noncritical block is not reliable, as it could be outside of the
train's allocated blocks and not guaranteed to set to a consistent path.
Worse, the get_first_noncritical_block function could return a block on
the other side of a turnout which is changing path, and is_block_critical
used completely different logic.
Mikko Rasa [Wed, 11 Feb 2015 18:14:30 +0000 (20:14 +0200)]
Avoid arriving too early if there's an unexpected stop on the last route
If the final block of the route is allocated while the train is stopped,
arrival could be triggered prematurely. I'm not entirely certain if this
can happen in absence of certain quirks of the dummy driver, but better
safe than sorry.
Mikko Rasa [Wed, 11 Feb 2015 15:35:56 +0000 (17:35 +0200)]
Apply all planned routes at once
Letting each router to do it separately in the tick function causes
certain problems with synchronization. In particular, sequence points
are difficult to synchronize unless the route update is atomic.
Mikko Rasa [Wed, 11 Feb 2015 12:43:15 +0000 (14:43 +0200)]
Unify destination and waypoints
Destination is really just a special case of a waypoint, so there's no
point in keeping it separate. It just adds duplicated logic, which was
about to get worse with some upcoming new features.
Mikko Rasa [Wed, 11 Feb 2015 12:06:39 +0000 (14:06 +0200)]
Do not allocate blocks while halt is in effect
A turnout state change signal is emitted even if a failure is detected,
to indicate the end of the operation. Resuming allocation in such a case
would cause the train to stray to an incorrect path. It's better to wait
until the user has resolved the situation and removed the halt state.
Mikko Rasa [Fri, 6 Feb 2015 14:37:46 +0000 (16:37 +0200)]
Make sure Block::signal_reserved is emitted consistently
Sigc++ apparently takes arguments as references, so if someone reached to
a signal with null train by reserving the block again, any remaining slots
of the release emission would also get the new train pointer. This caused
the routing system to malfunction in certain cases as the router saw two
emissions for the same block reservation.
The simplest solution would be to pass t instead of train to emit(), but
then the ordering of the two emissions would be inconsistent. Thus the
additional logic to delay further emissions until the outstanding one is
completed.
Mikko Rasa [Fri, 6 Feb 2015 14:32:18 +0000 (16:32 +0200)]
Consider block deallocation when planning routes
Blocks are not released until a sensor is detriggered. Not taking that
into account could cause situations where the planner tries to drive
trains through a balloon loop which is actually too small for them.
Mikko Rasa [Thu, 5 Feb 2015 14:19:01 +0000 (16:19 +0200)]
Eliminate a possible race condition in thread termination
In the unlikely event that the thread doesn't terminate fast enough after
setting the goal pointer, deleting it would send it a kill signal.
Remove this possibility by explicitly jouning the thread.
Mikko Rasa [Thu, 5 Feb 2015 14:01:13 +0000 (16:01 +0200)]
Allow an undetermined turnout at the beginning of a route
If route plans are regenerated when the train's last vehicle is on the
sensor following a turnout in a points-facing movement, the first track
of the lead route is a turnout with undetermined path. Route_changed
would then try to figure out which route the next allocation will occur
on and fail at the very beginning because advance_to_track refused to
use the undetermined turnout.
Mikko Rasa [Thu, 5 Feb 2015 08:48:48 +0000 (10:48 +0200)]
Penalize steps other than the fastest one
This encourages the planner to follow a single chain of steps and avoids
exploding the state tree too much. In the future this may be replaced by
different speed limits on diverging paths of turnouts (reducing the
ambiguity of fastest path) and an actual heuristic for potential wait time
(giving wait states an implicit penalty).
Mikko Rasa [Tue, 3 Feb 2015 14:23:01 +0000 (16:23 +0200)]
Avoid going past the end of route when a new one is set
Calling stop_at(0) causes the block allocator to immediately resume
allocating blocks. In certain circumstances this would cause an
allocation past the end of the route.