Ros

base_local_planner::transformGlobalPlan

transformGlobalPlan功能是根据本地代价地图,从全局路径global_plan截取一段,并将路径点从/map坐标系转换到/odom坐标系,生成结果放在参数transformed_plan。

图1 一次transformGlobalPlan实例

在图1,AD这条红色曲线是makePlan规划出的全局路径global_plan,中间有145个路径点。[0]A(1.17739, 1.75393)是起始,[144]D(3.13889, 2.50000)是终点,[19]B(0.95596, 2.18709)、C分别在曲线上,它们都是map坐标系。

点R是机器人当前在map坐标系下坐标。

transformGlobalPlan可分为两个阶段。

  1. 从起始点开始,找到第一个落在本地代价地图内的点。图1中,由于第一个点A就在落在本地代价地图内,所以i=0,
  2. 从i点开始,找到第一个落在本地代价地图外的点,把当中代价地图内的点放入transformed_plan。放入时会由map坐标系转为odom坐标系。示例中B是第一个落在本地代价图外的点,于是第二阶段后,i=19,而#0到#18的点则放入transformed_plan,当然,在放入时要由map坐标系转为odom坐标系。

怎么判断路径点A是否要放入transformed_plan?——把机器人中心放到/map坐标系下,记为robot_pose。如果A和robot_pose之间路径小于1.5米(本地代价地图半径),则放入

过程中路径点只是坐标系变换,不会发生插补。

在转换时,是不是已经走过的全局路径点,也会落在transformed_plan?——会。只要那些点和robot_pose距离小于1.5米。接下如果出现一次本地规划得不到轨迹,那MoveBase会调用makePlan,那些走过的全局路径点自然也没了。

 

一、官方源码

  • [IN]tf。用于获取map-->odom的坐标系变换tf。
  • [IN]global_plan。makePlan生成的全局路径。
  • [IN]global_pose。机器人在/odom坐标系下的当前位姿。即图1中的current_pose_。
  • [IN]costmap。本地代价地图。
  • [IN]global_frame。路径点要转换到的坐标系。示例“odom”。
  • [OUT]transformed_plan。存储截取出的路径。
<libros>/base_local_planner/src/goal_functions.cpp
------
  bool transformGlobalPlan(
      const tf2_ros::Buffer& tf,
      const std::vector<geometry_msgs::PoseStamped>& global_plan,
      const geometry_msgs::PoseStamped& global_pose,
      const costmap_2d::Costmap2D& costmap,
      const std::string& global_frame,
      std::vector<geometry_msgs::PoseStamped>& transformed_plan){
    transformed_plan.clear();

    if (global_plan.empty()) {
      ROS_ERROR("Received plan with zero length");
      return false;
    }

    const geometry_msgs::PoseStamped& plan_pose = global_plan[0];
    try {
      // get plan_to_global_transform from plan frame to global_frame
      geometry_msgs::TransformStamped plan_to_global_transform = tf.lookupTransform(global_frame, ros::Time(),
          plan_pose.header.frame_id, plan_pose.header.stamp, plan_pose.header.frame_id, ros::Duration(0.5));

      //let's get the pose of the robot in the frame of the plan
      geometry_msgs::PoseStamped robot_pose;
      tf.transform(global_pose, robot_pose, plan_pose.header.frame_id);

plan_to_global_transform是map-->odom的tf,global_pose是odom坐标系下的,robot_pose就是global_pose对应map坐标系下的。

      //we'll discard points on the plan that are outside the local costmap
      double dist_threshold = std::max(costmap.getSizeInCellsX() * costmap.getResolution() / 2.0,
                                       costmap.getSizeInCellsY() * costmap.getResolution() / 2.0);

      unsigned int i = 0;
      double sq_dist_threshold = dist_threshold * dist_threshold;
      double sq_dist = 0;

      //we need to loop to a point on the plan that is within a certain distance of the robot
      while(i < (unsigned int)global_plan.size()) {
        double x_diff = robot_pose.pose.position.x - global_plan[i].pose.position.x;
        double y_diff = robot_pose.pose.position.y - global_plan[i].pose.position.y;
        sq_dist = x_diff * x_diff + y_diff * y_diff;
        if (sq_dist <= sq_dist_threshold) {
          break;
        }
        ++i;
      }

第一阶段,从起始点开始,找到第一个落在本地代价地图内的点。这个点记为i。

      geometry_msgs::PoseStamped newer_pose;

      //now we'll transform until points are outside of our distance threshold
      while(i < (unsigned int)global_plan.size() && sq_dist <= sq_dist_threshold) {
        const geometry_msgs::PoseStamped& pose = global_plan[i];
        tf2::doTransform(pose, newer_pose, plan_to_global_transform);

        transformed_plan.push_back(newer_pose);

        double x_diff = robot_pose.pose.position.x - global_plan[i].pose.position.x;
        double y_diff = robot_pose.pose.position.y - global_plan[i].pose.position.y;
        sq_dist = x_diff * x_diff + y_diff * y_diff;

        ++i;
      }

第二阶段,从i点开始,找到第一个落在本地代价地图外的点,把当中代价地图内的点放入transformed_plan。放入时会由map坐标系转为odom坐标系。

    }
    catch(tf2::LookupException& ex) {
      ...
    }

    return true;
  }

 

二、修改源码

回到图1,按正确逻辑,指导路径应该是从R附近开始到终点D这段曲线。官方代码算出的则是AB(准确说,终点是B前面那个点),这已是个错误的指导路径。

解决思路是要在第一阶段找到正确i点。以下是我用方法。

  1. 以机器人当前位置R点为中心,扩展出一个正方形。
  2. 从A开始,找出第一个在正方形中的点,这个点作为第一阶段的结果i。图1中是点C附近。
  3. 如果没找到正方形中的点,认为这条全局路径不适合的,需要调用makePlan重新规划全局路径。

全部评论: 0

    写评论: