Beispiel #1
0
 /// <summary>
 /// Ons the bot join queue.
 /// </summary>
 /// <param name="bot">The bot.</param>
 internal void onBotJoinQueue(BotNormal bot)
 {
     if (!_managedBots.Contains(bot))
     {
         _managedBots.Add(bot);
     }
 }
Beispiel #2
0
 /// <summary>
 /// Gets the place in queue.
 /// </summary>
 /// <param name="bot">The bot.</param>
 /// <returns></returns>
 public Waypoint getPlaceInQueue(BotNormal bot)
 {
     if (_botsInQueue.Contains(bot))
     {
         return(null);
     }
     else
     {
         return(_placeInQueue[bot]);
     }
 }
Beispiel #3
0
        /// <summary>
        /// Notifies the path manager when the bot has a new destination.
        /// </summary>
        /// <param name="bot">The bot.</param>
        /// <exception cref="System.NotImplementedException"></exception>
        internal void notifyBotNewDestination(BotNormal bot)
        {
            if (bot.DestinationWaypoint == null)
            {
                return;
            }

            if (_queueManagers.ContainsKey(bot.DestinationWaypoint))
            {
                _queueManagers[bot.DestinationWaypoint].onBotJoinQueue(bot);
            }
        }
Beispiel #4
0
            /// <summary>
            /// Updates this instance.
            /// </summary>
            public void Update()
            {
                //no need for managing
                if (_managedBots.Count == 0)
                {
                    return;
                }

                //get locked way points
                LockedWaypoints.Clear();
                _botsInQueue.Clear();

                //is elevator and elevator is in use => lock the destination waypoint
                if (QueueWaypoint.Elevator != null && QueueWaypoint.Elevator.InUse)
                {
                    LockedWaypoints.Add(QueueWaypoint, null);
                }

                //check bot states
                for (int i = 0; i < _managedBots.Count; i++)
                {
                    BotNormal bot = _managedBots[i];

                    var nextWaypoint = bot.NextWaypoint != null ? bot.NextWaypoint : bot.CurrentWaypoint;

                    var currentWaypointInQueue = Queue.Contains(bot.CurrentWaypoint);
                    var nextWaypointInQueue    = Queue.Contains(nextWaypoint);

                    var locksCurrentWaypoint = currentWaypointInQueue && bot.CurrentWaypoint.GetDistance(bot) <= _maxEdgeLength[bot.CurrentWaypoint];

                    // Check whether bot is leaving the queue (only possible at the queue waypoint!)
                    if (// Check whether the bot has a new destination and its current waypoint is the end of the queue
                        (bot.DestinationWaypoint != QueueWaypoint && bot.CurrentWaypoint == QueueWaypoint && !locksCurrentWaypoint) ||
                        // Check whether the bot is already outside the queue area and has a different destination than the queue waypoint
                        (!currentWaypointInQueue && !nextWaypointInQueue && bot.DestinationWaypoint != QueueWaypoint))
                    {
                        //bot leaves elevator?
                        if (QueueWaypoint.Elevator != null && bot == QueueWaypoint.Elevator.usedBy)
                        {
                            QueueWaypoint.Elevator.InUse  = false;
                            QueueWaypoint.Elevator.usedBy = null;
                        }
                        // Not in queue anymore - remove it
                        _managedBots.RemoveAt(i);
                        // Update index (we removed one)
                        i--;
                        // Mark queueing inactive (this is redundant - see below)
                        bot.IsQueueing = false;
                        // Proceed to next bot
                        continue;
                    }

                    //bot in Queue
                    if (currentWaypointInQueue)
                    {
                        _botsInQueue.Add(bot);

                        // Indicate queueing
                        bot.IsQueueing = true;

                        if (bot.CurrentWaypoint != QueueWaypoint)
                        {
                            bot.RequestReoptimization = false; //this bot will be managed by this manager
                        }
                        //add locks
                        if (locksCurrentWaypoint && !LockedWaypoints.ContainsKey(bot.CurrentWaypoint))
                        {
                            LockedWaypoints.Add(bot.CurrentWaypoint, bot);
                        }
                        if (nextWaypointInQueue && !LockedWaypoints.ContainsKey(nextWaypoint))
                        {
                            LockedWaypoints.Add(nextWaypoint, bot);
                        }
                    }

                    //bot reached end of the queue - no active queueing anymore
                    if (_queueWaypointIndices.ContainsKey(bot.CurrentWaypoint) && _queueWaypointIndices[bot.CurrentWaypoint] == 0)
                    {
                        // Mark queueing inactive
                        bot.IsQueueing = false;
                        _botsInQueue.Remove(bot);
                    }
                }

                //if this is an elevator queue, the first way point is locked, when the elevator is in use
                if (QueueWaypoint.Elevator != null && QueueWaypoint.Elevator.InUse && !LockedWaypoints.ContainsKey(QueueWaypoint))
                {
                    LockedWaypoints[QueueWaypoint] = null;
                }

                // Remove bots that finished their cruise
                foreach (var bot in _queueCruisePaths.Where(kvp => kvp.Key.CurrentWaypoint == kvp.Value.Last()).Select(kvp => kvp.Key).ToArray())
                {
                    _queueCruisePaths.Remove(bot);
                }

                // Reset places
                _placeInQueue.Clear();

                // Manage locks for cruising bots
                HashSet <BotNormal> failedCruiseBots = null;

                foreach (var bot in _queueCruisePaths.Keys)
                {
                    // Assert that the bot is in the queue
                    Debug.Assert(_queueAreaXMin <= bot.X && bot.X <= _queueAreaXMax && _queueAreaYMin <= bot.Y && bot.Y <= _queueAreaYMax);
                    // Fetch the waypoint the bot is currently at
                    var realWP            = GetNearestQueueWaypoint(bot.X, bot.Y);
                    int currentQueueIndex = _queueWaypointIndices[realWP];
                    // Lock waypoints that are left for the cruise
                    foreach (var cruiseWP in _queueCruisePaths[bot].Where(wp => _queueWaypointIndices[wp] <= currentQueueIndex))
                    {
                        // If bot is not moving and next waypoint is already blocked by another bot, something went wrong - discard the cruise and lineup regularly
                        if (LockedWaypoints.ContainsKey(cruiseWP) && LockedWaypoints[cruiseWP] != bot)
                        {
                            // Cruise failed - mark for removal
                            if (failedCruiseBots == null)
                            {
                                failedCruiseBots = new HashSet <BotNormal>()
                                {
                                    bot
                                }
                            }
                            ;
                            else
                            {
                                failedCruiseBots.Add(bot);
                            }
                        }
                        else
                        {
                            // Lock waypoint for cruise
                            LockedWaypoints[cruiseWP] = bot;
                        }
                    }
                }
                // Cancel failed cruises
                if (failedCruiseBots != null)
                {
                    foreach (var failedBot in failedCruiseBots)
                    {
                        _queueCruisePaths.Remove(failedBot);
                    }
                }

                // Assign already moving bots
                foreach (var bot in _botsInQueue.Where(bot => bot.CurrentWaypoint != bot.NextWaypoint && bot.NextWaypoint != null))
                {
                    _placeInQueue.Add(bot, bot.NextWaypoint);
                }

                //assign standing bots
                foreach (var bot in _botsInQueue.Where(bot => !_placeInQueue.ContainsKey(bot)))
                {
                    var queueIndex    = _queueWaypointIndices[bot.CurrentWaypoint];
                    var newQueueIndex = -1;
                    if (queueIndex == 0 || LockedWaypoints.ContainsKey(Queue[queueIndex - 1]))
                    {
                        //locked => stay where you are
                        _placeInQueue.Add(bot, bot.CurrentWaypoint);
                        newQueueIndex = queueIndex;
                    }
                    else
                    {
                        //if almost there, just move one up
                        Path path = new Path();
                        if (queueIndex == 1)
                        {
                            LockedWaypoints.Add(Queue[queueIndex - 1], bot);
                            path.AddFirst(_pathManager.GetNodeIdByWaypoint(Queue[queueIndex - 1]), true, 0.0);
                            newQueueIndex = queueIndex - 1;
                        }
                        else
                        {
                            //go as far as you can
                            IEnumerable <Waypoint> lockedPredecessorWaypoints = LockedWaypoints.Keys.Where(q => _queueWaypointIndices[q] < queueIndex);
                            int             targetQueueIndex = lockedPredecessorWaypoints.Any() ? lockedPredecessorWaypoints.Max(w => _queueWaypointIndices[w]) + 1 : QueueWaypoint.Elevator != null ? 1 : 0;
                            List <Waypoint> cruisePath       = new List <Waypoint>();
                            int             nextIndex        = -1;
                            // Build cruise path through queue
                            for (int currentIndex = queueIndex; currentIndex >= targetQueueIndex;)
                            {
                                // Determine next waypoint in queue to go to after this one (consider shortcuts)
                                IEnumerable <Waypoint> shortCuts = Queue[currentIndex].Paths.Where(p => _queueWaypointIndices.ContainsKey(p) && _queueWaypointIndices[p] < currentIndex && targetQueueIndex <= _queueWaypointIndices[p]);
                                nextIndex = currentIndex > targetQueueIndex && shortCuts.Any() ? shortCuts.Min(p => _queueWaypointIndices[p]) : currentIndex - 1;
                                // Check whether a stop is required at the
                                double inboundOrientation = cruisePath.Count >= 1 && currentIndex > targetQueueIndex?Circle.GetOrientation(cruisePath[cruisePath.Count - 1].X, cruisePath[cruisePath.Count - 1].Y, Queue[currentIndex].X, Queue[currentIndex].Y) : double.NaN;

                                double outboundOrientation = cruisePath.Count >= 1 && currentIndex > targetQueueIndex?Circle.GetOrientation(Queue[currentIndex].X, Queue[currentIndex].Y, Queue[nextIndex].X, Queue[nextIndex].Y) : double.NaN;

                                bool stopRequired = !double.IsNaN(inboundOrientation) && Math.Abs(Circle.GetOrientationDifference(inboundOrientation, outboundOrientation)) >= bot.Instance.StraightOrientationTolerance;
                                // Add connection to the overall path
                                LockedWaypoints[Queue[currentIndex]] = bot;
                                bool stopAtNode = currentIndex == queueIndex || currentIndex == targetQueueIndex || stopRequired;
                                path.AddLast(
                                    // The next waypoint to go to
                                    _pathManager.GetNodeIdByWaypoint(Queue[currentIndex]),
                                    // See whether we need to stop at the waypoint (either because it is the last one or the angles do not match - using 10 degrees in radians here, which should be in line with the Graph class of path planning)
                                    stopAtNode,
                                    // Don't wait at all
                                    0.0);
                                // Add the step to the cruise path
                                cruisePath.Add(Queue[currentIndex]);
                                // Update to next index
                                currentIndex = nextIndex;
                            }
                            // Prepare for next node in queue
                            path.NextNodeToPrepareFor = queueIndex != nextIndex && nextIndex >= 0 ? _pathManager.GetNodeIdByWaypoint(Queue[nextIndex]) : -1;
                            // The new index in queue is the targeted one
                            newQueueIndex = targetQueueIndex;
                            // Save path for overwatch
                            _queueCruisePaths[bot] = cruisePath;
                            // Check path
                            for (int i = 0; i < cruisePath.Count - 1; i++)
                            {
                                if (!cruisePath[i].ContainsPath(cruisePath[i + 1]))
                                {
                                    throw new InvalidOperationException();
                                }
                            }
                        }
                        // Set path
                        bot.Path = path;

                        _placeInQueue.Add(bot, Queue[newQueueIndex]);

                        //if the next place is an elevator set it
                        if (_placeInQueue[bot].Elevator != null)
                        {
                            QueueWaypoint.Elevator.InUse  = true;
                            QueueWaypoint.Elevator.usedBy = bot;
                        }
                    }
                }

                //assign bots that are not in the queue

                //search for the first free node in the queue
                int firstFreeNode = Queue.Count - 1;

                while (firstFreeNode > 0 && !LockedWaypoints.ContainsKey(Queue[firstFreeNode - 1]))
                {
                    firstFreeNode--;
                }

                //if this is a queue for an elevator, then do not assign the elevator directly, because others might wait in a queue on a different tier
                if (firstFreeNode == 0 && QueueWaypoint.Elevator != null)
                {
                    firstFreeNode = 1;
                }

                //botsLeftToQueue
                var botsLeftToQueue = _managedBots.Where(bot => !_placeInQueue.ContainsKey(bot)).ToList();

                //while a bot exists with no place in queue
                while (botsLeftToQueue.Count > 0)
                {
                    var nearestBot = botsLeftToQueue[0];
                    var distance   = Queue[firstFreeNode].GetDistance(nearestBot);
                    for (int i = 1; i < botsLeftToQueue.Count; i++)
                    {
                        if (Queue[firstFreeNode].GetDistance(botsLeftToQueue[i]) < distance)
                        {
                            nearestBot = botsLeftToQueue[i];
                            distance   = Queue[firstFreeNode].GetDistance(nearestBot);
                        }
                    }

                    botsLeftToQueue.Remove(nearestBot);
                    _placeInQueue.Add(nearestBot, Queue[firstFreeNode]);

                    firstFreeNode = Math.Min(firstFreeNode + 1, Queue.Count - 1);
                }

                //Last Node should never be blocked
                if (LockedWaypoints.ContainsKey(Queue.Last()))
                {
                    LockedWaypoints.Remove(Queue.Last());
                }
            }
Beispiel #5
0
        /// <summary>
        /// Checks weather the bot can go to the next way point without collisions.
        /// </summary>
        /// <param name="botNormal">The bot.</param>
        /// <param name="currentTime">The current time.</param>
        /// <param name="waypointStart">The way point start.</param>
        /// <param name="waypointEnd">The way point end.</param>
        /// <param name="blockCurrentWaypointUntil">Block duration.</param>
        /// <param name="rotationDuration">Rotation duration.</param>
        /// <returns></returns>
        public bool RegisterNextWaypoint(BotNormal botNormal, double currentTime, double blockCurrentWaypointUntil, double rotationDuration, Waypoint waypointStart, Waypoint waypointEnd)
        {
            //get checkpoints
            var tmpReservations = _reservationTable.CreateIntervals(currentTime, blockCurrentWaypointUntil + rotationDuration, 0.0, botNormal.Physics, _waypointIds[waypointStart], _waypointIds[waypointEnd], true);

            if (tmpReservations == null)
            {
                return(false); //no valid way point
            }
            //if the last node or way point is an elevator way point than add all connected nodes
            if (tmpReservations.Count >= 2)
            {
                var lastReservation  = tmpReservations[tmpReservations.Count - 1];
                var elevatorWaypoint = _waypointIds[lastReservation.Node];
                if (elevatorWaypoint.Elevator != null)
                {
                    var prelastReservation = tmpReservations[tmpReservations.Count - 2];

                    foreach (var waypoint in elevatorWaypoint.Elevator.ConnectedPoints.Where(w => w != elevatorWaypoint))
                    {
                        tmpReservations.Add(new ReservationTable.Interval(_waypointIds[waypoint], prelastReservation.Start, prelastReservation.End));
                        tmpReservations.Add(new ReservationTable.Interval(_waypointIds[waypoint], lastReservation.Start, lastReservation.End));
                    }
                }
            }

            //remove current
            _reservationTable.Remove(_reservations[botNormal]);

            //check if free
            var free = _reservationTable.IntersectionFree(tmpReservations);

            //check if a pod collision can occur
            if (botNormal.Pod != null)
            {
                //checker if there is a static pod
                foreach (var interval in tmpReservations)
                {
                    if (_waypointIds[interval.Node].Pod != null)
                    {
                        //there exists a way point with a pod on it
                        free = false;
                        break;
                    }
                }
            }

            if (free)
            {
                _reservations[botNormal] = tmpReservations;

                //#RealWorldIntegration.start
                if (botNormal.Instance.SettingConfig.RealWorldIntegrationCommandOutput && botNormal.Instance.SettingConfig.LogAction != null)
                {
                    //Log the wait command
                    var sb = new StringBuilder();
                    sb.Append("#RealWorldIntegration => Bot ").Append(botNormal.ID).Append(" Drive: ");

                    if (blockCurrentWaypointUntil - currentTime > 0)
                    {
                        sb.Append("(wait: ").Append(blockCurrentWaypointUntil - currentTime).Append("s)");
                    }

                    for (var i = 1; i < _reservations[botNormal].Count - 1; i++)
                    {
                        sb.Append(_waypointIds[_reservations[botNormal][i].Node].ID).Append(";");
                    }
                    botNormal.Instance.SettingConfig.LogAction(sb.ToString());
                    // Issue the path command
                    Instance.RemoteController.RobotSubmitPath(
                        botNormal.ID,                                                                                                     // The ID of the robot the path is send to
                        blockCurrentWaypointUntil - currentTime,                                                                          // The time the robot shall wait before executing the path
                        _reservations[botNormal].Take(_reservations[botNormal].Count - 1).Select(r => _waypointIds[r.Node].ID).ToList()); // The path to execute
                }
                //#RealWorldIntegration.end
            }

            //Debug
            //Log the wait command

            /*
             * var tmp = new StringBuilder();
             * tmp.Append("Bot ").Append(botNormal.ID).Append(" Drive: ");
             *
             * if (blockCurrentWaypointUntil - currentTime > 0)
             *  tmp.Append("(wait: ").Append(blockCurrentWaypointUntil - currentTime).Append("s)");
             *
             * for (var i = 1; i < _reservations[botNormal].Count - 1; i++)
             *  tmp.Append(_waypointIds[_reservations[botNormal][i].Node].ID).Append(";");
             * botNormal.Instance.Configuration.LogAction(tmp.ToString());
             * if (tmp.ToString().Equals(_lastWaitLog))
             *  botNormal.Instance.Configuration.LogAction("Same Log(for Debugging)");
             * _lastWaitLog = tmp.ToString();
             */

            //(re)add intervals
            _reservationTable.Add(_reservations[botNormal]);

            return(free);
        }
Beispiel #6
0
        /// <summary>
        /// Creates a bot with the given characteristics.
        /// </summary>
        /// <param name="id">The ID of the bot.</param>
        /// <param name="tier">The initial position (tier).</param>
        /// <param name="x">The initial position (x-coordinate).</param>
        /// <param name="y">The initial position (y-coordinate).</param>
        /// <param name="radius">The radius of the bot.</param>
        /// <param name="orientation">The initial orientation.</param>
        /// <param name="podTransferTime">The time for picking up and setting down a pod.</param>
        /// <param name="maxAcceleration">The maximal acceleration in m/s^2.</param>
        /// <param name="maxDeceleration">The maximal deceleration in m/s^2.</param>
        /// <param name="maxVelocity">The maximal velocity in m/s.</param>
        /// <param name="turnSpeed">The time it takes the bot to take a full turn in s.</param>
        /// <param name="collisionPenaltyTime">The penalty time for a collision in s.</param>
        /// <returns>The newly created bot.</returns>
        public Bot CreateBot(int id, Tier tier, double x, double y, double radius, double orientation, double podTransferTime, double maxAcceleration, double maxDeceleration, double maxVelocity, double turnSpeed, double collisionPenaltyTime, bool createMovableStation = false)
        {
            // Consider override values
            if (SettingConfig.OverrideConfig != null && SettingConfig.OverrideConfig.OverrideBotPodTransferTime)
            {
                podTransferTime = SettingConfig.OverrideConfig.OverrideBotPodTransferTimeValue;
            }
            if (SettingConfig.OverrideConfig != null && SettingConfig.OverrideConfig.OverrideBotMaxAcceleration)
            {
                maxAcceleration = SettingConfig.OverrideConfig.OverrideBotMaxAccelerationValue;
            }
            if (SettingConfig.OverrideConfig != null && SettingConfig.OverrideConfig.OverrideBotMaxDeceleration)
            {
                maxDeceleration = SettingConfig.OverrideConfig.OverrideBotMaxDecelerationValue;
            }
            if (SettingConfig.OverrideConfig != null && SettingConfig.OverrideConfig.OverrideBotMaxVelocity)
            {
                maxVelocity = SettingConfig.OverrideConfig.OverrideBotMaxVelocityValue;
            }
            if (SettingConfig.OverrideConfig != null && SettingConfig.OverrideConfig.OverrideBotTurnSpeed)
            {
                turnSpeed = SettingConfig.OverrideConfig.OverrideBotTurnSpeedValue;
            }
            // Init
            Bot            bot = null;
            MovableStation ms  = null;

            if (createMovableStation)
            {
                ms  = new MovableStation(id, this, radius, maxAcceleration, maxDeceleration, maxVelocity, turnSpeed, collisionPenaltyTime, x, y);
                bot = ms;
            }
            else
            {
                switch (ControllerConfig.PathPlanningConfig.GetMethodType())
                {
                case PathPlanningMethodType.Simple:
                    bot = new BotHazard(this, ControllerConfig.PathPlanningConfig as SimplePathPlanningConfiguration);
                    break;

                case PathPlanningMethodType.Dummy:
                case PathPlanningMethodType.WHCAvStar:
                case PathPlanningMethodType.WHCAnStar:
                case PathPlanningMethodType.FAR:
                case PathPlanningMethodType.BCP:
                case PathPlanningMethodType.OD_ID:
                case PathPlanningMethodType.CBS:
                case PathPlanningMethodType.PAS:
                    bot = new BotNormal(id, this, radius, podTransferTime, maxAcceleration, maxDeceleration, maxVelocity, turnSpeed, collisionPenaltyTime, x, y);
                    break;

                default: throw new ArgumentException("Unknown path planning engine: " + ControllerConfig.PathPlanningConfig.GetMethodType());
                }
            }

            // Set values
            bot.ID                   = id;
            bot.Tier                 = tier;
            bot.Instance             = this;
            bot.Radius               = radius;
            bot.X                    = x;
            bot.Y                    = y;
            bot.PodTransferTime      = podTransferTime;
            bot.MaxAcceleration      = maxAcceleration;
            bot.MaxDeceleration      = maxDeceleration;
            bot.MaxVelocity          = maxVelocity;
            bot.TurnSpeed            = turnSpeed;
            bot.CollisionPenaltyTime = collisionPenaltyTime;
            bot.Orientation          = orientation;
            if (bot is BotHazard)
            {
                ((BotHazard)bot).EvadeDistance = 2.3 * radius;
                ((BotHazard)bot).SetTargetOrientation(orientation);
            }
            // Add bot
            if (ms != null)
            {
                ms.Capacity = 1000;
                Bots.Add(ms);
                //bot was referencing only bot-part of movable station and those values were updated
                MovableStations.Add(ms);
            }
            else
            {
                Bots.Add(bot);
            }
            tier.AddBot(bot);
            _idToBots[bot.ID] = bot;
            // Determine volatile ID
            int volatileID = 0;

            while (_volatileBotIDs.Contains(volatileID))
            {
                volatileID++;
            }
            bot.VolatileID = volatileID;
            _volatileBotIDs.Add(bot.VolatileID);
            // Return it
            return(bot);
        }