00001
00006 #include "yocs_waypoints_navi/waypoints_navi.hpp"
00007
00008
00009
00010
00011
00012
00013
00014 namespace yocs
00015 {
00016
00017 WaypointsGoalNode::WaypointsGoalNode() : mode_(NONE),
00018 state_(IDLE),
00019 frequency_(5),
00020 close_enough_(0.1),
00021 goal_timeout_(60.0),
00022 idle_status_update_sent_(false),
00023 move_base_ac_("move_base", true)
00024 {}
00025
00026 WaypointsGoalNode::~WaypointsGoalNode()
00027 {}
00028
00029 bool WaypointsGoalNode::init()
00030 {
00031 ros::NodeHandle nh;
00032 ros::NodeHandle pnh("~");
00033
00034 pnh.param("frequency", frequency_, 1.0);
00035 pnh.param("close_enough", close_enough_, 0.3);
00036 pnh.param("goal_timeout", goal_timeout_, 30.0);
00037 pnh.param("robot_frame", robot_frame_, std::string("/base_footprint"));
00038 pnh.param("world_frame", world_frame_, std::string("/map"));
00039
00040
00041 waypoints_.clear();
00042 waypoints_it_ = waypoints_.end();
00043
00044 while ((move_base_ac_.waitForServer(ros::Duration(1.0)) == false) && (ros::ok() == true))
00045 {
00046 ROS_WARN_THROTTLE(1, "Waiting for move_base action server to come up...");
00047 }
00048 waypoints_sub_ = nh.subscribe("waypoints", 1, &WaypointsGoalNode::waypointsCB, this);
00049 trajectories_sub_ = nh.subscribe("trajectories", 1, &WaypointsGoalNode::trajectoriesCB, this);
00050 nav_ctrl_sub_ = nh.subscribe("nav_ctrl", 1, &WaypointsGoalNode::navCtrlCB, this);
00051 status_pub_ = nh.advertise<yocs_msgs::NavigationControlStatus>("nav_ctrl_status", 1, true);
00052
00053 return true;
00054 }
00055
00056 void WaypointsGoalNode::waypointsCB(const yocs_msgs::WaypointList::ConstPtr& wps)
00057 {
00058 wp_list_ = *wps;
00059 ROS_INFO_STREAM("Received " << wp_list_.waypoints.size() << " way points.");
00060 }
00061
00062 void WaypointsGoalNode::trajectoriesCB(const yocs_msgs::TrajectoryList::ConstPtr& trajs)
00063 {
00064 traj_list_ = *trajs;
00065 ROS_INFO_STREAM("Received " << traj_list_.trajectories.size() << " trajectories.");
00066 }
00067
00068 void WaypointsGoalNode::navCtrlCB(const yocs_msgs::NavigationControl::ConstPtr& nav_ctrl)
00069 {
00070 if (nav_ctrl->control == yocs_msgs::NavigationControl::STOP)
00071 {
00072 if ((state_ == START) || (state_ == ACTIVE))
00073 {
00074 ROS_INFO_STREAM("Stopping current execution ...");
00075 cancelAllGoals();
00076 resetWaypoints();
00077 ROS_INFO_STREAM("Current execution stopped.");
00078 idle_status_update_sent_ = false;
00079 state_ = IDLE;
00080 publishStatusUpdate(yocs_msgs::NavigationControlStatus::CANCELLED);
00081 }
00082 else
00083 {
00084 ROS_WARN_STREAM("Cannot stop way point/trajectory execution, because nothing is being executed.");
00085 }
00086 }
00087 else if ((nav_ctrl->control == yocs_msgs::NavigationControl::START))
00088 {
00089 if ((state_ == IDLE) || (state_ == COMPLETED))
00090 {
00091 resetWaypoints();
00092
00093 bool goal_found = false;
00094 for (unsigned int wp = 0; wp < wp_list_.waypoints.size(); ++wp)
00095 {
00096 if (nav_ctrl->goal_name == wp_list_.waypoints[wp].name)
00097 {
00098 geometry_msgs::PoseStamped pose;
00099 pose.header = wp_list_.waypoints[wp].header;
00100 pose.pose = wp_list_.waypoints[wp].pose;
00101 waypoints_.push_back(pose);
00102 waypoints_it_ = waypoints_.begin();
00103 goal_found = true;
00104 ROS_INFO_STREAM("Prepared to navigate to way point '" << nav_ctrl->goal_name << "'.");
00105 continue;
00106 }
00107 }
00108 if (!goal_found)
00109 {
00110 for (unsigned int traj = 0; traj < traj_list_.trajectories.size(); ++traj)
00111 {
00112 if (nav_ctrl->goal_name == traj_list_.trajectories[traj].name)
00113 {
00114 for (unsigned int wp = 0; wp < traj_list_.trajectories[traj].waypoints.size(); ++wp)
00115 {
00116 geometry_msgs::PoseStamped pose;
00117 pose.header = traj_list_.trajectories[traj].waypoints[wp].header;
00118 pose.pose = traj_list_.trajectories[traj].waypoints[wp].pose;
00119 waypoints_.push_back(pose);
00120 }
00121 waypoints_it_ = waypoints_.begin();
00122 goal_found = true;
00123 ROS_INFO_STREAM("Prepared to navigate along the trajectory '" << nav_ctrl->goal_name << "'.");
00124 ROS_INFO_STREAM("# of way points = " << waypoints_.size());
00125 }
00126 }
00127 }
00128 if (goal_found)
00129 {
00130 state_ = START;
00131 mode_ = GOAL;
00132 }
00133 else
00134 {
00135 ROS_WARN_STREAM("Could not find provided way point or trajectory.");
00136 }
00137 }
00138 else
00139 {
00140 ROS_WARN_STREAM("Cannot start way point/trajectory execution, because navigator is currently active. "
00141 << "Please stop current activity first.");
00142 }
00143 }
00144 else
00145 {
00146
00147 ROS_WARN_STREAM("'Pause' not yet implemented.");
00148 }
00149 }
00150
00151 bool WaypointsGoalNode::cancelAllGoals(double timeout)
00152 {
00153 actionlib::SimpleClientGoalState goal_state = move_base_ac_.getState();
00154 if ((goal_state != actionlib::SimpleClientGoalState::ACTIVE) &&
00155 (goal_state != actionlib::SimpleClientGoalState::PENDING) &&
00156 (goal_state != actionlib::SimpleClientGoalState::RECALLED) &&
00157 (goal_state != actionlib::SimpleClientGoalState::PREEMPTED))
00158 {
00159
00160 ROS_WARN("Cannot cancel move base goal, as it has %s state!", goal_state.toString().c_str());
00161 publishStatusUpdate(yocs_msgs::NavigationControlStatus::ERROR);
00162 return true;
00163 }
00164
00165 ROS_INFO("Canceling move base goal with %s state...", goal_state.toString().c_str());
00166 move_base_ac_.cancelAllGoals();
00167 if (move_base_ac_.waitForResult(ros::Duration(timeout)) == false)
00168 {
00169 ROS_WARN("Cancel move base goal didn't finish after %.2f seconds: %s",
00170 timeout, goal_state.toString().c_str());
00171 publishStatusUpdate(yocs_msgs::NavigationControlStatus::ERROR);
00172 return false;
00173 }
00174
00175 ROS_INFO("Cancel move base goal succeed. New state is %s", goal_state.toString().c_str());
00176 publishStatusUpdate(yocs_msgs::NavigationControlStatus::CANCELLED);
00177 return true;
00178 }
00179
00180 void WaypointsGoalNode::resetWaypoints()
00181 {
00182 ROS_DEBUG("Full reset: clear markers, delete waypoints and goal and set state to IDLE");
00183 waypoints_.clear();
00184 waypoints_it_ = waypoints_.end();
00185 goal_ = NOWHERE;
00186 mode_ = NONE;
00187 }
00188
00189 void WaypointsGoalNode::spin()
00190 {
00191 move_base_msgs::MoveBaseGoal mb_goal;
00192
00193 ros::Rate rate(frequency_);
00194
00195 while (ros::ok())
00196 {
00197 rate.sleep();
00198 ros::spinOnce();
00199
00200 if (state_ == START)
00201 {
00202 if (mode_ == LOOP)
00203 {
00204 if (waypoints_it_ == waypoints_.end())
00205 {
00206 waypoints_it_ = waypoints_.begin();
00207 }
00208 }
00209
00210 if (waypoints_it_ < waypoints_.end())
00211 {
00212 mb_goal.target_pose.header.stamp = ros::Time::now();
00213 mb_goal.target_pose.header.frame_id = waypoints_it_->header.frame_id;
00214 mb_goal.target_pose.pose = waypoints_it_->pose;
00215
00216
00217 ROS_INFO("New goal: %.2f, %.2f, %.2f",
00218 mb_goal.target_pose.pose.position.x, mb_goal.target_pose.pose.position.y,
00219 tf::getYaw(mb_goal.target_pose.pose.orientation));
00220 move_base_ac_.sendGoal(mb_goal);
00221
00222 publishStatusUpdate(yocs_msgs::NavigationControlStatus::RUNNING);
00223
00224 state_ = ACTIVE;
00225 }
00226 else
00227 {
00228 ROS_ERROR_STREAM("Cannot start execution. Already at the last way point.");
00229 idle_status_update_sent_ = false;
00230 state_ = IDLE;
00231 }
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248 }
00249 else if (state_ == ACTIVE)
00250 {
00251 actionlib::SimpleClientGoalState goal_state = move_base_ac_.getState();
00252
00253
00254 if ((goal_state == actionlib::SimpleClientGoalState::ACTIVE) ||
00255 (goal_state == actionlib::SimpleClientGoalState::PENDING) ||
00256 (goal_state == actionlib::SimpleClientGoalState::RECALLED) ||
00257 (goal_state == actionlib::SimpleClientGoalState::PREEMPTED))
00258 {
00259
00260 if ((ros::Time::now() - mb_goal.target_pose.header.stamp).toSec() >= goal_timeout_)
00261 {
00262 ROS_WARN("Cannot reach goal after %.2f seconds; request a new one (current state is %s)",
00263 goal_timeout_, move_base_ac_.getState().toString().c_str());
00264 if (waypoints_it_ < (waypoints_.end() - 1))
00265 {
00266 ROS_INFO_STREAM("Requesting next way point.");
00267 waypoints_it_++;
00268 state_ = START;
00269 }
00270 else
00271 {
00272 ROS_INFO_STREAM("No more way points to go to.");
00273 state_ = COMPLETED;
00274 }
00275 }
00276
00277
00278 if (waypoints_it_ < (waypoints_.end() - 1))
00279 {
00280 tf::StampedTransform robot_gb, goal_gb;
00281 try
00282 {
00283 tf_listener_.lookupTransform(world_frame_, robot_frame_, ros::Time(0.0), robot_gb);
00284 }
00285 catch (tf::TransformException& e)
00286 {
00287 ROS_WARN("Cannot get tf %s -> %s: %s", world_frame_.c_str(), robot_frame_.c_str(), e.what());
00288 continue;
00289 }
00290
00291 mtk::pose2tf(mb_goal.target_pose, goal_gb);
00292 double distance = mtk::distance2D(robot_gb, goal_gb);
00293 if (distance <= close_enough_)
00294 {
00295 waypoints_it_++;
00296 state_ = START;
00297 ROS_INFO("Close enough to current goal (%.2f <= %.2f m).", distance, close_enough_);
00298 ROS_INFO_STREAM("Requesting next way point.");
00299 }
00300 else
00301 {
00302
00303 }
00304 }
00305 else
00306 {
00307
00308 }
00309 }
00310 else
00311 {
00312 if (goal_state == actionlib::SimpleClientGoalState::SUCCEEDED)
00313 {
00314 ROS_INFO("Go to goal successfully completed: %.2f, %.2f, %.2f",
00315 mb_goal.target_pose.pose.position.x, mb_goal.target_pose.pose.position.y,
00316 tf::getYaw(mb_goal.target_pose.pose.orientation));
00317 if (waypoints_it_ < (waypoints_.end() - 1))
00318 {
00319 ROS_INFO_STREAM("Requesting next way point.");
00320 waypoints_it_++;
00321 state_ = START;
00322 }
00323 else
00324 {
00325 ROS_INFO_STREAM("Reached final way point.");
00326 state_ = COMPLETED;
00327 }
00328 }
00329 else
00330 {
00331 ROS_ERROR("Go to goal failed: %s.", move_base_ac_.getState().toString().c_str());
00332 if (waypoints_it_ < (waypoints_.end() - 1))
00333 {
00334 ROS_INFO_STREAM("Requesting next way point.");
00335 waypoints_it_++;
00336 state_ = START;
00337 }
00338 else
00339 {
00340 ROS_INFO_STREAM("No more way points to go to.");
00341 state_ = COMPLETED;
00342 }
00343 }
00344 }
00345 }
00346 else if(state_ == COMPLETED)
00347 {
00348
00349 publishStatusUpdate(yocs_msgs::NavigationControlStatus::COMPLETED);
00350 idle_status_update_sent_ = false;
00351 state_ = IDLE;
00352 }
00353 else
00354 {
00355 if (!idle_status_update_sent_)
00356 {
00357 publishStatusUpdate(yocs_msgs::NavigationControlStatus::IDLING);
00358 idle_status_update_sent_ = true;
00359 }
00360 }
00361 }
00362 }
00363
00364 bool WaypointsGoalNode::equals(const geometry_msgs::PoseStamped& a, const geometry_msgs::PoseStamped& b)
00365 {
00366 return ((a.pose.position.x == b.pose.position.x) &&
00367 (a.pose.position.y == b.pose.position.y) &&
00368 (a.pose.position.z == b.pose.position.z));
00369
00370 }
00371
00372 bool WaypointsGoalNode::equals(const geometry_msgs::Point& a, const geometry_msgs::Point& b)
00373 {
00374 return ((a.x == b.x) && (a.y == b.y) && (a.z == b.z));
00375 }
00376
00377 void WaypointsGoalNode::publishStatusUpdate(const uint8_t& status)
00378 {
00379 yocs_msgs::NavigationControlStatus msg;
00380 if (status == yocs_msgs::NavigationControlStatus::IDLING)
00381 {
00382 msg.status = yocs_msgs::NavigationControlStatus::IDLING;
00383 msg.status_desc = "Idling";
00384 status_pub_.publish(msg);
00385 }
00386 else if (status == yocs_msgs::NavigationControlStatus::RUNNING)
00387 {
00388 msg.status = yocs_msgs::NavigationControlStatus::RUNNING;
00389 msg.status_desc = "Navigating to way point.";
00390 status_pub_.publish(msg);
00391 }
00392 else if (status == yocs_msgs::NavigationControlStatus::PAUSED)
00393 {
00394 msg.status = yocs_msgs::NavigationControlStatus::PAUSED;
00395 msg.status_desc = "Navigation on hold.";
00396 status_pub_.publish(msg);
00397 }
00398 else if (status == yocs_msgs::NavigationControlStatus::COMPLETED)
00399 {
00400 msg.status = yocs_msgs::NavigationControlStatus::COMPLETED;
00401 msg.status_desc = "Reached final destination.";
00402 status_pub_.publish(msg);
00403 }
00404 else if (status == yocs_msgs::NavigationControlStatus::CANCELLED)
00405 {
00406 msg.status = yocs_msgs::NavigationControlStatus::CANCELLED;
00407 msg.status_desc = "Navigation cancelled.";
00408 status_pub_.publish(msg);
00409 }
00410 else if (status == yocs_msgs::NavigationControlStatus::ERROR)
00411 {
00412 msg.status = yocs_msgs::NavigationControlStatus::ERROR;
00413 msg.status_desc = "An error occurred.";
00414 status_pub_.publish(msg);
00415 }
00416 else
00417 {
00418 ROS_ERROR_STREAM("Cannot publish unknown status updated!");
00419 }
00420 }
00421
00422 }
00423