00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include <actionlib/client/connection_monitor.h>
00037
00038 #include <sstream>
00039
00040 using namespace std;
00041 using namespace actionlib;
00042
00043
00044 #define CONNECTION_DEBUG(fmt, ...) \
00045 ROS_DEBUG_NAMED("ConnectionMonitor", fmt,##__VA_ARGS__)
00046
00047 #define CONNECTION_WARN(fmt, ...) \
00048 ROS_WARN_NAMED("ConnectionMonitor", fmt,##__VA_ARGS__)
00049
00050
00051 ConnectionMonitor::ConnectionMonitor(ros::Subscriber&feedback_sub, ros::Subscriber& result_sub)
00052 : feedback_sub_(feedback_sub), result_sub_(result_sub)
00053 {
00054 status_received_ = false;
00055 }
00056
00057
00058
00059 void ConnectionMonitor::goalConnectCallback(const ros::SingleSubscriberPublisher& pub)
00060 {
00061 boost::recursive_mutex::scoped_lock lock(data_mutex_);
00062
00063
00064 if (goalSubscribers_.find(pub.getSubscriberName()) == goalSubscribers_.end())
00065 {
00066 CONNECTION_DEBUG("goalConnectCallback: Adding [%s] to goalSubscribers", pub.getSubscriberName().c_str());
00067 goalSubscribers_.insert(pub.getSubscriberName());
00068 }
00069 else
00070 CONNECTION_WARN("goalConnectCallback: Trying to add [%s] to goalSubscribers, but it is already in the goalSubscribers list", pub.getSubscriberName().c_str());
00071 CONNECTION_DEBUG("%s", goalSubscribersString().c_str());
00072
00073 check_connection_condition_.notify_all();
00074 }
00075
00076 void ConnectionMonitor::goalDisconnectCallback(const ros::SingleSubscriberPublisher& pub)
00077 {
00078 boost::recursive_mutex::scoped_lock lock(data_mutex_);
00079
00080 set<string>::iterator it;
00081 it = goalSubscribers_.find(pub.getSubscriberName());
00082
00083 if (it == goalSubscribers_.end())
00084 CONNECTION_WARN("goalDisconnectCallback: Trying to remove [%s] to goalSubscribers, but it is not in the goalSubscribers list", pub.getSubscriberName().c_str());
00085 else
00086 {
00087 CONNECTION_DEBUG("goalDisconnectCallback: Removing [%s] from goalSubscribers", pub.getSubscriberName().c_str());
00088 goalSubscribers_.erase(it);
00089 }
00090 CONNECTION_DEBUG("%s", goalSubscribersString().c_str());
00091 }
00092
00093 string ConnectionMonitor::goalSubscribersString()
00094 {
00095 boost::recursive_mutex::scoped_lock lock(data_mutex_);
00096 ostringstream ss;
00097 ss << "Goal Subscribers (" << goalSubscribers_.size() << " total)";
00098 for (set<string>::iterator it=goalSubscribers_.begin(); it != goalSubscribers_.end(); it++)
00099 ss << "\n - " << *it;
00100 return ss.str();
00101 }
00102
00103
00104
00105 void ConnectionMonitor::cancelConnectCallback(const ros::SingleSubscriberPublisher& pub)
00106 {
00107 boost::recursive_mutex::scoped_lock lock(data_mutex_);
00108
00109
00110 if (cancelSubscribers_.find(pub.getSubscriberName()) == cancelSubscribers_.end())
00111 {
00112 CONNECTION_DEBUG("cancelConnectCallback: Adding [%s] to cancelSubscribers", pub.getSubscriberName().c_str());
00113 cancelSubscribers_.insert(pub.getSubscriberName());
00114 }
00115 else
00116 CONNECTION_WARN("cancelConnectCallback: Trying to add [%s] to cancelSubscribers, but it is already in the cancelSubscribers list", pub.getSubscriberName().c_str());
00117 CONNECTION_DEBUG("%s", cancelSubscribersString().c_str());
00118
00119 check_connection_condition_.notify_all();
00120 }
00121
00122 void ConnectionMonitor::cancelDisconnectCallback(const ros::SingleSubscriberPublisher& pub)
00123 {
00124 boost::recursive_mutex::scoped_lock lock(data_mutex_);
00125
00126 set<string>::iterator it;
00127 it = cancelSubscribers_.find(pub.getSubscriberName());
00128
00129 if (it == cancelSubscribers_.end())
00130 CONNECTION_WARN("cancelDisconnectCallback: Trying to remove [%s] to cancelSubscribers, but it is not in the cancelSubscribers list", pub.getSubscriberName().c_str());
00131 else
00132 {
00133 CONNECTION_DEBUG("cancelDisconnectCallback: Removing [%s] from cancelSubscribers", pub.getSubscriberName().c_str());
00134 cancelSubscribers_.erase(it);
00135 }
00136 CONNECTION_DEBUG("%s", cancelSubscribersString().c_str());
00137 }
00138
00139 string ConnectionMonitor::cancelSubscribersString()
00140 {
00141 boost::recursive_mutex::scoped_lock lock(data_mutex_);
00142
00143 ostringstream ss;
00144 ss << "cancel Subscribers (" << cancelSubscribers_.size() << " total)";
00145 for (set<string>::iterator it=cancelSubscribers_.begin(); it != cancelSubscribers_.end(); it++)
00146 ss << "\n - " << *it;
00147 return ss.str();
00148 }
00149
00150
00151 void ConnectionMonitor::processStatus(const actionlib_msgs::GoalStatusArrayConstPtr& status)
00152 {
00153 boost::recursive_mutex::scoped_lock lock(data_mutex_);
00154
00155 string cur_status_caller_id = (*(status->__connection_header))["callerid"];
00156
00157 if (status_received_)
00158 {
00159 if (status_caller_id_ != cur_status_caller_id)
00160 {
00161 CONNECTION_WARN("processStatus: Previously received status from [%s], but we now received status from [%s]. Did the ActionServer change?",
00162 status_caller_id_.c_str(), cur_status_caller_id.c_str());
00163 status_caller_id_ = cur_status_caller_id;
00164 }
00165 latest_status_time_ = status->header.stamp;
00166 }
00167 else
00168 {
00169 CONNECTION_DEBUG("processStatus: Just got our first status message from the ActionServer at node [%s]", cur_status_caller_id.c_str());
00170 status_received_ = true;
00171 status_caller_id_ = cur_status_caller_id;
00172 latest_status_time_ = status->header.stamp;
00173 }
00174
00175 check_connection_condition_.notify_all();
00176 }
00177
00178
00179 bool ConnectionMonitor::isServerConnected()
00180 {
00181 boost::recursive_mutex::scoped_lock lock(data_mutex_);
00182
00183 if (!status_received_)
00184 {
00185 CONNECTION_DEBUG("isServerConnected: Didn't receive status yet, so not connected yet");
00186 return false;
00187 }
00188
00189 if(goalSubscribers_.find(status_caller_id_) == goalSubscribers_.end())
00190 {
00191 CONNECTION_DEBUG("isServerConnected: Server [%s] has not yet subscribed to the goal topic, so not connected yet", status_caller_id_.c_str());
00192 CONNECTION_DEBUG("%s", goalSubscribersString().c_str());
00193 return false;
00194 }
00195
00196 if(cancelSubscribers_.find(status_caller_id_) == cancelSubscribers_.end())
00197 {
00198 CONNECTION_DEBUG("isServerConnected: Server [%s] has not yet subscribed to the cancel topic, so not connected yet", status_caller_id_.c_str());
00199 CONNECTION_DEBUG("%s", cancelSubscribersString().c_str());
00200 return false;
00201 }
00202
00203 if(feedback_sub_.getNumPublishers() == 0)
00204 {
00205 CONNECTION_DEBUG("isServerConnected: Client has not yet connected to feedback topic of server [%s]", status_caller_id_.c_str());
00206 return false;
00207 }
00208
00209 if(result_sub_.getNumPublishers() == 0)
00210 {
00211 CONNECTION_DEBUG("isServerConnected: Client has not yet connected to result topic of server [%s]", status_caller_id_.c_str());
00212 return false;
00213 }
00214
00215 CONNECTION_DEBUG("isServerConnected: Server [%s] is fully connected", status_caller_id_.c_str());
00216 return true;
00217 }
00218
00219 bool ConnectionMonitor::waitForActionServerToStart(const ros::Duration& timeout, const ros::NodeHandle& nh)
00220 {
00221 if (timeout < ros::Duration(0,0))
00222 ROS_ERROR_NAMED("actionlib", "Timeouts can't be negative. Timeout is [%.2fs]", timeout.toSec());
00223
00224 ros::Time timeout_time = ros::Time::now() + timeout;
00225
00226 boost::recursive_mutex::scoped_lock lock(data_mutex_);
00227
00228 if (isServerConnected())
00229 return true;
00230
00231
00232 ros::Duration loop_period = ros::Duration().fromSec(.5);
00233
00234 while (nh.ok() && !isServerConnected())
00235 {
00236
00237 ros::Duration time_left = timeout_time - ros::Time::now();
00238
00239
00240 if (timeout != ros::Duration(0,0) && time_left <= ros::Duration(0,0) )
00241 break;
00242
00243
00244 if (time_left > loop_period || timeout == ros::Duration())
00245 time_left = loop_period;
00246
00247 check_connection_condition_.timed_wait(lock, boost::posix_time::milliseconds(time_left.toSec() * 1000.0f));
00248 }
00249
00250 return isServerConnected();
00251 }
00252
00253
00254
00255
00256
00257
00258
00259