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
00038 #include <trajectory_planner_ros.h>
00039 #include <ros/console.h>
00040 #include <sys/time.h>
00041 #include <pluginlib/class_list_macros.h>
00042 #include <boost/tokenizer.hpp>
00043
00044 #include "geometry_msgs/PolygonStamped.h"
00045 #include "nav_msgs/Path.h"
00046 #include "goal_functions.h"
00047
00048 using namespace std;
00049 using namespace costmap_2d;
00050
00051
00052 PLUGINLIB_DECLARE_CLASS(iri_ackermann_local_planner, TrajectoryPlannerROS, iri_ackermann_local_planner::TrajectoryPlannerROS, nav_core::BaseLocalPlanner)
00053
00054 namespace iri_ackermann_local_planner {
00055
00056 void TrajectoryPlannerROS::reconfigureCB(AckermannLocalPlannerConfig &config, uint32_t level) {
00057 if(setup_ && config.restore_defaults) {
00058 config = default_config_;
00059
00060 config.restore_defaults = false;
00061 }
00062 if(!setup_) {
00063 default_config_ = config;
00064 setup_ = true;
00065 }
00066 else if(setup_) {
00067 tc_->reconfigure(config);
00068 }
00069 }
00070
00071 TrajectoryPlannerROS::TrajectoryPlannerROS() : world_model_(NULL), tc_(NULL), costmap_ros_(NULL), tf_(NULL), initialized_(false), setup_(false)
00072 {
00073 }
00074
00075 TrajectoryPlannerROS::TrajectoryPlannerROS(std::string name, tf::TransformListener* tf, Costmap2DROS* costmap_ros)
00076 : world_model_(NULL), tc_(NULL), costmap_ros_(NULL), tf_(NULL), initialized_(false), setup_(false) {
00077
00078 initialize(name, tf, costmap_ros);
00079 }
00080
00081 void TrajectoryPlannerROS::initialize(std::string name, tf::TransformListener* tf, Costmap2DROS* costmap_ros){
00082 if(!initialized_)
00083 {
00084 tf_ = tf;
00085 costmap_ros_ = costmap_ros;
00086 rot_stopped_velocity_ = 1e-2;
00087 trans_stopped_velocity_ = 1e-2;
00088 double sim_time, sim_granularity, angular_sim_granularity;
00089 int vx_samples, vtheta_samples;
00090 double pdist_scale, gdist_scale, occdist_scale, hdiff_scale;
00091 double ack_acc_max,ack_vel_max,ack_vel_min;
00092 double ack_steer_acc_max,ack_steer_vel_max,ack_steer_vel_min,ack_steer_angle_max,ack_steer_angle_min;
00093 double axis_distance;
00094 bool simple_attractor;
00095 int heading_points;
00096 string world_model_type;
00097 rotating_to_goal_ = false;
00098
00099
00100 costmap_ros_->getCostmapCopy(costmap_);
00101
00102 ros::NodeHandle private_nh("~/" + name);
00103
00104 g_plan_pub_ = private_nh.advertise<nav_msgs::Path>("global_plan", 1);
00105 l_plan_pub_ = private_nh.advertise<nav_msgs::Path>("local_plan", 1);
00106
00107 global_frame_ = costmap_ros_->getGlobalFrameID();
00108 robot_base_frame_ = costmap_ros_->getBaseFrameID();
00109 private_nh.param("prune_plan", prune_plan_, true);
00110
00111 private_nh.param("yaw_goal_tolerance", yaw_goal_tolerance_, 0.05);
00112 private_nh.param("xy_goal_tolerance", xy_goal_tolerance_, 0.10);
00113
00114
00115 inflation_radius_ = costmap_ros_->getInflationRadius();
00116
00117 private_nh.param("ack_acc_max", ack_acc_max, 1.0);
00118 private_nh.param("ack_vel_max", ack_vel_max, 0.6);
00119 private_nh.param("ack_vel_min", ack_vel_min, -0.6);
00120 private_nh.param("ack_steer_acc_max", ack_steer_acc_max, 1.0);
00121 private_nh.param("ack_steer_speed_max", ack_steer_vel_max, 0.5);
00122 private_nh.param("ack_steer_speed_min", ack_steer_vel_min, -0.5);
00123 private_nh.param("ack_steer_angle_max", ack_steer_angle_max, 0.35);
00124 private_nh.param("ack_steer_angle_min", ack_steer_angle_min, -0.35);
00125 private_nh.param("ack_axis_distance", axis_distance, 1.65);
00126
00127 private_nh.param("latch_xy_goal_tolerance", latch_xy_goal_tolerance_, false);
00128
00129
00130
00131
00132 std::string controller_frequency_param_name;
00133
00134 private_nh.param("sim_time", sim_time, 10.0);
00135 private_nh.param("sim_granularity", sim_granularity, 0.025);
00136 private_nh.param("angular_sim_granularity", angular_sim_granularity, sim_granularity);
00137 private_nh.param("vx_samples", vx_samples, 10);
00138 private_nh.param("vtheta_samples", vtheta_samples, 20);
00139
00140 private_nh.param("pdist_scale", pdist_scale, 0.6);
00141 private_nh.param("gdist_scale", gdist_scale, 0.8);
00142 private_nh.param("hdiff_scale", hdiff_scale, 1.0);
00143 private_nh.param("occdist_scale", occdist_scale, 0.01);
00144 private_nh.param("heading_points", heading_points, 8);
00145
00146 private_nh.param("world_model", world_model_type, string("costmap"));
00147
00148 simple_attractor = false;
00149
00150
00151 double min_pt_separation, max_obstacle_height, grid_resolution;
00152 private_nh.param("point_grid/max_sensor_range", max_sensor_range_, 2.0);
00153 private_nh.param("point_grid/min_pt_separation", min_pt_separation, 0.01);
00154 private_nh.param("point_grid/max_obstacle_height", max_obstacle_height, 2.0);
00155 private_nh.param("point_grid/grid_resolution", grid_resolution, 0.2);
00156
00157 ROS_ASSERT_MSG(world_model_type == "costmap", "At this time, only costmap world models are supported by this controller");
00158 world_model_ = new CostmapModel(costmap_);
00159
00160 tc_ = new TrajectoryPlanner(*world_model_, costmap_, costmap_ros_->getRobotFootprint(),
00161 ack_acc_max, ack_vel_max, ack_vel_min, ack_steer_acc_max,ack_steer_vel_max,ack_steer_vel_min,ack_steer_angle_max,ack_steer_angle_min,axis_distance,
00162 sim_time, sim_granularity, vx_samples, vtheta_samples, pdist_scale,gdist_scale, occdist_scale, hdiff_scale,simple_attractor,angular_sim_granularity,
00163 heading_points,xy_goal_tolerance_);
00164
00165 map_viz_.initialize(name, &costmap_, boost::bind(&TrajectoryPlanner::getCellCosts, tc_, _1, _2, _3, _4, _5, _6));
00166 initialized_ = true;
00167
00168 dsrv_ = new dynamic_reconfigure::Server<AckermannLocalPlannerConfig>(private_nh);
00169 dynamic_reconfigure::Server<AckermannLocalPlannerConfig>::CallbackType cb = boost::bind(&TrajectoryPlannerROS::reconfigureCB, this, _1, _2);
00170 dsrv_->setCallback(cb);
00171
00172 ros::NodeHandle global_node;
00173 odom_sub_ = global_node.subscribe<nav_msgs::Odometry>("odom", 1, boost::bind(&TrajectoryPlannerROS::odomCallback, this, _1));
00174 }
00175 else
00176 ROS_WARN("This planner has already been initialized, you can't call it twice, doing nothing");
00177 }
00178
00179 TrajectoryPlannerROS::~TrajectoryPlannerROS(){
00180
00181 delete dsrv_;
00182
00183 if(tc_ != NULL)
00184 delete tc_;
00185
00186 if(world_model_ != NULL)
00187 delete world_model_;
00188 }
00189
00190 void TrajectoryPlannerROS::odomCallback(const nav_msgs::Odometry::ConstPtr& msg){
00191
00192 boost::recursive_mutex::scoped_lock lock(odom_lock_);
00193 base_odom_.twist.twist.linear.x = msg->twist.twist.linear.x;
00194 base_odom_.twist.twist.linear.y = msg->twist.twist.linear.y;
00195 base_odom_.twist.twist.angular.z = msg->twist.twist.angular.z;
00196 ackermann_state_.linear.z=msg->twist.twist.linear.z;
00197 ackermann_state_.angular.x=msg->twist.twist.angular.x;
00198 ackermann_state_.angular.y=msg->twist.twist.angular.y;
00199 ROS_DEBUG("In the odometry callback with velocity values: (%.2f, %.2f, %.2f)",
00200 base_odom_.twist.twist.linear.x, base_odom_.twist.twist.linear.y, base_odom_.twist.twist.angular.z);
00201 }
00202
00203 bool TrajectoryPlannerROS::setPlan(const std::vector<geometry_msgs::PoseStamped>& orig_global_plan)
00204 {
00205 if(!initialized_)
00206 {
00207 ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
00208 return false;
00209 }
00210
00212 subPathList.clear();
00213 subPath.clear();
00214 subPathIndex = 0;
00215 double pathLength = 0;
00216 for(unsigned int i = 0; i < orig_global_plan.size(); ++i)
00217 {
00218 if(i>1 && i<orig_global_plan.size())
00219 {
00220 double x0 = orig_global_plan[i ].pose.position.x;
00221 double x1 = orig_global_plan[i-1].pose.position.x;
00222 double x2 = orig_global_plan[i-2].pose.position.x;
00223 double y0 = orig_global_plan[i ].pose.position.y;
00224 double y1 = orig_global_plan[i-1].pose.position.y;
00225 double y2 = orig_global_plan[i-2].pose.position.y;
00226 double angle=std::acos(((x0-x1)*(x1-x2)+(y0-y1)*(y1-y2))/(std::sqrt(std::pow(x0-x1,2)+std::pow(y0-y1,2))*std::sqrt(std::pow(x1-x2,2)+std::pow(y1-y2,2))));
00227 pathLength+= std::sqrt(std::pow(x0-x1,2)+std::pow(y0-y1,2));
00228 if(fabs(angle)>1.57)
00229 {
00230 if(pathLength>1.0)
00231 {
00232 ROS_INFO("TrajectoryPlannerROS::setPlan: subPath split at i=%d, angle=%f, length=%f", i, angle, pathLength);
00233 subPathList.push_back(subPath);
00234 }
00235 else
00236 {
00237 ROS_INFO("TrajectoryPlannerROS::setPlan: subPath split at i=%d, angle=%f, Ignored by length=%f", i, angle, pathLength);
00238 }
00239 subPath.clear();
00240 pathLength=0.0;
00241 }
00242 }
00243 subPath.push_back(orig_global_plan[i]);
00244 }
00245 subPathList.push_back(subPath);
00246 ROS_INFO("TrajectoryPlannerROS::setPlan: subPath last length=%f", pathLength);
00247 ROS_INFO("TrajectoryPlannerROS::setPlan: Global plan (%lu points) split in %lu paths", orig_global_plan.size(), subPathList.size());
00248 global_plan_.clear();
00249 global_plan_ = subPathList[subPathIndex];
00251
00252
00255
00256
00257 xy_tolerance_latch_ = false;
00258
00259 return true;
00260 }
00261
00262 bool TrajectoryPlannerROS::computeVelocityCommands(geometry_msgs::Twist& cmd_vel){
00263 if(!initialized_){
00264 ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
00265 return false;
00266 }
00267 ROS_INFO("TrajectoryPlannerROS::computeVelocityCommands!");
00268
00269 std::vector<geometry_msgs::PoseStamped> local_plan;
00270 tf::Stamped<tf::Pose> global_pose;
00271 if(!costmap_ros_->getRobotPose(global_pose))
00272 return false;
00273
00274 std::vector<geometry_msgs::PoseStamped> transformed_plan;
00275
00276 if(!transformGlobalPlan(*tf_, global_plan_, *costmap_ros_, global_frame_, transformed_plan)){
00277 ROS_WARN("Could not transform the global plan to the frame of the controller");
00278 return false;
00279 }
00280
00281
00282 if(prune_plan_)
00283 prunePlan(global_pose, transformed_plan, global_plan_);
00284
00285
00286
00287 costmap_ros_->clearRobotFootprint();
00288
00289
00290 costmap_ros_->getCostmapCopy(costmap_);
00291
00292
00293 geometry_msgs::Twist global_vel;
00294
00295 odom_lock_.lock();
00296 global_vel.linear.x = base_odom_.twist.twist.linear.x;
00297 global_vel.linear.y = base_odom_.twist.twist.linear.y;
00298 global_vel.angular.z = base_odom_.twist.twist.angular.z;
00299 odom_lock_.unlock();
00300
00301 tf::Stamped<tf::Pose> drive_cmds;
00302 drive_cmds.frame_id_ = robot_base_frame_;
00303
00304 tf::Stamped<tf::Pose> robot_vel;
00305 robot_vel.setData(tf::Transform(tf::createQuaternionFromYaw(global_vel.angular.z), tf::Vector3(global_vel.linear.x, global_vel.linear.y, 0)));
00306 robot_vel.frame_id_ = robot_base_frame_;
00307 robot_vel.stamp_ = ros::Time();
00308
00309
00310 if(transformed_plan.empty())
00311 return false;
00312
00313 tf::Stamped<tf::Pose> goal_point;
00314 tf::poseStampedMsgToTF(transformed_plan.back(), goal_point);
00315
00316 double goal_x = goal_point.getOrigin().getX();
00317 double goal_y = goal_point.getOrigin().getY();
00318
00319 double yaw = tf::getYaw(goal_point.getRotation());
00320
00321 double goal_th = yaw;
00322
00323
00324 if(goalPositionReached(global_pose, goal_x, goal_y, xy_goal_tolerance_) || xy_tolerance_latch_){
00325
00327 if(subPathIndex < subPathList.size()-1)
00328 {
00329 subPathIndex++;
00330 global_plan_.clear();
00331 global_plan_ = subPathList[subPathIndex];
00332 return true;
00333 }
00335
00336
00337
00338 if(latch_xy_goal_tolerance_)
00339 xy_tolerance_latch_ = true;
00340
00341
00342 if(goalOrientationReached(global_pose, goal_th, yaw_goal_tolerance_)){
00343
00344 cmd_vel.linear.x = 0.0;
00345 cmd_vel.linear.y = 0.0;
00346 cmd_vel.angular.z = 0.0;
00347 rotating_to_goal_ = false;
00348 xy_tolerance_latch_ = false;
00349 }
00350
00351
00352 publishPlan(transformed_plan, g_plan_pub_, 0.0, 1.0, 0.0, 0.0);
00353 publishPlan(local_plan, l_plan_pub_, 0.0, 0.0, 1.0, 0.0);
00354
00355
00356 return true;
00357 }
00358
00359 tc_->updatePlan(transformed_plan);
00360
00361
00362 Trajectory path = tc_->findBestPath(global_pose, robot_vel, drive_cmds,ackermann_state_);
00363
00364 ROS_INFO("Speed command x,y,yaw: %f,%f,%f",drive_cmds.getOrigin().getX(),drive_cmds.getOrigin().getY(),tf::getYaw(drive_cmds.getRotation()));
00365
00366 map_viz_.publishCostCloud();
00367
00368
00369 cmd_vel.linear.x = drive_cmds.getOrigin().getX();
00370 cmd_vel.linear.y = drive_cmds.getOrigin().getY();
00371 yaw = tf::getYaw(drive_cmds.getRotation());
00372
00373 cmd_vel.angular.z = yaw;
00374
00375
00376 if(path.cost_ < 0){
00377 local_plan.clear();
00378 publishPlan(transformed_plan, g_plan_pub_, 0.0, 1.0, 0.0, 0.0);
00379 publishPlan(local_plan, l_plan_pub_, 0.0, 0.0, 1.0, 0.0);
00380 return false;
00381 }
00382
00383
00384 for(unsigned int i = 0; i < path.getPointsSize(); ++i){
00385 double p_x, p_y, p_th;
00386 path.getPoint(i, p_x, p_y, p_th);
00387
00388 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(), global_frame_);
00389 geometry_msgs::PoseStamped pose;
00390 tf::poseStampedTFToMsg(p, pose);
00391 local_plan.push_back(pose);
00392 }
00393
00394
00395 publishPlan(transformed_plan, g_plan_pub_, 0.0, 1.0, 0.0, 0.0);
00396 publishPlan(local_plan, l_plan_pub_, 0.0, 0.0, 1.0, 0.0);
00397 return true;
00398 }
00399
00400 bool TrajectoryPlannerROS::checkTrajectory(double vx_samp, double vy_samp, double vtheta_samp, bool update_map){
00401 tf::Stamped<tf::Pose> global_pose;
00402 if(costmap_ros_->getRobotPose(global_pose)){
00403 if(update_map){
00404
00405 costmap_ros_->clearRobotFootprint();
00406
00407
00408 costmap_ros_->getCostmapCopy(costmap_);
00409
00410
00411
00412 std::vector<geometry_msgs::PoseStamped> plan;
00413 geometry_msgs::PoseStamped pose_msg;
00414 tf::poseStampedTFToMsg(global_pose, pose_msg);
00415 plan.push_back(pose_msg);
00416 tc_->updatePlan(plan, true);
00417 }
00418
00419
00420 nav_msgs::Odometry base_odom;
00421 {
00422 boost::recursive_mutex::scoped_lock lock(odom_lock_);
00423 base_odom = base_odom_;
00424 }
00425
00426 return tc_->checkTrajectory(global_pose.getOrigin().x(), global_pose.getOrigin().y(), tf::getYaw(global_pose.getRotation()),
00427 base_odom.twist.twist.linear.x,
00428 base_odom.twist.twist.linear.y,
00429 base_odom.twist.twist.angular.z, vx_samp, vy_samp, vtheta_samp);
00430
00431 }
00432 ROS_WARN("Failed to get the pose of the robot. No trajectories will pass as legal in this case.");
00433 return false;
00434 }
00435
00436
00437 double TrajectoryPlannerROS::scoreTrajectory(double vx_samp, double vy_samp, double vtheta_samp, bool update_map){
00438
00439 tf::Stamped<tf::Pose> global_pose;
00440 if(costmap_ros_->getRobotPose(global_pose)){
00441 if(update_map){
00442
00443 costmap_ros_->clearRobotFootprint();
00444
00445
00446 costmap_ros_->getCostmapCopy(costmap_);
00447
00448
00449
00450 std::vector<geometry_msgs::PoseStamped> plan;
00451 geometry_msgs::PoseStamped pose_msg;
00452 tf::poseStampedTFToMsg(global_pose, pose_msg);
00453 plan.push_back(pose_msg);
00454 tc_->updatePlan(plan, true);
00455 }
00456
00457
00458 nav_msgs::Odometry base_odom;
00459 {
00460 boost::recursive_mutex::scoped_lock lock(odom_lock_);
00461 base_odom = base_odom_;
00462 }
00463
00464 return tc_->scoreTrajectory(global_pose.getOrigin().x(), global_pose.getOrigin().y(), tf::getYaw(global_pose.getRotation()),
00465 base_odom.twist.twist.linear.x,
00466 base_odom.twist.twist.linear.y,
00467 base_odom.twist.twist.angular.z, vx_samp, vy_samp, vtheta_samp);
00468
00469 }
00470 ROS_WARN("Failed to get the pose of the robot. No trajectories will pass as legal in this case.");
00471 return -1.0;
00472 }
00473
00474 bool TrajectoryPlannerROS::isGoalReached(){
00475 if(!initialized_){
00476 ROS_ERROR("This planner has not been initialized, please call initialize() before using this planner");
00477 return false;
00478 }
00479
00480
00481 nav_msgs::Odometry base_odom;
00482 {
00483 boost::recursive_mutex::scoped_lock lock(odom_lock_);
00484 base_odom = base_odom_;
00485 }
00486
00487 return iri_ackermann_local_planner::isGoalReached(*tf_, global_plan_, *costmap_ros_, global_frame_, base_odom,
00488 rot_stopped_velocity_, trans_stopped_velocity_, xy_goal_tolerance_, yaw_goal_tolerance_);
00489 }
00490 };