oscillation.cpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2017, Locus Robotics
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of the copyright holder nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
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   // if we've got restrictions... check if we can reset any oscillation flags
00149   if (x_trend_.hasSignFlipped() || y_trend_.hasSignFlipped() || theta_trend_.hasSignFlipped())
00150   {
00151     // Reset flags if enough time or distance has passed
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   // set oscillation flags for moving forward and backward
00201   flag_set |= x_trend_.update(cmd_vel.x);
00202 
00203   // we'll only set flags for strafing and rotating when we're not moving forward at all
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 }  // namespace dwb_critics


dwb_critics
Author(s): David V. Lu!!
autogenerated on Wed Jun 26 2019 20:09:47