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

在图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中,由于第一个点A就在落在本地代价地图内,所以i=0,
- 从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点。以下是我用方法。
- 以机器人当前位置R点为中心,扩展出一个正方形。
- 从A开始,找出第一个在正方形中的点,这个点作为第一阶段的结果i。图1中是点C附近。
- 如果没找到正方形中的点,认为这条全局路径不适合的,需要调用makePlan重新规划全局路径。