00001 #include <nj_escape_crossing/crossing_escaper.h>
00002
00003 namespace nj_escape_crossing
00004 {
00005
00006 CrossingEscaper::CrossingEscaper(std::string name, double escape_distance) :
00007 lama_jockeys::NavigatingJockey(name),
00008 kp_v_(0.1),
00009 kp_w_(0.2),
00010 min_linear_velocity_(0),
00011 max_linear_velocity_(0),
00012 min_angular_velocity_(0),
00013 max_angular_velocity_(0),
00014 escape_distance_(escape_distance),
00015 distance_reached_(0.1),
00016 max_angle_turn_only_(1.0),
00017 max_odometry_age_(0.1),
00018 exit_angle_topic_name_("exit_angle"),
00019 start_reached_(false),
00020 angle_reached_(false),
00021 goal_reached_(false),
00022 has_odometry_(false),
00023 has_direction_(false),
00024 crossing_interface_name_("crossing"),
00025 exit_angle_interface_name_("exit_angle"),
00026 last_dtheta_(0)
00027 {
00028 ros::NodeHandle private_nh("~");
00029 private_nh.getParam("kp_v", kp_v_);
00030 private_nh.getParam("kp_w", kp_w_);
00031 private_nh.getParam("min_linear_velocity", min_linear_velocity_);
00032 private_nh.getParam("max_linear_velocity", max_linear_velocity_);
00033 private_nh.getParam("min_angular_velocity", min_angular_velocity_);
00034 private_nh.getParam("max_angular_velocity", max_angular_velocity_);
00035 private_nh.getParam("escape_distance", escape_distance_);
00036 private_nh.getParam("distance_reached", distance_reached_);
00037 private_nh.getParam("max_angle_turn_only", max_angle_turn_only_);
00038 private_nh.getParam("max_odometry_age", max_odometry_age_);
00039 private_nh.getParam("crossing_interface_name", crossing_interface_name_);
00040 private_nh.getParam("exit_angle_interface_name", exit_angle_interface_name_);
00041 private_nh.getParam("exit_angle_topic", exit_angle_topic_name_);
00042
00043 crossing_getter_ = nh_.serviceClient<lama_msgs::GetCrossing>(crossing_interface_name_ + "_getter");
00044 exit_angle_getter_ = nh_.serviceClient<lama_interfaces::GetDouble>(exit_angle_interface_name_ + "_getter");
00045 }
00046
00052 void CrossingEscaper::onTraverse()
00053 {
00054
00055
00056
00057 ROS_DEBUG_STREAM(jockey_name_ << ": received action TRAVERSE");
00058
00059 if (!getDistanceToEscape())
00060 {
00061 server_.setAborted();
00062 return;
00063 }
00064 else if (distance_to_escape_ < 1e-10)
00065 {
00066 result_.final_state = lama_jockeys::NavigateResult::DONE;
00067 result_.completion_time = ros::Duration(0.0);
00068 server_.setSucceeded(result_);
00069 return;
00070 }
00071
00072 twist_publisher_ = private_nh_.advertise<geometry_msgs::Twist>("cmd_vel", 1);
00073 odometry_subscriber_ = private_nh_.subscribe("odom", 1, &CrossingEscaper::odometry_callback, this);
00074
00075 getExitDirection();
00076
00077 start_position_ = odometry_;
00078 feedback_.completion = 0.01;
00079 server_.publishFeedback(feedback_);
00080
00081 geometry_msgs::Twist twist;
00082
00083 ros::Rate r(50);
00084 while (ros::ok())
00085 {
00086 if (server_.isPreemptRequested() && !ros::ok())
00087 {
00088 ROS_INFO_STREAM(jockey_name_ << ": Preempted");
00089
00090 server_.setPreempted();
00091 twist_publisher_.publish(geometry_msgs::Twist());
00092 break;
00093 }
00094
00095
00096 if ((ros::Time::now() - odometry_.header.stamp) > ros::Duration(max_odometry_age_))
00097 {
00098 ROS_WARN("No Odometry received within %.3f s, setting Twist to 0 (odometry age: %.3f s)",
00099 max_odometry_age_, (ros::Time::now() - odometry_.header.stamp).toSec());
00100 twist_publisher_.publish(geometry_msgs::Twist());
00101 continue;
00102 }
00103
00104 if (!start_reached_)
00105 {
00106 geometry_msgs::Point goal = goalFromOdometry(
00107 goal_.relative_edge_start.position.x,
00108 goal_.relative_edge_start.position.y);
00109 start_reached_ = goToGoal(goal, twist);
00110 twist_publisher_.publish(twist);
00111
00112 if (start_reached_)
00113 {
00114 start_position_ = odometry_;
00115 }
00116 }
00117 else if (!angle_reached_)
00118 {
00119 angle_reached_ = turnToAngle(direction_, twist);
00120 twist_publisher_.publish(twist);
00121 if (angle_reached_)
00122 {
00123 ROS_DEBUG_STREAM(jockey_name_ << ": angle reached");
00124 last_dtheta_ = 0;
00125 feedback_.completion = 0.25;
00126 server_.publishFeedback(feedback_);
00127 }
00128 }
00129 else if (!goal_reached_)
00130 {
00131 geometry_msgs::Point goal = goalFromOdometry(
00132 (distance_to_escape_ + distance_reached_) * std::cos(direction_),
00133 (distance_to_escape_ + distance_reached_) * std::sin(direction_));
00134 goal_reached_ = goToGoal(goal, twist);
00135 twist_publisher_.publish(twist);
00136 }
00137 else
00138 {
00139
00140 feedback_.completion = 1;
00141 server_.publishFeedback(feedback_);
00142
00143
00144
00145
00146 ROS_DEBUG("%s: goal reached", jockey_name_.c_str());
00147 result_.final_state = lama_jockeys::NavigateResult::DONE;
00148 result_.completion_time = ros::Time::now() - getStartTime() - getInterruptionsDuration();
00149 server_.setSucceeded(result_);
00150 break;
00151 }
00152 ros::spinOnce();
00153 r.sleep();
00154 }
00155 angle_reached_ = false;
00156 goal_reached_ = false;
00157 }
00158
00159 void CrossingEscaper::onStop()
00160 {
00161 twist_publisher_.publish(geometry_msgs::Twist());
00162 result_.final_state = lama_jockeys::NavigateResult::DONE;
00163 result_.completion_time = ros::Duration(0);
00164 server_.setSucceeded(result_);
00165 start_reached_ = false;
00166 angle_reached_ = false;
00167 goal_reached_ = false;
00168 has_odometry_ = false;
00169 has_direction_ = false;
00170 }
00171
00172 void CrossingEscaper::odometry_callback(const nav_msgs::Odometry& odometry)
00173 {
00174 odometry_ = odometry;
00175 has_odometry_ = true;
00176 }
00177
00178 void CrossingEscaper::direction_callback(const std_msgs::Float32& direction)
00179 {
00180 direction_ = direction.data;
00181 has_direction_ = true;
00182 }
00183
00191 bool CrossingEscaper::getDistanceToEscape()
00192 {
00193 if (escape_distance_ < 1e-10)
00194 {
00195
00196 if (!getCrossing())
00197 {
00198 ROS_ERROR_STREAM(jockey_name_ <<
00199 ": escape_distance not set and no Crossing found, aborting...");
00200 return false;
00201 }
00202 if (crossing_.radius == 0)
00203 {
00204
00205 ROS_WARN("Crossing descriptor to be used as escape distance but radius is 0, DONE");
00206 return true;
00207 }
00208 distance_to_escape_ = crossing_.radius;
00209 }
00210 else
00211 {
00212 distance_to_escape_ = escape_distance_;
00213 }
00214 ROS_DEBUG("Distance to escape: %.3f m", distance_to_escape_);
00215 return true;
00216 }
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227 bool CrossingEscaper::getCrossing()
00228 {
00229 if (goal_.edge.id != 0)
00230 {
00231 lama_interfaces::ActOnMap map_action;
00232 map_action.request.action = lama_interfaces::ActOnMapRequest::GET_DESCRIPTOR_LINKS;
00233 map_action.request.interface_name = crossing_interface_name_;
00234 if (goal_.edge.references.empty())
00235 {
00236 ROS_INFO("goal.edge (id: %d) should be have references, probably not an edge",
00237 goal_.edge.id);
00238 return false;
00239 }
00240 map_action.request.object.id = goal_.edge.references[0];
00241 map_action.request.interface_name = crossing_interface_name_;
00242 if (!map_agent_.call(map_action))
00243 {
00244 ROS_ERROR("Failed to call map agent");
00245 return false;
00246 }
00247 if (map_action.response.descriptor_links.empty())
00248 {
00249 ROS_DEBUG("No crossing descriptor for vertex %d", map_action.request.object.id);
00250 return false;
00251 }
00252 if (map_action.response.descriptor_links.size() > 1)
00253 {
00254 ROS_WARN("More than one crossing descriptor for vertex %d, taking the first one (id %d)",
00255 map_action.request.object.id, map_action.response.descriptor_links[0].descriptor_id);
00256 }
00257 return retrieveCrossingFromMap(map_action.response.descriptor_links[0].descriptor_id);
00258 }
00259 else
00260 {
00261 ROS_DEBUG("Goal.edge.id not set, getting descriptor id from goal.descriptor_link (id %d)",
00262 goal_.descriptor_link.descriptor_id);
00263 return retrieveCrossingFromMap(goal_.descriptor_link.descriptor_id);
00264 }
00265 }
00266
00267
00268
00269
00270
00271
00272
00273
00274 bool CrossingEscaper::retrieveCrossingFromMap(const int32_t descriptor_id)
00275 {
00276 lama_msgs::GetCrossing crossing_srv;
00277 crossing_srv.request.id = descriptor_id;
00278 if (!crossing_getter_.call(crossing_srv))
00279 {
00280 ROS_ERROR_STREAM(jockey_name_ << ": failed to get Crossing with id " <<
00281 descriptor_id << " and interface " << crossing_interface_name_ <<
00282 " (service " << crossing_getter_.getService() << ")");
00283 return false;
00284 }
00285 crossing_ = crossing_srv.response.descriptor;
00286 return true;
00287 }
00288
00298 void CrossingEscaper::getExitDirection()
00299 {
00300 if (!getExitAngleFromMap())
00301 {
00302
00303 ros::Subscriber direction_subscriber = private_nh_.subscribe(exit_angle_topic_name_, 1,
00304 &CrossingEscaper::direction_callback, this);
00305
00306
00307 ros::Duration(0.2).sleep();
00308 ros::spinOnce();
00309 ros::Duration(0.1).sleep();
00310 while (!(has_odometry_ && has_direction_))
00311 {
00312 ros::spinOnce();
00313 ROS_WARN_STREAM_THROTTLE(5, "Waiting for odometry on topic " << odometry_subscriber_.getTopic() <<
00314 " and exit_angle on topic " << direction_subscriber.getTopic());
00315 ros::Duration(0.01).sleep();
00316 }
00317 has_odometry_ = false;
00318 has_direction_ = false;
00319
00320
00321 }
00322 else
00323 {
00324
00325
00326 ros::Duration(0.2).sleep();
00327 ros::spinOnce();
00328 ros::Duration(0.1).sleep();
00329 while (!has_odometry_)
00330 {
00331 ros::spinOnce();
00332 ROS_WARN_STREAM_THROTTLE(5, "Waiting for odometry on topic " << odometry_subscriber_.getTopic());
00333 ros::Duration(0.01).sleep();
00334 }
00335 has_odometry_ = false;
00336 }
00337
00338
00339
00340 direction_ += tf::getYaw(goal_.relative_edge_start.orientation);
00341 }
00342
00347 bool CrossingEscaper::getExitAngleFromMap()
00348 {
00349 if (goal_.edge.id == 0)
00350 {
00351
00352 return false;
00353 }
00354
00355 lama_interfaces::ActOnMap map_action;
00356 map_action.request.action = lama_interfaces::ActOnMapRequest::GET_DESCRIPTOR_LINKS;
00357 map_action.request.object.id = goal_.edge.id;
00358 map_action.request.interface_name = exit_angle_interface_name_;
00359 map_agent_.call(map_action);
00360 if (map_action.response.descriptor_links.empty())
00361 {
00362 ROS_WARN_STREAM("No exit angle descriptor for edge " << map_action.request.object.id <<
00363 " on interface " << exit_angle_interface_name_);
00364 return false;
00365 }
00366 if (map_action.response.descriptor_links.size() > 1)
00367 {
00368 ROS_WARN("More than one exit angle descriptor for edge %d, taking the first one",
00369 map_action.request.object.id);
00370 }
00371 lama_interfaces::GetDouble exit_angle_srv;
00372 exit_angle_srv.request.id = map_action.response.descriptor_links[0].descriptor_id;
00373 if (!exit_angle_getter_.call(exit_angle_srv))
00374 {
00375 ROS_ERROR_STREAM(jockey_name_ << ": failed to get exit_angle with id " <<
00376 exit_angle_srv.request.id << " and interface " << exit_angle_interface_name_ <<
00377 " (service " << exit_angle_getter_.getService() << ")");
00378 return false;
00379 }
00380 direction_ = exit_angle_srv.response.descriptor;
00381 return true;
00382 }
00383
00390 bool CrossingEscaper::turnToAngle(double direction, geometry_msgs::Twist& twist)
00391 {
00392 const double yaw_now= tf::getYaw(odometry_.pose.pose.orientation);
00393 const double dtheta = angles::shortest_angular_distance(yaw_now, direction);
00394 ROS_DEBUG("dtheta to goal: %.3f", dtheta);
00395
00396 double wz = kp_w_ * dtheta;
00397
00398
00399 if ((wz > 0) && (wz < min_angular_velocity_))
00400 {
00401 wz = min_angular_velocity_;
00402 }
00403 else if ((wz < 0) && (wz > -min_angular_velocity_))
00404 {
00405 wz = -min_angular_velocity_;
00406 }
00407 twist.linear.x = 0;
00408 twist.angular.z = wz;
00409
00410
00411 bool angle_reached = (dtheta * last_dtheta_ < -1e-10) && (dtheta < M_PI_2);
00412 last_dtheta_ = dtheta;
00413 return angle_reached;
00414 }
00415
00422 bool CrossingEscaper::goToGoal(const geometry_msgs::Point& goal, geometry_msgs::Twist& twist)
00423 {
00424
00425 ros::NodeHandle private_nh("~");
00426 private_nh.getParamCached("kp_v", kp_v_);
00427 private_nh.getParamCached("kp_w", kp_w_);
00428 private_nh.getParamCached("min_linear_velocity", min_linear_velocity_);
00429 private_nh.getParamCached("max_linear_velocity", max_linear_velocity_);
00430 private_nh.getParamCached("min_angular_velocity", min_angular_velocity_);
00431 private_nh.getParamCached("max_angular_velocity", max_angular_velocity_);
00432
00433 ROS_DEBUG("goal: (%.3f, %.3f)", goal.x, goal.y);
00434 double distance = std::sqrt(goal.x * goal.x + goal.y * goal.y);
00435
00436 if (distance < distance_reached_)
00437 {
00438
00439 twist = geometry_msgs::Twist();
00440 return true;
00441 }
00442
00443 double dtheta = std::atan2(goal.y, goal.x);
00444
00445 if (std::fabs(dtheta) > max_angle_turn_only_)
00446 {
00447
00448 distance = 0.0;
00449 }
00450
00451
00452
00453 double vx = kp_v_ * distance;
00454 double wz = kp_w_ * dtheta;
00455
00456
00457 if ((vx < min_linear_velocity_) && (std::abs(distance) > 1e-10) && (std::abs(wz) < min_angular_velocity_))
00458 {
00459 vx = min_linear_velocity_;
00460 }
00461 if ((wz > 0) && (wz < min_angular_velocity_) && (vx < min_linear_velocity_))
00462 {
00463 wz = min_angular_velocity_;
00464 }
00465 else if ((wz < 0) && (wz > -min_angular_velocity_) && (vx < min_linear_velocity_))
00466 {
00467 wz = -min_angular_velocity_;
00468 }
00469
00470
00471 if (max_linear_velocity_ > 1e-10)
00472 {
00473
00474 if (vx > max_linear_velocity_)
00475 {
00476 vx = max_linear_velocity_;
00477 }
00478 }
00479 if (max_angular_velocity_ > 1e-10)
00480 {
00481
00482 if (wz > max_angular_velocity_)
00483 {
00484 wz = max_angular_velocity_;
00485 }
00486 else if (wz < -max_angular_velocity_)
00487 {
00488 wz = -max_angular_velocity_;
00489 }
00490 }
00491
00492 ROS_DEBUG("Distance to goal: %f, dtheta to goal: %f, vx: %f, wz: %f", distance, dtheta, vx, wz);
00493
00494 twist.linear.x = vx;
00495 twist.angular.z = wz;
00496
00497 return false;
00498 }
00499
00505 geometry_msgs::Point CrossingEscaper::goalFromOdometry(double dx, double dy)
00506 {
00507 geometry_msgs::Point abs_goal;
00508 abs_goal.x = start_position_.pose.pose.position.x + dx;
00509 abs_goal.y = start_position_.pose.pose.position.y + dy;
00510
00511 geometry_msgs::Point rel_goal_abs_frame;
00512 rel_goal_abs_frame.x = abs_goal.x - odometry_.pose.pose.position.x;
00513 rel_goal_abs_frame.y = abs_goal.y - odometry_.pose.pose.position.y;
00514
00515 const double yaw = tf::getYaw(odometry_.pose.pose.orientation);
00516 const double cos_yaw = std::cos(yaw);
00517 const double sin_yaw = std::sin(yaw);
00518 geometry_msgs::Point rel_goal;
00519 rel_goal.x = rel_goal_abs_frame.x * cos_yaw + rel_goal_abs_frame.y * sin_yaw;
00520 rel_goal.y = -rel_goal_abs_frame.x * sin_yaw + rel_goal_abs_frame.y * cos_yaw;
00521
00522 return rel_goal;
00523 }
00524
00525 }