straf_recovery.cpp
Go to the documentation of this file.
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   // get some parameters from the parameter server
00036   ros::NodeHandle private_nh("~/" + name_);
00037   ros::NodeHandle nh;
00038   ros::NodeHandle base_local_planner_nh("~/TrajectoryPlannerROS");
00039 
00040   // setup dynamic reconfigure
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   // use the same control frequency and xy goal tolerance as the base local planner
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   // for visualizing
00058   obstacle_pub_ = private_nh.advertise<geometry_msgs::PoseStamped>("obstacle_direction", 10);
00059 
00060   // for failure detection
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   // use the same control frequency as the base local planner
00068   base_local_planner_nh.param("frequency", frequency_, 20.0);
00069 
00070   // knowing current goal means we can cheat and straf to the goal
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   // find the nearest obstacle
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); //straf towards not away
00140 
00141       if (distance_to_goal < xy_goal_tolerance_){
00142         return;
00143       }
00144     }
00145     else {
00146 
00147       // The obstacle finder has a pointer to the local costmap, so that will keep working.
00148       // We just need to use the opdated x and y
00149       obstacle_finder::Obstacle nearest_obstacle = finder.nearestObstacle(robot_odom_x, robot_odom_y);
00150 
00151       // check if we've reached max distance
00152       if (current_distance_translated > maximum_translate_distance_)
00153       {
00154         ROS_WARN("Straf Recovery has met maximum translate distance");
00155         return;
00156       }
00157 
00158       // check if we've reade the minimum distance
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   // angle in the base_link frame
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)


straf_recovery
Author(s):
autogenerated on Sat Jun 8 2019 20:37:23