Beispiel #1
0
        private void CancelCallback(GoalID goalId)
        {
            if (!started)
            {
                return;
            }

            ROS.Debug()("actionlib", "The action server has received a new cancel request");

            if (goalId.id == null)
            {
                var timeZero = DateTime.UtcNow;

                foreach (var valuePair in goalHandles)
                {
                    var goalHandle = valuePair.Value;
                    if ((ROS.ToDateTime(goalId.stamp) == timeZero) || (ROS.ToDateTime(goalHandle.GoalId.stamp) < ROS.ToDateTime(goalId.stamp)))
                    {
                        if (goalHandle.SetCancelRequested() && (cancelCallback != null))
                        {
                            cancelCallback(goalHandle);
                        }
                    }
                }
            }
            else
            {
                ServerGoalHandle <TGoal, TResult, TFeedback> goalHandle;
                var foundGoalHandle = goalHandles.TryGetValue(goalId.id, out goalHandle);
                if (foundGoalHandle)
                {
                    if (goalHandle.SetCancelRequested() && (cancelCallback != null))
                    {
                        cancelCallback(goalHandle);
                    }
                }
                else
                {
                    // We have not received the goal yet, prepare to cancel goal when it is received
                    var goalStatus = new GoalStatus();
                    goalStatus.status = GoalStatus.RECALLING;
                    goalHandle        = new ServerGoalHandle <TGoal, TResult, TFeedback>(this, goalId, goalStatus, null);

                    goalHandle.DestructionTime = ROS.ToDateTime(goalId.stamp);
                    lock (lockGoalHandles)
                    {
                        goalHandles[goalId.id] = goalHandle;
                    }
                }
            }

            // Make sure to set lastCancel based on the stamp associated with this cancel request
            if (ROS.ToDateTime(goalId.stamp) > lastCancel)
            {
                lastCancel = ROS.ToDateTime(goalId.stamp);
            }
        }
Beispiel #2
0
        public void PublishFeedback(GoalStatus goalStatus, TFeedback feedback)
        {
            var newFeedback = new FeedbackActionMessage <TFeedback>();

            newFeedback.Header       = new Messages.std_msgs.Header();
            newFeedback.Header.stamp = ROS.GetTime();
            newFeedback.GoalStatus   = goalStatus;
            newFeedback.Feedback     = feedback;
            ROS.Debug()("actionlib", $"Publishing feedback for goal with id: {goalStatus.goal_id.id} and stamp: " +
                        $"{new DateTimeOffset(ROS.ToDateTime(goalStatus.goal_id.stamp)).ToUnixTimeSeconds()}"
                        );
            feedbackPublisher.Publish(newFeedback);
        }
Beispiel #3
0
        public ServerGoalHandle(IActionServer <TGoal, TResult, TFeedback> actionServer, GoalID goalId, GoalStatus goalStatus,
                                TGoal goal)
        {
            this.actionServer  = actionServer;
            GoalStatus         = goalStatus;
            GoalId             = goalId;
            GoalStatus.goal_id = goalId;

            if ((goalId.stamp == null) || (ROS.ToDateTime(goalId.stamp) == new DateTime(1970, 1, 1, 0, 0, 0)))
            {
                // If stamp is not initialized
                GoalStatus.goal_id.stamp = ROS.GetTime();
            }

            GoalStatus = goalStatus;
            this.Goal  = goal;
        }
Beispiel #4
0
        public void PublishResult(GoalStatus goalStatus, TResult result)
        {
            var newResult = new ResultActionMessage <TResult>();

            newResult.Header       = new Messages.std_msgs.Header();
            newResult.Header.stamp = ROS.GetTime();
            newResult.GoalStatus   = goalStatus;
            if (result != null)
            {
                newResult.Result = result;
            }
            ROS.Debug()("actionlib", $"Publishing result for goal with id: {goalStatus.goal_id.id} and stamp: " +
                        $"{new DateTimeOffset(ROS.ToDateTime(goalStatus.goal_id.stamp)).ToUnixTimeSeconds()}"
                        );
            resultPublisher.Publish(newResult);
            PublishStatus();
        }
Beispiel #5
0
        private void GoalCallback(GoalActionMessage <TGoal> goalAction)
        {
            if (!started)
            {
                return;
            }

            GoalID goalId = goalAction.GoalId;

            ROS.Debug()("actionlib", "The action server has received a new goal request");
            ServerGoalHandle <TGoal, TResult, TFeedback> observedGoalHandle = null;

            if (goalHandles.ContainsKey(goalId.id))
            {
                observedGoalHandle = goalHandles[goalId.id];
            }

            if (observedGoalHandle != null)
            {
                // The goal could already be in a recalling state if a cancel came in before the goal
                if (observedGoalHandle.GoalStatus.status == GoalStatus.RECALLING)
                {
                    observedGoalHandle.GoalStatus.status = GoalStatus.RECALLED;
                    PublishResult(observedGoalHandle.GoalStatus, null); // Empty result
                }
            }
            else
            {
                // Create and register new goal handle
                GoalStatus goalStatus = new GoalStatus();
                goalStatus.status = GoalStatus.PENDING;
                var newGoalHandle = new ServerGoalHandle <TGoal, TResult, TFeedback>(this, goalId,
                                                                                     goalStatus, goalAction.Goal
                                                                                     );
                newGoalHandle.DestructionTime = ROS.ToDateTime(goalId.stamp);
                lock (lockGoalHandles)
                {
                    goalHandles[goalId.id] = newGoalHandle;
                }
                goalCallback?.Invoke(newGoalHandle);
            }
        }
Beispiel #6
0
        private void OnStatusMessage(GoalStatusArray statusArray)
        {
            string callerId;
            var    timestamp       = statusArray.header.stamp;
            bool   callerIdPresent = statusArray.connection_header.TryGetValue("callerid", out callerId);

            if (callerIdPresent)
            {
                ROS.Debug()($"Getting status over the wire (callerid: {callerId}; count: " +
                            $"{statusArray.status_list.Length})."
                            );

                if (statusReceived)
                {
                    if (statusCallerId != callerId)
                    {
                        ROS.Warn()($"onStatusMessage: Previously received status from {statusCallerId}, but we now" +
                                   $" received status from {callerId}. Did the ActionServer change?"
                                   );
                        statusCallerId = callerId;
                    }
                }
                else
                {
                    ROS.Debug()("onStatusMessage: Just got our first status message from the ActionServer at " +
                                $"node {callerId}"
                                );
                    statusReceived = true;
                    statusCallerId = callerId;
                }
                LatestStatusTime = timestamp;
                if (LatestSequenceNumber != null && statusArray.header.seq <= LatestSequenceNumber)
                {
                    ROS.Warn()("Status sequence number was decreased. This can only happen when the action server was restarted. Assume all active goals are lost.");
                    HandleConnectionLost();
                }
                LatestSequenceNumber = statusArray.header.seq;

                // Create a copy of all goal handle references in thread safe environment so it can be looped over all goal
                // handles without blocking the sending of new goals
                Dictionary <string, ClientGoalHandle <TGoal, TResult, TFeedback> > goalHandlesReferenceCopy;
                lock (lockGoalHandles)
                {
                    goalHandlesReferenceCopy = new Dictionary <string, ClientGoalHandle <TGoal, TResult, TFeedback> >(goalHandles);
                }

                // Loop over all goal handles and update their state, mark goal handles that are done for deletion
                var completedGoals = new List <string>();
                foreach (var pair in goalHandlesReferenceCopy)
                {
                    if ((pair.Value.LatestResultAction == null) || (ROS.ToDateTime(pair.Value.LatestResultAction.Header.stamp) < ROS.ToDateTime(timestamp)))
                    {
                        var goalStatus = FindGoalInStatusList(statusArray, pair.Key);
                        UpdateStatus(pair.Value, goalStatus);
                        if (pair.Value.State == CommunicationState.DONE)
                        {
                            completedGoals.Add(pair.Key);
                        }
                    }
                }

                // Remove goal handles that are done from the tracking list
                foreach (var goalHandleId in completedGoals)
                {
                    //Logger.LogInformation($"Remove goal handle id {goalHandleId} from tracked goal handles");
                    lock (lockGoalHandles)
                    {
                        goalHandles.Remove(goalHandleId);
                    }
                }
            }
            else
            {
                ROS.Error()("Received StatusMessage with no caller ID");
            }
        }