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
00036
00037 #include <pluginlib/class_list_macros.h>
00038
00039 #include <dwa_local_planner/dwa_planner_ros.h>
00040 #include <base_local_planner/goal_functions.h>
00041
00042
00043 PLUGINLIB_DECLARE_CLASS(dwa_local_planner, DWAPlannerROS, dwa_local_planner::DWAPlannerROS, nav_core::BaseLocalPlanner)
00044
00045 namespace dwa_local_planner {
00046 void DWAPlannerROS::initialize(std::string name, tf::TransformListener* tf,
00047 costmap_2d::Costmap2DROS* costmap_ros){
00048 if(!initialized_){
00049 tf_ = tf;
00050 rotating_to_goal_ = false;
00051
00052 costmap_ros_ = costmap_ros;
00053
00054 ros::NodeHandle pn("~/" + name);
00055
00056 g_plan_pub_ = pn.advertise<nav_msgs::Path>("global_plan", 1);
00057 l_plan_pub_ = pn.advertise<nav_msgs::Path>("local_plan", 1);
00058
00059 pn.param("prune_plan", prune_plan_, true);
00060
00061 pn.param("yaw_goal_tolerance", yaw_goal_tolerance_, 0.05);
00062 pn.param("xy_goal_tolerance", xy_goal_tolerance_, 0.1);
00063
00064 pn.param("rot_stopped_vel", rot_stopped_vel_, 1e-2);
00065 pn.param("trans_stopped_vel", trans_stopped_vel_, 1e-2);
00066
00067 pn.param("latch_xy_goal_tolerance", latch_xy_goal_tolerance_, false);
00068
00069
00070 ros::NodeHandle gn;
00071 odom_sub_ = gn.subscribe<nav_msgs::Odometry>("odom", 1, boost::bind(&DWAPlannerROS::odomCallback, this, _1));
00072
00073 pn.param("max_rot_vel", max_vel_th_, 1.0);
00074 min_vel_th_ = -1.0 * max_vel_th_;
00075
00076 pn.param("min_rot_vel", min_rot_vel_, 0.4);
00077
00078
00079 dp_ = boost::shared_ptr<DWAPlanner>(new DWAPlanner(name, costmap_ros_));
00080
00081 initialized_ = true;
00082 }
00083 else{
00084 ROS_WARN("This planner has already been initialized, doing nothing.");
00085 }
00086 }
00087
00088 void DWAPlannerROS::odomCallback(const nav_msgs::Odometry::ConstPtr& msg){
00089
00090 boost::mutex::scoped_lock(odom_mutex_);
00091 base_odom_.twist.twist.linear.x = msg->twist.twist.linear.x;
00092 base_odom_.twist.twist.linear.y = msg->twist.twist.linear.y;
00093 base_odom_.twist.twist.angular.z = msg->twist.twist.angular.z;
00094 ROS_DEBUG("In the odometry callback with velocity values: (%.2f, %.2f, %.2f)",
00095 base_odom_.twist.twist.linear.x, base_odom_.twist.twist.linear.y, base_odom_.twist.twist.angular.z);
00096 }
00097
00098 bool DWAPlannerROS::stopWithAccLimits(const tf::Stamped<tf::Pose>& global_pose, const tf::Stamped<tf::Pose>& robot_vel, geometry_msgs::Twist& cmd_vel){
00099 Eigen::Vector3f acc_lim = dp_->getAccLimits();
00100
00101
00102 double vx = sign(robot_vel.getOrigin().x()) * std::max(0.0, (fabs(robot_vel.getOrigin().x()) - acc_lim[0] * dp_->getSimPeriod()));
00103 double vy = sign(robot_vel.getOrigin().y()) * std::max(0.0, (fabs(robot_vel.getOrigin().y()) - acc_lim[1] * dp_->getSimPeriod()));
00104
00105 double vel_yaw = tf::getYaw(robot_vel.getRotation());
00106 double vth = sign(vel_yaw) * std::max(0.0, (fabs(vel_yaw) - acc_lim[2] * dp_->getSimPeriod()));
00107
00108
00109 double yaw = tf::getYaw(global_pose.getRotation());
00110 bool valid_cmd = dp_->checkTrajectory(Eigen::Vector3f(global_pose.getOrigin().getX(), global_pose.getOrigin().getY(), yaw),
00111 Eigen::Vector3f(vx, vy, vth));
00112
00113
00114 if(valid_cmd){
00115 ROS_DEBUG("Slowing down... using vx, vy, vth: %.2f, %.2f, %.2f", vx, vy, vth);
00116 cmd_vel.linear.x = vx;
00117 cmd_vel.linear.y = vy;
00118 cmd_vel.angular.z = vth;
00119 return true;
00120 }
00121
00122 cmd_vel.linear.x = 0.0;
00123 cmd_vel.linear.y = 0.0;
00124 cmd_vel.angular.z = 0.0;
00125 return false;
00126 }
00127
00128 bool DWAPlannerROS::rotateToGoal(const tf::Stamped<tf::Pose>& global_pose, const tf::Stamped<tf::Pose>& robot_vel, double goal_th, geometry_msgs::Twist& cmd_vel){
00129 Eigen::Vector3f acc_lim = dp_->getAccLimits();
00130 double yaw = tf::getYaw(global_pose.getRotation());
00131 double vel_yaw = tf::getYaw(robot_vel.getRotation());
00132 cmd_vel.linear.x = 0;
00133 cmd_vel.linear.y = 0;
00134 double ang_diff = angles::shortest_angular_distance(yaw, goal_th);
00135
00136 double v_theta_samp = ang_diff > 0.0 ? std::min(max_vel_th_,
00137 std::max(min_rot_vel_, ang_diff)) : std::max(min_vel_th_,
00138 std::min(-1.0 * min_rot_vel_, ang_diff));
00139
00140
00141 double max_acc_vel = fabs(vel_yaw) + acc_lim[2] * dp_->getSimPeriod();
00142 double min_acc_vel = fabs(vel_yaw) - acc_lim[2] * dp_->getSimPeriod();
00143
00144 v_theta_samp = sign(v_theta_samp) * std::min(std::max(fabs(v_theta_samp), min_acc_vel), max_acc_vel);
00145
00146
00147 double max_speed_to_stop = sqrt(2 * acc_lim[2] * fabs(ang_diff));
00148
00149 v_theta_samp = sign(v_theta_samp) * std::min(max_speed_to_stop, fabs(v_theta_samp));
00150
00151 if(fabs(v_theta_samp) < min_rot_vel_)
00152 v_theta_samp = sign(v_theta_samp) * min_rot_vel_;
00153
00154
00155 bool valid_cmd = dp_->checkTrajectory(Eigen::Vector3f(global_pose.getOrigin().getX(), global_pose.getOrigin().getY(), yaw),
00156 Eigen::Vector3f( 0.0, 0.0, v_theta_samp));
00157
00158 ROS_DEBUG("Moving to desired goal orientation, th cmd: %.2f, valid_cmd: %d", v_theta_samp, valid_cmd);
00159
00160 if(valid_cmd){
00161 cmd_vel.angular.z = v_theta_samp;
00162 return true;
00163 }
00164
00165 cmd_vel.angular.z = 0.0;
00166 return false;
00167
00168 }
00169
00170 bool DWAPlannerROS::computeVelocityCommands(geometry_msgs::Twist& cmd_vel){
00171 if(!initialized_){
00172 ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
00173 return false;
00174 }
00175
00176 std::vector<geometry_msgs::PoseStamped> local_plan;
00177 tf::Stamped<tf::Pose> global_pose;
00178 if(!costmap_ros_->getRobotPose(global_pose))
00179 return false;
00180
00181 costmap_2d::Costmap2D costmap;
00182 costmap_ros_->getCostmapCopy(costmap);
00183 std::vector<geometry_msgs::PoseStamped> transformed_plan;
00184
00185 if(!base_local_planner::transformGlobalPlan(*tf_, global_plan_, *costmap_ros_, costmap_ros_->getGlobalFrameID(), transformed_plan)){
00186 ROS_WARN("Could not transform the global plan to the frame of the controller");
00187 return false;
00188 }
00189
00190
00191 if(prune_plan_)
00192 base_local_planner::prunePlan(global_pose, transformed_plan, global_plan_);
00193
00194
00195
00196 costmap_ros_->clearRobotFootprint();
00197
00198
00199 geometry_msgs::Twist global_vel;
00200
00201 {
00202 boost::mutex::scoped_lock lock(odom_mutex_);
00203 global_vel.linear.x = base_odom_.twist.twist.linear.x;
00204 global_vel.linear.y = base_odom_.twist.twist.linear.y;
00205 global_vel.angular.z = base_odom_.twist.twist.angular.z;
00206 }
00207
00208 tf::Stamped<tf::Pose> drive_cmds;
00209 drive_cmds.frame_id_ = costmap_ros_->getBaseFrameID();
00210
00211 tf::Stamped<tf::Pose> robot_vel;
00212 robot_vel.setData(btTransform(tf::createQuaternionFromYaw(global_vel.angular.z), btVector3(global_vel.linear.x, global_vel.linear.y, 0)));
00213 robot_vel.frame_id_ = costmap_ros_->getBaseFrameID();
00214 robot_vel.stamp_ = ros::Time();
00215
00216
00217
00218
00219
00220
00221
00222
00223 if(transformed_plan.empty())
00224 return false;
00225
00226 tf::Stamped<tf::Pose> goal_point;
00227 tf::poseStampedMsgToTF(transformed_plan.back(), goal_point);
00228
00229 double goal_x = goal_point.getOrigin().getX();
00230 double goal_y = goal_point.getOrigin().getY();
00231
00232 double yaw = tf::getYaw(goal_point.getRotation());
00233
00234 double goal_th = yaw;
00235
00236
00237 if(base_local_planner::goalPositionReached(global_pose, goal_x, goal_y, xy_goal_tolerance_) || xy_tolerance_latch_){
00238
00239
00240 if(latch_xy_goal_tolerance_)
00241 xy_tolerance_latch_ = true;
00242
00243
00244 if(base_local_planner::goalOrientationReached(global_pose, goal_th, yaw_goal_tolerance_)){
00245
00246 cmd_vel.linear.x = 0.0;
00247 cmd_vel.linear.y = 0.0;
00248 cmd_vel.angular.z = 0.0;
00249 rotating_to_goal_ = false;
00250 xy_tolerance_latch_ = false;
00251 }
00252 else {
00253
00254
00255 dp_->updatePlan(transformed_plan);
00256 base_local_planner::Trajectory path = dp_->findBestPath(global_pose, robot_vel, drive_cmds);
00257
00258
00259 nav_msgs::Odometry base_odom;
00260 {
00261 boost::recursive_mutex::scoped_lock(odom_lock_);
00262 base_odom = base_odom_;
00263 }
00264
00265
00266 if(!rotating_to_goal_ && !base_local_planner::stopped(base_odom, rot_stopped_vel_, trans_stopped_vel_)){
00267 if(!stopWithAccLimits(global_pose, robot_vel, cmd_vel))
00268 return false;
00269 }
00270
00271 else{
00272
00273 rotating_to_goal_ = true;
00274 if(!rotateToGoal(global_pose, robot_vel, goal_th, cmd_vel))
00275 return false;
00276 }
00277 }
00278
00279
00280 base_local_planner::publishPlan(transformed_plan, g_plan_pub_, 0.0, 1.0, 0.0, 0.0);
00281 base_local_planner::publishPlan(local_plan, l_plan_pub_, 0.0, 0.0, 1.0, 0.0);
00282
00283
00284 return true;
00285 }
00286
00287 dp_->updatePlan(transformed_plan);
00288
00289
00290 base_local_planner::Trajectory path = dp_->findBestPath(global_pose, robot_vel, drive_cmds);
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302 cmd_vel.linear.x = drive_cmds.getOrigin().getX();
00303 cmd_vel.linear.y = drive_cmds.getOrigin().getY();
00304 yaw = tf::getYaw(drive_cmds.getRotation());
00305
00306 cmd_vel.angular.z = yaw;
00307
00308
00309 if(path.cost_ < 0){
00310 local_plan.clear();
00311 base_local_planner::publishPlan(transformed_plan, g_plan_pub_, 0.0, 1.0, 0.0, 0.0);
00312 base_local_planner::publishPlan(local_plan, l_plan_pub_, 0.0, 0.0, 1.0, 0.0);
00313 return false;
00314 }
00315
00316
00317 for(unsigned int i = 0; i < path.getPointsSize(); ++i){
00318 double p_x, p_y, p_th;
00319 path.getPoint(i, p_x, p_y, p_th);
00320
00321 tf::Stamped<tf::Pose> p = tf::Stamped<tf::Pose>(tf::Pose(tf::createQuaternionFromYaw(p_th), tf::Point(p_x, p_y, 0.0)), ros::Time::now(), costmap_ros_->getGlobalFrameID());
00322 geometry_msgs::PoseStamped pose;
00323 tf::poseStampedTFToMsg(p, pose);
00324 local_plan.push_back(pose);
00325 }
00326
00327
00328 base_local_planner::publishPlan(transformed_plan, g_plan_pub_, 0.0, 1.0, 0.0, 0.0);
00329 base_local_planner::publishPlan(local_plan, l_plan_pub_, 0.0, 0.0, 1.0, 0.0);
00330 return true;
00331 }
00332
00333 bool DWAPlannerROS::isGoalReached(){
00334 if(!initialized_){
00335 ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
00336 return false;
00337 }
00338
00339
00340 nav_msgs::Odometry base_odom;
00341 {
00342 boost::recursive_mutex::scoped_lock(odom_lock_);
00343 base_odom = base_odom_;
00344 }
00345
00346 return base_local_planner::isGoalReached(*tf_, global_plan_, *costmap_ros_, costmap_ros_->getGlobalFrameID(), base_odom,
00347 rot_stopped_vel_, trans_stopped_vel_, xy_goal_tolerance_, yaw_goal_tolerance_);
00348 }
00349
00350 bool DWAPlannerROS::setPlan(const std::vector<geometry_msgs::PoseStamped>& orig_global_plan){
00351 if(!initialized_){
00352 ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
00353 return false;
00354 }
00355
00356
00357 global_plan_.clear();
00358 global_plan_ = orig_global_plan;
00359
00360
00361 xy_tolerance_latch_ = false;
00362
00363 return true;
00364 }
00365
00366 };