大概步骤
1-就是把机器人走过的全局路线给裁剪掉,因为已经过去了没有比较再参与计算后面的局部规划。
pruneGlobalPlan(*tf_, robot_pose, global_plan_, cfg_.trajectory.global_plan_prune_distance);
2-就是截取距离当前机器人这个max_global_plan_lookahead_dist距离的全局路径,并存放在transformed_plan里,函数中各种转化其实没有用到,因为都是在map坐标系下
if (!transformGlobalPlan(*tf_, global_plan_, robot_pose, *costmap_, global_frame_, cfg_.trajectory.max_global_plan_lookahead_dist,
transformed_plan, &goal_idx, &tf_plan_to_global))
3-就是对上一步截取的距离进行采样,采样后只会更稀疏不会更密集,采样间隔为global_plan_viapoint_sep,采样后的lu。
if (!custom_via_points_active_)
updateViaPointsContainer(transformed_plan, cfg_.trajectory.global_plan_viapoint_sep);
4-检测是否到达目标点
tf::Stamped<tf::Pose> global_goal;
tf::poseStampedMsgToTF(global_plan_.back(), global_goal);
global_goal.setData( tf_plan_to_global * global_goal );
double dx = global_goal.getOrigin().getX() - robot_pose_.x();
double dy = global_goal.getOrigin().getY() - robot_pose_.y();
double delta_orient = g2o::normalize_theta( tf::getYaw(global_goal.getRotation()) - robot_pose_.theta() );
if(fabs(std::sqrt(dx*dx+dy*dy)) < cfg_.goal_tolerance.xy_goal_tolerance
&& fabs(delta_orient) < cfg_.goal_tolerance.yaw_goal_tolerance
&& (!cfg_.goal_tolerance.complete_global_plan || via_points_.size() == 0))
{
goal_reached_ = true;
return true;
}
5-检测是否轨迹有异常并进入备份模式同时设置一些参数
configureBackupModes(transformed_plan, goal_idx);
6-检测截取的transformed_plan是否为空
if (transformed_plan.empty())
{
ROS_WARN("Transformed plan is empty. Cannot determine a local plan.");
return false;
}
7-获取局部目标的终点,就是transformed_plan的最后一个点,这里目标点的方向有2种方式,一个就是不需要处理,一个是目标点附近做平均值后的方向。有点意思。
tf::Stamped<tf::Pose> goal_point;
tf::poseStampedMsgToTF(transformed_plan.back(), goal_point);
robot_goal_.x() = goal_point.getOrigin().getX();
robot_goal_.y() = goal_point.getOrigin().getY();
if (cfg_.trajectory.global_plan_overwrite_orientation)
{
robot_goal_.theta() = estimateLocalGoalOrientation(global_plan_, goal_point, goal_idx, tf_plan_to_global);
transformed_plan.back().pose.orientation = tf::createQuaternionMsgFromYaw(robot_goal_.theta());
}
else
{
robot_goal_.theta() = tf::getYaw(goal_point.getRotation());
}
8-一般发生在目标位置基本不变或已经到达,但是角度不对,发生的纯旋转运动
if (transformed_plan.size()==1)
{
transformed_plan.insert(transformed_plan.begin(), geometry_msgs::PoseStamped());
}
tf::poseTFToMsg(robot_pose, transformed_plan.front().pose);
9-和障碍物有关的操作,这里暂时跳过
obstacles_.clear();
if (costmap_converter_)
updateObstacleContainerWithCostmapConverter();
else
updateObstacleContainerWithCostmap();
updateObstacleContainerWithCustomObstacles();
10-重头戏,计算优化后的局部规划结果,如果没有成功,则巴拉巴拉记录一番。
boost::mutex::scoped_lock cfg_lock(cfg_.configMutex());
bool success = planner_->plan(transformed_plan, &robot_vel_, cfg_.goal_tolerance.free_goal_vel);
if (!success)
{
planner_->clearPlanner();
ROS_WARN("teb_local_planner was not able to obtain a local plan for the current setting.");
++no_infeasible_plans_;
time_last_infeasible_plan_ = ros::Time::now();
last_cmd_ = cmd_vel;
return false;
}
11-是否检测车体轮廓线的碰撞情况,feasibility_check_no_poses是检测当前位置前面的几个局部规划点是否会发生碰撞。如果会碰撞,则巴拉巴拉记录一下。
if(cfg_.robot.is_footprint_dynamic)
{
footprint_spec_ = costmap_ros_->getRobotFootprint();
costmap_2d::calculateMinAndMaxDistances(footprint_spec_, robot_inscribed_radius_, robot_circumscribed_radius);
}
bool feasible = planner_->isTrajectoryFeasible(costmap_model_.get(), footprint_spec_, robot_inscribed_radius_, robot_circumscribed_radius, cfg_.trajectory.feasibility_check_no_poses);
if (!feasible)
{
cmd_vel.linear.x = 0;
cmd_vel.linear.y = 0;
cmd_vel.angular.z = 0;
planner_->clearPlanner();
ROS_WARN("TebLocalPlannerROS: trajectory is not feasible. Resetting planner...");
++no_infeasible_plans_;
time_last_infeasible_plan_ = ros::Time::now();
last_cmd_ = cmd_vel;
return false;
}
12-获取局部规划后应该发送的速度,control_look_ahead_poses这个参数是要参照当前机器人后面多少个局部规划位姿来计算控制速度。
if (!planner_->getVelocityCommand(cmd_vel.linear.x, cmd_vel.linear.y, cmd_vel.angular.z, cfg_.trajectory.control_look_ahead_poses))
{
planner_->clearPlanner();
ROS_WARN("TebLocalPlannerROS: velocity command invalid. Resetting planner...");
++no_infeasible_plans_;
time_last_infeasible_plan_ = ros::Time::now();
last_cmd_ = cmd_vel;
return false;
}
13-当优化后的局部规划速度超过了最大速度,则限制速度。
saturateVelocity(cmd_vel.linear.x, cmd_vel.linear.y, cmd_vel.angular.z, cfg_.robot.max_vel_x, cfg_.robot.max_vel_y,
cfg_.robot.max_vel_theta, cfg_.robot.max_vel_x_backwards);
14-对于carlike-robot(阿卡曼模型)的小车,可以使用控制角度代替角速度
if (cfg_.robot.cmd_angle_instead_rotvel)
{
cmd_vel.angular.z = convertTransRotVelToSteeringAngle(cmd_vel.linear.x, cmd_vel.angular.z, cfg_.robot.wheelbase, 0.95*cfg_.robot.min_turning_radius);
if (!std::isfinite(cmd_vel.angular.z))
{
cmd_vel.linear.x = cmd_vel.linear.y = cmd_vel.angular.z = 0;
last_cmd_ = cmd_vel;
planner_->clearPlanner();
ROS_WARN("TebLocalPlannerROS: Resulting steering angle is not finite. Resetting planner...");
++no_infeasible_plans_;
time_last_infeasible_plan_ = ros::Time::now();
return false;
}
}
15-万事大吉,重置记录一些信息,可视化一下
no_infeasible_plans_ = 0;
last_cmd_ = cmd_vel;
planner_->visualize();
visualization_->publishObstacles(obstacles_);
visualization_->publishViaPoints(via_points_);
visualization_->publishGlobalPlan(global_plan_);
return true;