Go to the documentation of this file.00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 #include <nav_2d_utils/parameters.h>
00036 #include <dwb_critics/oscillation.h>
00037 #include <nav_core2/exceptions.h>
00038 #include <pluginlib/class_list_macros.h>
00039 #include <cmath>
00040 #include <string>
00041 #include <vector>
00042 
00043 PLUGINLIB_EXPORT_CLASS(dwb_critics::OscillationCritic, dwb_local_planner::TrajectoryCritic)
00044 
00045 namespace dwb_critics
00046 {
00047 
00048 OscillationCritic::CommandTrend::CommandTrend()
00049 {
00050   reset();
00051 }
00052 
00053 void OscillationCritic::CommandTrend::reset()
00054 {
00055   sign_ = Sign::ZERO;
00056   positive_only_ = false;
00057   negative_only_ = false;
00058 }
00059 
00060 bool OscillationCritic::CommandTrend::update(double velocity)
00061 {
00062   bool flag_set = false;
00063   if (velocity < 0.0)
00064   {
00065     if (sign_ == Sign::POSITIVE)
00066     {
00067       negative_only_ = true;
00068       flag_set = true;
00069     }
00070     sign_ = Sign::NEGATIVE;
00071   }
00072   else if (velocity > 0.0)
00073   {
00074     if (sign_ == Sign::NEGATIVE)
00075     {
00076       positive_only_ = true;
00077       flag_set = true;
00078     }
00079     sign_ = Sign::POSITIVE;
00080   }
00081   return flag_set;
00082 }
00083 
00084 bool OscillationCritic::CommandTrend::isOscillating(double velocity)
00085 {
00086   return (positive_only_ && velocity < 0.0) || (negative_only_ && velocity > 0.0);
00087 }
00088 
00089 bool OscillationCritic::CommandTrend::hasSignFlipped()
00090 {
00091   return positive_only_ || negative_only_;
00092 }
00093 
00094 void OscillationCritic::onInit()
00095 {
00096   oscillation_reset_dist_ = nav_2d_utils::searchAndGetParam(critic_nh_, "oscillation_reset_dist", 0.05);
00097   oscillation_reset_dist_sq_ = oscillation_reset_dist_ * oscillation_reset_dist_;
00098   oscillation_reset_angle_ = nav_2d_utils::searchAndGetParam(critic_nh_, "oscillation_reset_angle", 0.2);
00099   oscillation_reset_time_ = nav_2d_utils::searchAndGetParam(critic_nh_, "oscillation_reset_time", -1.0);
00100 
00108   std::string resolved_name;
00109   if (critic_nh_.hasParam("x_only_threshold"))
00110   {
00111     critic_nh_.getParam("x_only_threshold", x_only_threshold_);
00112   }
00113   else if (critic_nh_.searchParam("min_speed_xy", resolved_name))
00114   {
00115     critic_nh_.getParam(resolved_name, x_only_threshold_);
00116   }
00117   else if (critic_nh_.searchParam("min_trans_vel", resolved_name))
00118   {
00119     ROS_WARN_NAMED("OscillationCritic", "Parameter min_trans_vel is deprecated. "
00120                                         "Please use the name min_speed_xy or x_only_threshold instead.");
00121     critic_nh_.getParam(resolved_name, x_only_threshold_);
00122   }
00123   else
00124   {
00125     x_only_threshold_ = 0.05;
00126   }
00127 
00128   reset();
00129 }
00130 
00131 bool OscillationCritic::prepare(const geometry_msgs::Pose2D& pose,
00132                                 const nav_2d_msgs::Twist2D& vel,
00133                                 const geometry_msgs::Pose2D& goal,
00134                                 const nav_2d_msgs::Path2D& global_plan)
00135 {
00136   pose_ = pose;
00137   return true;
00138 }
00139 
00140 void OscillationCritic::debrief(const nav_2d_msgs::Twist2D& cmd_vel)
00141 {
00142   if (setOscillationFlags(cmd_vel))
00143   {
00144     prev_stationary_pose_ = pose_;
00145     prev_reset_time_ = ros::Time::now();
00146   }
00147 
00148   
00149   if (x_trend_.hasSignFlipped() || y_trend_.hasSignFlipped() || theta_trend_.hasSignFlipped())
00150   {
00151     
00152     if (resetAvailable())
00153     {
00154       reset();
00155     }
00156   }
00157 }
00158 
00159 bool OscillationCritic::resetAvailable()
00160 {
00161   if (oscillation_reset_dist_ >= 0.0)
00162   {
00163     double x_diff = pose_.x - prev_stationary_pose_.x;
00164     double y_diff = pose_.y - prev_stationary_pose_.y;
00165     double sq_dist = x_diff * x_diff + y_diff * y_diff;
00166     if (sq_dist > oscillation_reset_dist_sq_)
00167     {
00168       return true;
00169     }
00170   }
00171   if (oscillation_reset_angle_ >= 0.0)
00172   {
00173     double th_diff = pose_.theta - prev_stationary_pose_.theta;
00174     if (fabs(th_diff) > oscillation_reset_angle_)
00175     {
00176       return true;
00177     }
00178   }
00179   if (oscillation_reset_time_ >= 0.0)
00180   {
00181     double t_diff = (ros::Time::now() - prev_reset_time_).toSec();
00182     if (t_diff > oscillation_reset_time_)
00183     {
00184       return true;
00185     }
00186   }
00187   return false;
00188 }
00189 
00190 void OscillationCritic::reset()
00191 {
00192   x_trend_.reset();
00193   y_trend_.reset();
00194   theta_trend_.reset();
00195 }
00196 
00197 bool OscillationCritic::setOscillationFlags(const nav_2d_msgs::Twist2D& cmd_vel)
00198 {
00199   bool flag_set = false;
00200   
00201   flag_set |= x_trend_.update(cmd_vel.x);
00202 
00203   
00204   if (x_only_threshold_ < 0.0 || fabs(cmd_vel.x) <= x_only_threshold_)
00205   {
00206     flag_set |= y_trend_.update(cmd_vel.y);
00207     flag_set |= theta_trend_.update(cmd_vel.theta);
00208   }
00209   return flag_set;
00210 }
00211 
00212 double OscillationCritic::scoreTrajectory(const dwb_msgs::Trajectory2D& traj)
00213 {
00214   if (x_trend_.isOscillating(traj.velocity.x) ||
00215       y_trend_.isOscillating(traj.velocity.y) ||
00216       theta_trend_.isOscillating(traj.velocity.theta))
00217   {
00218     throw nav_core2::IllegalTrajectoryException(name_, "Trajectory is oscillating.");
00219   }
00220   return 0.0;
00221 }
00222 
00223 }