stepback_and_steerturn_recovery.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008, Willow Garage, Inc.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Neither the name of the Willow Garage, Inc. nor the names of its
00014  *       contributors may be used to endorse or promote products derived from
00015  *       this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  *
00029  */
00030 
00035 #include <stepback_and_steerturn_recovery/stepback_and_steerturn_recovery.h>
00036 #include <pluginlib/class_list_macros.h>
00037 #include <tf/transform_datatypes.h>
00038 
00039 // register as a RecoveryBehavior plugin
00040 PLUGINLIB_DECLARE_CLASS(stepback_and_steerturn_recovery, StepBackAndSteerTurnRecovery, stepback_and_steerturn_recovery::StepBackAndSteerTurnRecovery,      
00041                         nav_core::RecoveryBehavior)
00042 
00043 namespace stepback_and_steerturn_recovery
00044 {
00045 
00046 StepBackAndSteerTurnRecovery::StepBackAndSteerTurnRecovery () :
00047   global_costmap_(NULL), local_costmap_(NULL), tf_(NULL), initialized_(false)
00048 {
00049     TWIST_STOP.linear.x = 0.0;
00050     TWIST_STOP.linear.y = 0.0;
00051     TWIST_STOP.linear.z = 0.0;
00052     TWIST_STOP.angular.x = 0.0;
00053     TWIST_STOP.angular.y = 0.0;
00054     TWIST_STOP.angular.z = 0.0;
00055 }
00056 
00057 StepBackAndSteerTurnRecovery::~StepBackAndSteerTurnRecovery ()
00058 {
00059   delete world_model_;
00060 }
00061 
00062 void StepBackAndSteerTurnRecovery::initialize (std::string name, tf::TransformListener* tf,
00063                                 cmap::Costmap2DROS* global_cmap, cmap::Costmap2DROS* local_cmap)
00064 {
00065   ROS_ASSERT(!initialized_);
00066   name_ = name;
00067   tf_ = tf;
00068   local_costmap_ = local_cmap;
00069   global_costmap_ = global_cmap;
00070   /*
00071   local_costmap_->getCostmapCopy(costmap_);
00072   world_model_ = new blp::CostmapModel(costmap_);
00073   */
00074   world_model_ = new base_local_planner::CostmapModel(*local_costmap_->getCostmap());
00075 
00076   cmd_vel_pub_ = nh_.advertise<gm::Twist>("cmd_vel", 10);
00077   recover_run_pub_ = nh_.advertise<std_msgs::Bool>("recover_run", 10);
00078   ros::NodeHandle private_nh("~/" + name);
00079 
00080   /*
00081   {
00082       bool found=true;
00083       found = found && private_nh.getParam("linear_x", base_frame_twist_.linear.x);
00084       found = found && private_nh.getParam("linear_y", base_frame_twist_.linear.y);
00085       found = found && private_nh.getParam("angular_z", base_frame_twist_.angular.z);
00086       if (!found) {
00087           ROS_FATAL_STREAM ("Didn't find twist parameters in " << private_nh.getNamespace());
00088           ros::shutdown();
00089       }
00090   }
00091   */
00092 
00093   private_nh.param("duration", duration_, 1.0);
00094   private_nh.param("linear_speed_limit", linear_speed_limit_, 0.3);
00095   private_nh.param("angular_speed_limit", angular_speed_limit_, 1.0);
00096   private_nh.param("linear_acceleration_limit", linear_acceleration_limit_, 4.0);
00097   private_nh.param("angular_acceleration_limit", angular_acceleration_limit_, 3.2);
00098   private_nh.param("controller_frequency", controller_frequency_, 20.0);
00099   private_nh.param("simulation_frequency", simulation_frequency_, 5.0);
00100   private_nh.param("simulation_inc", simulation_inc_, 1/simulation_frequency_);
00101 
00102   private_nh.param("only_single_steering", only_single_steering_, true);
00103   private_nh.param("trial_times", trial_times_, 5);
00104   private_nh.param("obstacle_patience", obstacle_patience_, 0.5);
00105   private_nh.param("obstacle_check_frequency", obstacle_check_frequency_, 5.0);
00106   private_nh.param("sim_angle_resolution", sim_angle_resolution_, 0.1);
00107 
00108   // back
00109   private_nh.param("linear_vel_back", linear_vel_back_, -0.3);
00110   private_nh.param("step_back_length", step_back_length_, 1.0);
00111   private_nh.param("step_back_timeout", step_back_timeout_, 15.0);
00112   //-- steer
00113   private_nh.param("linear_vel_steer", linear_vel_steer_, 0.3);
00114   private_nh.param("angular_speed_steer", angular_speed_steer_, 0.5);
00115   private_nh.param("turn_angle", turn_angle_, 2.0);
00116   private_nh.param("steering_timeout", steering_timeout_, 15.0);
00117   //-- forward
00118   private_nh.param("linear_vel_forward", linear_vel_forward_, 0.3);
00119   private_nh.param("step_forward_length", step_forward_length_, 0.5);
00120   private_nh.param("step_forward_timeout", step_forward_timeout_, 15.0);
00121 
00122   /*
00123   ROS_INFO_STREAM_NAMED ("top", "Initialized twist recovery with twist " <<
00124                           base_frame_twist_ << " and duration " << duration_);
00125   */
00126 
00127   ROS_INFO_NAMED ("top", "Initialized with only_single_steering = %s", (only_single_steering_ ? "true" : "false"));
00128   ROS_INFO_NAMED ("top", "Initialized with recovery_trial_times = %d", trial_times_);
00129   ROS_INFO_NAMED ("top", "Initialized with obstacle_patience = %.2f", obstacle_patience_);
00130   ROS_INFO_NAMED ("top", "Initialized with obstacle_check_frequency = %.2f", obstacle_check_frequency_);
00131   ROS_INFO_NAMED ("top", "Initialized with simulation_frequency = %.2f", simulation_frequency_);
00132   ROS_INFO_NAMED ("top", "Initialized with sim_angle_resolution = %.2f", sim_angle_resolution_);
00133   ROS_INFO_NAMED ("top", "Initialized with linear_vel_back = %.2f, step_back_length = %.2f, step_back_steering = %.2f",
00134                   linear_vel_back_, step_back_length_, step_back_timeout_);
00135   ROS_INFO_NAMED ("top", "Initialized with linear_vel_steer = %.2f, angular_speed_steer = %.2f,"
00136                          " turn_angle = %.2f, steering_timeout = %.2f",
00137                   linear_vel_steer_, angular_speed_steer_, turn_angle_, steering_timeout_);
00138   ROS_INFO_NAMED ("top", "Initialized with linear_vel_forward = %.2f, step_forward_length = %.2f, step_forward_timeout = %.2f",
00139                   linear_vel_forward_, step_forward_length_, step_forward_timeout_);
00140 
00141   initialized_ = true;
00142 }
00143 
00144 gm::Twist scaleTwist (const gm::Twist& twist, const double scale)
00145 {
00146   gm::Twist t;
00147   t.linear.x = twist.linear.x * scale;
00148   t.linear.y = twist.linear.y * scale;
00149   t.angular.z = twist.angular.z * scale;
00150   return t;
00151 }
00152 
00153 gm::Pose2D forwardSimulate (const gm::Pose2D& p, const gm::Twist& twist, const double t=1.0)
00154 {
00155   gm::Pose2D p2;
00156   const double linear_vel = twist.linear.x;
00157   p2.theta = p.theta + twist.angular.z;//*t;
00158   p2.x = p.x + linear_vel * cos(p2.theta)*t;
00159   p2.y = p.y + linear_vel * sin(p2.theta)*t;
00160 
00161   return p2;
00162 }
00163 
00165 double StepBackAndSteerTurnRecovery::normalizedPoseCost (const gm::Pose2D& pose) const
00166 {
00167   gm::Point p;
00168   p.x = pose.x;
00169   p.y = pose.y;
00170 
00171   unsigned int pose_map_idx_x, pose_map_idx_y;
00172   costmap_2d::Costmap2D* costmap = local_costmap_->getCostmap();
00173   costmap->worldToMap(p.x, p.y, pose_map_idx_x, pose_map_idx_y);  // convert point unit from [m] to [idx]
00174   ROS_DEBUG_NAMED ("top", "Trying to get cost at (%d, %d) in getCost", pose_map_idx_x, pose_map_idx_y);
00175   const double c = costmap->getCost(pose_map_idx_x, pose_map_idx_y);
00176 
00177   return c < 0 ? 1e9 : c;
00178 }
00179 
00180 
00185 gm::Pose2D StepBackAndSteerTurnRecovery::getPoseToObstacle (const gm::Pose2D& current, const gm::Twist& twist) const
00186 {
00187   double cost = 0;
00188   cost = normalizedPoseCost(current);
00189   double t; // Will hold the first time that is invalid
00190   gm::Pose2D current_tmp = current;
00191   double next_cost;
00192 
00193   ROS_DEBUG_NAMED ("top", " ");
00194   for (t=simulation_inc_; t<=duration_ + 500; t+=simulation_inc_) {
00195       ROS_DEBUG_NAMED ("top", "start loop");
00196       current_tmp = forwardSimulate(current, twist, t);
00197       ROS_DEBUG_NAMED ("top", "finish fowardSimulate");
00198       next_cost = normalizedPoseCost(current_tmp);
00199       ROS_DEBUG_NAMED ("top", "finish Cost");
00200     //if (next_cost > cost) {
00201     if (/*next_cost == costmap_2d::INSCRIBED_INFLATED_OBSTACLE ||*/ next_cost == costmap_2d::LETHAL_OBSTACLE) {
00202       ROS_DEBUG_STREAM_NAMED ("cost", "Cost at " << t << " and pose " << forwardSimulate(current, twist, t)
00203                               << " is " << next_cost << " which is greater than previous cost " << cost);
00204       break;
00205     }
00206     cost = next_cost;
00207   }
00208   ROS_DEBUG_NAMED ("top", "cost = %.2f, next_cost = %.2f", cost, next_cost);
00209   ROS_DEBUG_NAMED ("top", "twist.linear.x = %.2f, twist.angular.z = %.2f", twist.linear.x, twist.angular.z);
00210   ROS_DEBUG_NAMED ("top", "init = (%.2f, %.2f, %.2f), current = (%.2f, %.2f, %.2f)",
00211                   current.x, current.y, current.theta, current_tmp.x, current_tmp.y, current_tmp.theta);
00212   ROS_DEBUG_NAMED ("top", "time = %.2f", t);
00213 
00214   // return t-simulation_inc_;
00215   return current_tmp;
00216 }
00217 
00218 double linearSpeed (const gm::Twist& twist)
00219 {
00220   return sqrt(twist.linear.x*twist.linear.x + twist.linear.y*twist.linear.y);
00221 }
00222 
00223 double angularSpeed (const gm::Twist& twist)
00224 {
00225   return fabs(twist.angular.z);
00226 }
00227 
00228 // Scale twist so we can stop in the given time, and so it's within the max velocity
00229 gm::Twist StepBackAndSteerTurnRecovery::scaleGivenAccelerationLimits (const gm::Twist& twist, const double time_remaining) const
00230 {
00231   const double linear_speed = linearSpeed(twist);
00232   const double angular_speed = angularSpeed(twist);
00233   const double linear_acc_scaling = linear_speed/(time_remaining*linear_acceleration_limit_);
00234   const double angular_acc_scaling = angular_speed/(time_remaining*angular_acceleration_limit_);
00235   const double acc_scaling = max(linear_acc_scaling, angular_acc_scaling);
00236   const double linear_vel_scaling = linear_speed/linear_speed_limit_;
00237   const double angular_vel_scaling = angular_speed/angular_speed_limit_;
00238   const double vel_scaling = max(linear_vel_scaling, angular_vel_scaling);
00239   return scaleTwist(twist, max(1.0, max(acc_scaling, vel_scaling)));
00240 }
00241 
00242 // Get pose in local costmap framoe
00243 gm::Pose2D StepBackAndSteerTurnRecovery::getCurrentLocalPose () const
00244 {
00245   tf::Stamped<tf::Pose> p;
00246   local_costmap_->getRobotPose(p);
00247   gm::Pose2D pose;
00248   pose.x = p.getOrigin().x();
00249   pose.y = p.getOrigin().y();
00250   pose.theta = tf::getYaw(p.getRotation());
00251   return pose;
00252 }
00253 
00254 void StepBackAndSteerTurnRecovery::moveSpacifiedLength (const gm::Twist twist, const double distination, const COSTMAP_SEARCH_MODE mode) const
00255 {
00256     double distination_cmd = distination;
00257     double min_dist_to_obstacle = getMinimalDistanceToObstacle(mode);
00258 
00259     std::string mode_name;
00260     double time_out;
00261 
00262     switch (mode) {
00263     case FORWARD:
00264         mode_name = "FORWARD";
00265         time_out = step_forward_timeout_;
00266         if (min_dist_to_obstacle < distination)
00267         {
00268           distination_cmd = min_dist_to_obstacle - obstacle_patience_;
00269 
00270           ROS_WARN_NAMED ("top", "obstacle detected before moving %s", mode_name.c_str());
00271           ROS_WARN_NAMED ("top", "min dist to obstacle = %.2f [m] in %s", min_dist_to_obstacle, mode_name.c_str());
00272           ROS_WARN_NAMED ("top", "moving length is switched from %.2f [m] to %.2f in %s", distination, distination_cmd,mode_name.c_str());
00273         }
00274         break;
00275     case FORWARD_LEFT:
00276         mode_name = "FORWARD_LEFT";
00277         time_out = steering_timeout_;
00278         if (min_dist_to_obstacle < obstacle_patience_)
00279         {
00280           distination_cmd = 0.0;
00281 
00282           ROS_WARN_NAMED ("top", "obstacle detected before moving %s", mode_name.c_str());
00283           ROS_WARN_NAMED ("top", "min dist to obstacle = %.2f [m] in %s", min_dist_to_obstacle, mode_name.c_str());
00284           ROS_WARN_NAMED ("top", "stop turning because an obstacle is too close in %s", mode_name.c_str());
00285         }
00286         break;
00287     case FORWARD_RIGHT:
00288         mode_name = "FORWARD_RIGHT";
00289         time_out = steering_timeout_;
00290         if (min_dist_to_obstacle < obstacle_patience_)
00291         {
00292           distination_cmd = 0.0;
00293 
00294           ROS_WARN_NAMED ("top", "obstacle detected before moving %s", mode_name.c_str());
00295           ROS_WARN_NAMED ("top", "min dist to obstacle = %.2f [m] in %s", min_dist_to_obstacle, mode_name.c_str());
00296           ROS_WARN_NAMED ("top", "stop turning because an obstacle is too close in %s", mode_name.c_str());
00297         }
00298         break;
00299     case BACKWARD:
00300         mode_name = "BACKWARD";
00301         time_out = step_back_timeout_;
00302         if (min_dist_to_obstacle < distination)
00303         {
00304           distination_cmd = min_dist_to_obstacle - 2 * obstacle_patience_;
00305 
00306           ROS_WARN_NAMED ("top", "obstacle detected before moving %s", mode_name.c_str());
00307           ROS_WARN_NAMED ("top", "min dist to obstacle = %.2f [m] in %s", min_dist_to_obstacle, mode_name.c_str());
00308           ROS_WARN_NAMED ("top", "moving length is switched from %.2f [m] to %.2f in %s", distination, distination_cmd, mode_name.c_str());
00309         }
00310         break;
00311     default:
00312         break;
00313     }
00314 
00315     const double frequency = 5.0;
00316     ros::Rate r(frequency);
00317 
00318     const gm::Pose2D initialPose = getCurrentLocalPose();
00319 
00320     int log_cnt = 0;
00321     int log_frequency = (int)obstacle_check_frequency_;
00322 
00323     ros::Time time_begin = ros::Time::now();
00324     while (double dist_diff = getCurrentDistDiff(initialPose, distination_cmd, mode) > 0.01)
00325     {
00326         double remaining_time = dist_diff / base_frame_twist_.linear.x;
00327         double min_dist = getMinimalDistanceToObstacle(mode);
00328 
00329         // time out
00330         if(time_out > 0.0 &&
00331                 time_begin + ros::Duration(time_out) < ros::Time::now())
00332         {
00333             //cmd_vel_pub_.publish(scaleGivenAccelerationLimits(TWIST_STOP, remaining_time));
00334             cmd_vel_pub_.publish(TWIST_STOP);
00335             ROS_WARN_NAMED ("top", "time out at %s", mode_name.c_str());
00336             ROS_WARN_NAMED ("top", "%.2f [sec] elapsed.", time_out);
00337             break;
00338         }
00339 
00340         // detect an obstacle
00341         if(min_dist < obstacle_patience_)
00342         {
00343             //cmd_vel_pub_.publish(scaleGivenAccelerationLimits(TWIST_STOP, remaining_time));
00344             cmd_vel_pub_.publish(TWIST_STOP);
00345             ROS_WARN_NAMED ("top", "obstacle detected at %s", mode_name.c_str());
00346             ROS_WARN_NAMED ("top", "min dist to obstacle = %.2f [m] in %s", min_dist, mode_name.c_str());
00347             break;
00348         }
00349 
00350         //cmd_vel_pub_.publish(scaleGivenAccelerationLimits(twist, remaining_time));
00351         cmd_vel_pub_.publish(twist);
00352         if(log_cnt++ % log_frequency == 0)
00353         {
00354             ROS_DEBUG_NAMED ("top", "no obstacle around");
00355             ROS_INFO_NAMED ("top", "min dist to obstacle = %.2f [m] in %s", min_dist, mode_name.c_str());
00356         }
00357 
00358         ros::spinOnce();
00359         r.sleep();
00360     }
00361 
00362     return;
00363 }
00364 
00365 double StepBackAndSteerTurnRecovery::getCurrentDiff(const gm::Pose2D initialPose, const COSTMAP_SEARCH_MODE mode) const
00366 {
00367 
00368     const gm::Pose2D& currentPose = getCurrentLocalPose();
00369     ROS_DEBUG_NAMED ("top", "current pose (%.2f, %.2f, %.2f)", currentPose.x,
00370                        currentPose.y, currentPose.theta);
00371 
00372     double current_diff;
00373 
00374     switch (mode) {
00375     case FORWARD:
00376     case BACKWARD:
00377         current_diff = getDistBetweenTwoPoints(currentPose, initialPose);
00378         ROS_DEBUG_NAMED ("top", "current_diff in translation = %.2f", current_diff);
00379         break;
00380     case FORWARD_LEFT:
00381     case FORWARD_RIGHT:
00382         current_diff = initialPose.theta - currentPose.theta;
00383         current_diff = fabs(current_diff);
00384         ROS_DEBUG_NAMED ("top", "initialPose.Theta = %.2f, currentPose.theta = %.2f", initialPose.theta, currentPose.theta);
00385         ROS_DEBUG_NAMED ("top", "current_diff in angle = %.2f", current_diff);
00386     default:
00387         break;
00388     }
00389 
00390     return current_diff;
00391 }
00392 
00393 double StepBackAndSteerTurnRecovery::getCurrentDistDiff(const gm::Pose2D initialPose, const double distination, COSTMAP_SEARCH_MODE mode) const
00394 {
00395     const double dist_diff = distination - getCurrentDiff(initialPose, mode);
00396     ROS_DEBUG_NAMED ("top", "dist_diff = %.2f", dist_diff);
00397 
00398     return dist_diff;
00399 }
00400 
00401 double StepBackAndSteerTurnRecovery::getMinimalDistanceToObstacle(const COSTMAP_SEARCH_MODE mode) const
00402 {
00403     double max_angle, min_angle;
00404     gm::Twist twist = TWIST_STOP;
00405 
00406     switch (mode) {
00407     case FORWARD:
00408         twist.linear.x = linear_vel_forward_;
00409         max_angle = M_PI/3.0;
00410         min_angle = -M_PI/3.0;
00411         break;
00412     case FORWARD_LEFT:
00413         twist.linear.x = linear_vel_forward_;
00414         max_angle = M_PI/2.0;
00415         min_angle = 0.0;
00416         break;
00417     case FORWARD_RIGHT:
00418         twist.linear.x = linear_vel_forward_;
00419         max_angle = 0.0;
00420         min_angle = -M_PI/2.0;
00421         break;
00422     case BACKWARD:
00423         twist.linear.x = linear_vel_back_;
00424         max_angle = M_PI/3.0;
00425         min_angle = -M_PI/3.0;
00426         break;
00427     default:
00428         break;
00429     }
00430 
00431     const gm::Pose2D& current = getCurrentLocalPose();
00432     double min_dist = INFINITY;
00433 
00434     for(double angle = min_angle; angle < max_angle; angle+=sim_angle_resolution_)
00435       {
00436           twist.angular.z = angle;
00437           gm::Pose2D pose_to_obstacle = getPoseToObstacle(current, twist);
00438           double dist_to_obstacle = getDistBetweenTwoPoints(current, pose_to_obstacle);
00439 
00440           if(dist_to_obstacle < min_dist)
00441               min_dist = dist_to_obstacle;
00442     }
00443 
00444     ROS_DEBUG_NAMED ("top", "min_dist = %.2f", min_dist);
00445 
00446     return min_dist;
00447 }
00448 
00449 int StepBackAndSteerTurnRecovery::determineTurnDirection()
00450 {
00451     // simulate and evaluate cost
00452     const gm::Pose2D& current = getCurrentLocalPose();
00453 
00454     gm::Twist twist = TWIST_STOP;
00455     twist.linear.x = linear_vel_forward_;
00456 
00457     vector<double> dist_to_obstacle_r;
00458     vector<double> dist_to_obstacle_l;
00459     double max = M_PI/2.0;
00460     double min = - max;
00461     for(double angle = min; angle < max; angle+=sim_angle_resolution_)
00462     {
00463         twist.angular.z = angle;
00464         gm::Pose2D pose_to_obstacle = getPoseToObstacle(current, twist);
00465         double dist_to_obstacle = getDistBetweenTwoPoints(current, pose_to_obstacle);
00466 
00467         ROS_DEBUG_NAMED ("top", "(%.2f, %.2f, %.2f) for %.2f [m] to obstacle",
00468                          twist.linear.x, twist.linear.y, twist.angular.z, dist_to_obstacle);
00469 
00470         if(angle > 0.0)
00471             dist_to_obstacle_l.push_back(dist_to_obstacle);
00472         else if(angle < 0.0)
00473             dist_to_obstacle_r.push_back(dist_to_obstacle);
00474         else
00475             ;// do nothing
00476     }
00477 
00478     // determine the directoin to go from cost
00479     /*
00480     double sum_l = 0.0;
00481     double sum_r = 0.0;
00482     double ave_l = 0.0;
00483     double ave_r = 0.0;
00484     for(int i = 0; i < dist_to_obstacle_l.size(); i++)
00485         sum_l += dist_to_obstacle_l[i];
00486     for(int i = 0; i < dist_to_obstacle_r.size(); i++)
00487         sum_r += dist_to_obstacle_r[i];
00488     ave_l = sum_l / dist_to_obstacle_l.size();
00489     ave_r = sum_r / dist_to_obstacle_r.size();
00490     ROS_DEBUG_NAMED ("top", "sum_l = %.2f, sum_r = %.2f", sum_l, sum_r);
00491     ROS_DEBUG_NAMED ("top", "size_l = %d, size_r = %d", (int)dist_to_obstacle_l.size(), (int)dist_to_obstacle_r.size());
00492     ROS_DEBUG_NAMED ("top", "ave_l = %.2f, ave_r = %.2f", ave_l, ave_r);
00493     */
00494 
00495     double min_l = *min_element(dist_to_obstacle_l.begin(), dist_to_obstacle_l.end());
00496     double min_r = *min_element(dist_to_obstacle_r.begin(), dist_to_obstacle_r.end());
00497     ROS_INFO_NAMED ("top", "min_l = %.2f [m], min_r = %.2f [m]", min_l, min_r);
00498 
00499     int ret_val;
00500 
00501     if(min_l < min_r)
00502         ret_val = RIGHT; // if obstacle settles on left, turn right
00503     else
00504         ret_val = LEFT; // vice versa
00505 
00506     return ret_val;
00507 }
00508 
00509 double StepBackAndSteerTurnRecovery::getDistBetweenTwoPoints(const gm::Pose2D pose1, const gm::Pose2D pose2) const
00510 {
00511     double dist_to_obstacle = (pose1.x - pose2.x) * (pose1.x - pose2.x) +
00512             (pose1.y - pose2.y) * (pose1.y - pose2.y);
00513     return sqrt(dist_to_obstacle);
00514 }
00515 
00516 void StepBackAndSteerTurnRecovery::runBehavior ()
00517 {
00518   ROS_ASSERT (initialized_);
00519 
00520   ROS_INFO_NAMED ("top", "*****************************************************");
00521   ROS_INFO_NAMED ("top", "********Start StepBackAndSteerTurnRecovery!!!********");
00522   ROS_INFO_NAMED ("top", "*****************************************************");
00523 
00524   std_msgs::Bool run_state;
00525 
00526   // when starting recovery, topic /run_state_ shifts to true
00527   run_state.data = true;
00528   recover_run_pub_.publish(run_state);
00529 
00530   int cnt = 0;
00531   const double stop_duaration = 1.0;
00532   while(true)
00533   {
00534       cnt++;
00535       ROS_INFO_NAMED ("top", "==== %d th recovery trial ====", cnt);
00536 
00537       // Figure out how long we can safely run the behavior
00538       const gm::Pose2D& initialPose = getCurrentLocalPose();
00539 
00540       // initial pose
00541       ROS_DEBUG_NAMED ("top", "initial pose (%.2f, %.2f, %.2f)", initialPose.x,
00542                        initialPose.y, initialPose.theta);
00543       ros::Rate r(controller_frequency_);
00544 
00545       // step back
00546       base_frame_twist_.linear.x = linear_vel_back_;
00547       ROS_INFO_NAMED ("top", "attempting step back");
00548       moveSpacifiedLength(base_frame_twist_, step_back_length_, BACKWARD);
00549       ROS_INFO_NAMED ("top", "complete step back");
00550 
00551       double final_diff = getCurrentDiff(initialPose);
00552       ROS_DEBUG_NAMED ("top", "final_diff = %.2f",final_diff);
00553 
00554       // stop
00555       for (double t=0; t<stop_duaration; t+=1/controller_frequency_) {
00556           cmd_vel_pub_.publish(TWIST_STOP);
00557           r.sleep();
00558       }
00559 
00560       int turn_dir = determineTurnDirection();
00561       int costmap_search_mode[CNT_TURN];
00562 
00563       double z;
00564       if(turn_dir == LEFT)
00565       {
00566           z = angular_speed_steer_;
00567           costmap_search_mode[FIRST_TURN] = FORWARD_LEFT;
00568           costmap_search_mode[SECOND_TURN] = FORWARD_RIGHT;
00569           ROS_INFO_NAMED ("top", "attempting to turn left at the 1st turn");
00570       }
00571       else
00572       {
00573           z = -1 * angular_speed_steer_;
00574           costmap_search_mode[FIRST_TURN] = FORWARD_RIGHT;
00575           costmap_search_mode[SECOND_TURN] = FORWARD_LEFT;
00576           ROS_INFO_NAMED ("top", "attemping to turn right at the 1st turn");
00577       }
00578 
00579       // clear way
00580       //-- first steering
00581       gm::Twist twist;
00582       twist = TWIST_STOP;
00583       twist.linear.x = linear_vel_steer_;
00584       twist.angular.z = z;
00585       moveSpacifiedLength(twist, turn_angle_, (COSTMAP_SEARCH_MODE)costmap_search_mode[FIRST_TURN]);
00586       ROS_INFO_NAMED ("top", "complete the 1st turn");
00587 
00588       if(!only_single_steering_) {
00589           //-- go straight
00590           ROS_INFO_NAMED ("top", "attemping step forward");
00591           twist = TWIST_STOP;
00592           twist.linear.x = linear_vel_forward_;
00593           moveSpacifiedLength(twist, step_forward_length_, FORWARD);
00594           ROS_INFO_NAMED ("top", "complete step forward");
00595 
00596           //-- second steering
00597           ROS_INFO_NAMED ("top", "attempting second turn");
00598           twist = TWIST_STOP;
00599           twist.linear.x = linear_vel_steer_;
00600           twist.angular.z = -z;
00601           moveSpacifiedLength(twist, turn_angle_, (COSTMAP_SEARCH_MODE)costmap_search_mode[SECOND_TURN]);
00602           ROS_INFO_NAMED ("top", "complete second turn");
00603       }
00604 
00605       // stop
00606       for (double t=0; t<stop_duaration; t+=1/controller_frequency_) {
00607           cmd_vel_pub_.publish(TWIST_STOP);
00608           r.sleep();
00609       }
00610 
00611       // check trial times
00612       if(cnt == trial_times_)
00613       {
00614           ROS_INFO_NAMED ("top", "break after %d times recovery", cnt);
00615           break;
00616       }
00617 
00618       // check clearance forward
00619       const  gm::Pose2D& current = getCurrentLocalPose();
00620       double max_angle = 0.1;
00621       double min_angle = -max_angle;
00622       double max_clearance = 0;
00623       twist.linear.x = 3.0;
00624       for(double angle = min_angle; angle < max_angle; angle+=sim_angle_resolution_)
00625       {
00626           twist.angular.z = angle;
00627           gm::Pose2D pose_to_obstacle = getPoseToObstacle(current, twist);
00628           double dist_to_obstacle = getDistBetweenTwoPoints(current, pose_to_obstacle);
00629 
00630           if(dist_to_obstacle > max_clearance)
00631               max_clearance = dist_to_obstacle;
00632       }
00633 
00634       if(max_clearance < 3.0)
00635       {
00636           ROS_INFO_NAMED ("top", "continue recovery because the robot couldn't get clearance");
00637           ROS_DEBUG_NAMED ("top", "continue at (%.2f, %.2f, %.2f) for max_clearance %.2f m",
00638                           twist.linear.x, twist.linear.y, twist.angular.z, max_clearance);
00639           continue;
00640       }
00641       else
00642       {
00643           ROS_INFO_NAMED ("top", "break recovery because the robot got clearance");
00644           ROS_DEBUG_NAMED ("top", "break at (%.2f, %.2f, %.2f) for max_clearance %.2f m",
00645                           twist.linear.x, twist.linear.y, twist.angular.z, max_clearance);
00646           break;
00647       }
00648   }
00649 
00650   // when finishing recovery, topic /run_state_ shifts to false
00651   run_state.data = false;
00652   recover_run_pub_.publish(run_state);
00653 
00654   ROS_INFO_NAMED ("top", "*****************************************************");
00655   ROS_INFO_NAMED ("top", "********Finish StepBackAndSteerTurnRecovery!!********");
00656   ROS_INFO_NAMED ("top", "*****************************************************");
00657 
00658 }
00659 
00660 
00661 } // namespace stepback_and_steerturn_recovery


stepback_and_steerturn_recovery
Author(s): CIR-KIT , Masaru Morita
autogenerated on Sat Jun 8 2019 19:20:28