move_base分析(五) planService和makePlan函数

move_base源码没有获取机器人当前位姿的地方,这属于局部路径算法的范畴。只能获得全局目标的位姿

bool MoveBase::makePlan(const geometry_msgs::PoseStamped& goal, vector& plan)

此函数只在一个地方被调用,就是planThread()线程被唤醒之后开始规划路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
boost::unique_lock<costmap_2d::Costmap2D::mutex_t> lock(*(planner_costmap_ros_->getCostmap()->getMutex() ));
plan.clear();
if(planner_costmap_ros_ == NULL) {
log.error("Planner costmap ROS is NULL, unable to create global plan");
return false;
}
//get the starting pose of the robot
tf::Stamped<tf::Pose> global_pose;
if(!planner_costmap_ros_->getRobotPose(global_pose)) {
log.warn("Unable to get starting pose of robot, unable to create global plan");
return false;
}
geometry_msgs::PoseStamped start;
tf::poseStampedTFToMsg(global_pose, start);

// 这里就是 GlobalPlanner::makePlan 了
if(!planner_->makePlan(start, goal, plan) || plan.empty()){
ROS_WARN("[move_base] Failed to find a plan to point (%.2f, %.2f)",
goal.pose.position.x, goal.pose.position.y);
return false;
}
return true;

代码并不复杂, 最后实际就进入bool GlobalPlanner::makePlan(const geometry_msgs::PoseStamped& start, const geometry_msgs::PoseStamped& goal, double tolerance, std::vector<geometry_msgs::PoseStamped>& plan)

这里要参考全局路径规划(二) makePlan


MoveBase::planService(nav_msgs::GetPlan::Request &req, nav_msgs::GetPlan::Response &resp)

req参数包含了起点和目标信息,这个服务回调函数的的核心是planner_->makePlan

  1. move_base server必须在inactive状态,否则不向下执行

  2. 判断global planner的costmap是否存在;若req给定机器人初始位姿则使用,否则使用getRobotPose获得机器人所在位置做初始位姿

  3. 调用clearCostmapWindows完成对机器人区域的clear, clear_radius由参数设置

  4. 调用 if(!planner_->makePlan(start, req.goal, global_plan) || global_plan.empty()) 这是完成plan计算的核心部分。判断这个调用是否成功,如果失败,则在目标区域附近搜索,多次更改req.goal的值,并重新调用makePlan;新的goal如下图:

各个可能位置之间的水平和竖直间距和req.tolerance正相关

如果还是失败,则此次路径规划无解。如果成功,直接break循环,把原来无法达到的目标点插入global_plan容器的最后,local planner一般会从新的目标点导航到原目标点.

  1. global_plan拷贝到resp.plan

MoveBase::clearCostmapWindows(double size_x, double size_y)

planService·用到了clearCostmapWindows函数,它只被调用了这一次,过程如下:

  • 通过planner_costmap_ros_->getRobotPose(global_pose); 获取在全局地图的global_pose
  • 以这个点为中心,找到以size_x和size_y为边长的矩形的四个顶点

  • 调用planner_costmap_ros_->getCostmap()->setConvexPolygonCost(clear_poly, costmap_2d::FREE_SPACE);完成对机器人所在区域的clear工作

  • 以上同样的操作在controller_costmap_ros上也操作一遍,这样globa costmap 和local costmap都已经在机器人所在的区域完成clear工作