00001 #include "straf_recovery/straf_recovery.h"
00002 #include "obstacle_finder/obstacle_finder.h"
00003
00004 #include <angles/angles.h>
00005 #include <cmath>
00006 #include <math.h>
00007 #include <pluginlib/class_list_macros.h>
00008 #include <std_msgs/Int32.h>
00009 #include <tf/transform_datatypes.h>
00010
00011 namespace straf_recovery
00012 {
00013 StrafRecovery::StrafRecovery() : initialized_(false), cycles_(0)
00014 {
00015 }
00016
00017 void StrafRecovery::initialize(std::string name, tf::TransformListener *tf, costmap_2d::Costmap2DROS *global_costmap,
00018 costmap_2d::Costmap2DROS *local_costmap)
00019 {
00020 if (initialized_)
00021 {
00022 ROS_ERROR("thou shall not call initialize twice on this object. Doing "
00023 "nothing.");
00024 return;
00025 }
00026
00027 initialized_ = true;
00028
00029 name_ = name;
00030 tf_ = tf;
00031 global_costmap_ = global_costmap;
00032 local_costmap_ = local_costmap;
00033 local_costmap_model_ = new base_local_planner::CostmapModel(*local_costmap_->getCostmap());
00034
00035
00036 ros::NodeHandle private_nh("~/" + name_);
00037 ros::NodeHandle nh;
00038 ros::NodeHandle base_local_planner_nh("~/TrajectoryPlannerROS");
00039
00040
00041 dsrv_ = new dynamic_reconfigure::Server<StrafRecoveryConfig>(private_nh);
00042 dynamic_reconfigure::Server<StrafRecoveryConfig>::CallbackType cb =
00043 boost::bind(&StrafRecovery::reconfigureCB, this, _1, _2);
00044 dsrv_->setCallback(cb);
00045
00046 private_nh.param("enabled", enabled_, true);
00047 private_nh.param("go_to_goal_distance_threshold", go_to_goal_distance_threshold_, 0.0);
00048 private_nh.param("minimum_translate_distance", minimum_translate_distance_, 0.5);
00049 private_nh.param("maximum_translate_distance", maximum_translate_distance_, 5.0);
00050 private_nh.param("straf_vel", vel_, 0.1);
00051 private_nh.param("timeout", timeout_, 10);
00052
00053
00054 base_local_planner_nh.param("frequency", frequency_, 20.0);
00055 base_local_planner_nh.param("xy_goal_tolerance", xy_goal_tolerance_, 0.1);
00056
00057
00058 obstacle_pub_ = private_nh.advertise<geometry_msgs::PoseStamped>("obstacle_direction", 10);
00059
00060
00061 cycles_pub_ = private_nh.advertise<std_msgs::Int32>("cycles", 10);
00062
00063 ROS_INFO("minimum_translate_distance %f", minimum_translate_distance_);
00064 ROS_INFO("maximum_translate_distance %f", maximum_translate_distance_);
00065 ROS_INFO("vel %f", vel_);
00066
00067
00068 base_local_planner_nh.param("frequency", frequency_, 20.0);
00069
00070
00071 goal_sub_ = nh.subscribe("move_base_simple/goal", 10, &StrafRecovery::goalCallback, this);
00072 }
00073
00074 void StrafRecovery::runBehavior()
00075 {
00076 if (!initialized_)
00077 {
00078 ROS_ERROR("thou shall not fail to call initialize! Doing nothing.");
00079 return;
00080 }
00081
00082 if (!enabled_)
00083 {
00084 ROS_INFO("skipping %s because it's disabled.", name_.c_str());
00085 return;
00086 }
00087
00088 if (local_costmap_ == NULL || global_costmap_ == NULL)
00089 {
00090 ROS_ERROR("Thou shall not pass costmaps to the straf recovery which are nullptr. "
00091 "Doing nothing");
00092 return;
00093 }
00094
00095 ROS_WARN("Entering straf recovery behavior.");
00096
00097 ros::NodeHandle n;
00098 ros::Rate r(frequency_);
00099 vel_pub_ = n.advertise<geometry_msgs::Twist>("cmd_vel", 10);
00100
00101 tf::Stamped<tf::Pose> initial_local_pose;
00102 local_costmap_->getRobotPose(initial_local_pose);
00103
00104 tf::Stamped<tf::Pose> initial_global_pose;
00105 global_costmap_->getRobotPose(initial_global_pose);
00106
00107 double current_distance_translated = 0.0;
00108
00109
00110 double robot_odom_x = initial_local_pose.getOrigin().x();
00111 double robot_odom_y = initial_local_pose.getOrigin().y();
00112
00113 obstacle_finder::ObstacleFinder finder(local_costmap_, robot_odom_x, robot_odom_y);
00114
00115 ros::Time end = ros::Time::now() + ros::Duration(timeout_);
00116 while (n.ok() && ros::Time::now() < end)
00117 {
00118 tf::Stamped<tf::Pose> global_pose;
00119 global_costmap_->getRobotPose(global_pose);
00120
00121 tf::Stamped<tf::Pose> local_pose;
00122 local_costmap_->getRobotPose(local_pose);
00123
00124 double robot_odom_x = local_pose.getOrigin().x();
00125 double robot_odom_y = local_pose.getOrigin().y();
00126
00127 current_distance_translated = (global_pose.getOrigin() - initial_global_pose.getOrigin()).length();
00128
00129 tf::Stamped<tf::Pose> last_goal_pose;
00130 tf::poseStampedMsgToTF(last_goal_, last_goal_pose);
00131
00132 double distance_to_goal = (last_goal_pose.getOrigin() - local_pose.getOrigin()).length();
00133
00134 ROS_DEBUG("distance_to_goal: %f", distance_to_goal);
00135 if (distance_to_goal < go_to_goal_distance_threshold_) {
00136 ROS_INFO("close enough to goal. strafing there instead");
00137 tf::Pose goal_pose;
00138 tf::poseMsgToTF(last_goal_.pose, goal_pose);
00139 strafInDiretionOfPose(local_pose, goal_pose.getOrigin(), false);
00140
00141 if (distance_to_goal < xy_goal_tolerance_){
00142 return;
00143 }
00144 }
00145 else {
00146
00147
00148
00149 obstacle_finder::Obstacle nearest_obstacle = finder.nearestObstacle(robot_odom_x, robot_odom_y);
00150
00151
00152 if (current_distance_translated > maximum_translate_distance_)
00153 {
00154 ROS_WARN("Straf Recovery has met maximum translate distance");
00155 return;
00156 }
00157
00158
00159 if (current_distance_translated > minimum_translate_distance_)
00160 {
00161 return;
00162 }
00163
00164 tf::Vector3 obstacle_pose(nearest_obstacle.x, nearest_obstacle.y, local_pose.getOrigin().z());
00165 strafInDiretionOfPose(local_pose, obstacle_pose);
00166 }
00167 r.sleep();
00168 }
00169
00170 cycles_++;
00171 std_msgs::Int32 msg;
00172 msg.data = cycles_;
00173 cycles_pub_.publish(msg);
00174 }
00175
00176 void StrafRecovery::strafInDiretionOfPose(tf::Stamped<tf::Pose> current_pose, tf::Vector3 direction_pose, bool away){
00177 tf::Vector3 diff = current_pose.getOrigin() - direction_pose;
00178 double yaw_in_odom_frame = atan2(diff.y(), diff.x());
00179
00180 tf::Quaternion straf_direction = tf::createQuaternionFromYaw(yaw_in_odom_frame);
00181
00182 geometry_msgs::PoseStamped obstacle_msg;
00183
00184 obstacle_msg.header.frame_id = current_pose.frame_id_;
00185 obstacle_msg.header.stamp = ros::Time::now();
00186 obstacle_msg.pose.position.x = direction_pose.getX();
00187 obstacle_msg.pose.position.y = direction_pose.getY();
00188 obstacle_msg.pose.orientation.x = straf_direction.x();
00189 obstacle_msg.pose.orientation.y = straf_direction.y();
00190 obstacle_msg.pose.orientation.z = straf_direction.z();
00191 obstacle_msg.pose.orientation.w = straf_direction.w();
00192
00193 obstacle_pub_.publish(obstacle_msg);
00194
00195 geometry_msgs::PoseStamped straf_msg;
00196 tf_->waitForTransform("/base_link", current_pose.frame_id_, ros::Time::now(), ros::Duration(3.0));
00197 tf_->transformPose("/base_link", obstacle_msg, straf_msg);
00198
00199
00200 double straf_angle = tf::getYaw(straf_msg.pose.orientation);
00201
00202 geometry_msgs::Twist cmd_vel;
00203 cmd_vel.linear.x = vel_ * cos(straf_angle);
00204 cmd_vel.linear.y = vel_ * sin(straf_angle);
00205 cmd_vel.linear.z = 0.0;
00206
00207 vel_pub_.publish(cmd_vel);
00208
00209 }
00210
00211 void StrafRecovery::goalCallback(const geometry_msgs::PoseStamped& msg)
00212 {
00213 ROS_INFO_ONCE("Received goal");
00214 last_goal_ = msg;
00215 }
00216
00217 void StrafRecovery::reconfigureCB(StrafRecoveryConfig& config, uint32_t level)
00218 {
00219 enabled_ = config.enabled;
00220 timeout_ = config.timeout;
00221 minimum_translate_distance_ = config.minimum_translate_distance;
00222 maximum_translate_distance_ = config.maximum_translate_distance;
00223 xy_goal_tolerance_ = config.xy_goal_tolerance;
00224 go_to_goal_distance_threshold_ = config.go_to_goal_distance_threshold;
00225 vel_ = config.straf_vel;
00226 frequency_ = config.frequency;
00227 }
00228
00229 }
00230
00231 PLUGINLIB_EXPORT_CLASS(straf_recovery::StrafRecovery, nav_core::RecoveryBehavior)