ROS 导航 :make_plan (路线规划)

本文深入讲解了在ROS中实现路径规划的方法,详细介绍了如何使用make_plan服务进行两点间最优路径的规划,包括代码示例和服务调用流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

以下是在学习ROS 导航时,按照自己的理解整理的资料,有不对的地方请指出。
路径规划:从一个点到另一个点,规划出最优的路线。用到service :make_plan (nav_msgs/GetPlan)
服务名为move_base_node/make_plan
nav_msgs/GetPlan api:

 # Get a plan from the current position to the goal Pose

# The start pose for the plan
geometry_msgs/PoseStamped start

# The final pose of the goal position
geometry_msgs/PoseStamped goal

# If the goal is obstructed, how many meters the planner can
# relax the constraint in x and y before failing.
float32 tolerance
---
nav_msgs/Path plan

Compact Message Definition
geometry_msgs/PoseStamped start
geometry_msgs/PoseStamped goal
float32 tolerance
nav_msgs/Path plan

现在学习如何使用
在工作空间新建package navigation_example

cd ~/catkin_ws/src
catkin_create_pkg navigation_example std_msgs rospy roscpp tf actionlib

    1
    2

CMakeList.txt 中的find_package如下

find_package(catkin REQUIRED COMPONENTS
  actionlib
  roscpp
  rospy
  std_msgs
  tf
)

在src目录下新建make_plan.cpp

/*
 * make_plan.cpp
 *
 *  Created on: Aug 10, 2016
 *      Author: unicorn
 */
//路线规划代码
#include <ros/ros.h>
#include <nav_msgs/GetPlan.h>
#include <geometry_msgs/PoseStamped.h>
#include <string>
#include <boost/foreach.hpp>
#define forEach BOOST_FOREACH
void fillPathRequest(nav_msgs::GetPlan::Request &request)
{
request.start.header.frame_id ="map";
request.start.pose.position.x = 12.378;//初始位置x坐标
request.start.pose.position.y = 28.638;//初始位置y坐标
request.start.pose.orientation.w = 1.0;//方向
request.goal.header.frame_id = "map";
request.goal.pose.position.x = 18.792;//终点坐标
request.goal.pose.position.y = 29.544;
request.goal.pose.orientation.w = 1.0;
request.tolerance = 0.5;//如果不能到达目标,最近可到的约束
}
//路线规划结果回调
void callPlanningService(ros::ServiceClient &serviceClient, nav_msgs::GetPlan &srv)
{
// Perform the actual path planner call
//执行实际路径规划器
if (serviceClient.call(srv)) {
//srv.response.plan.poses 为保存结果的容器,遍历取出
if (!srv.response.plan.poses.empty()) {
forEach(const geometry_msgs::PoseStamped &p, srv.response.plan.poses) {
ROS_INFO("x = %f, y = %f", p.pose.position.x, p.pose.position.y);
}
}
else {
ROS_WARN("Got empty plan");
}
}
else {
ROS_ERROR("Failed to call service %s - is the robot moving?",
serviceClient.getService().c_str());
}
}

int main(int argc, char** argv)
{
ros::init(argc, argv, "make_plan_node");
ros::NodeHandle nh;
// Init service query for make plan
//初始化路径规划服务,服务名称为"move_base_node/make_plan"
std::string service_name = "move_base_node/make_plan";
//等待服务空闲,如果已经在运行这个服务,会等到运行结束。
while (!ros::service::waitForService(service_name, ros::Duration(3.0))) {
ROS_INFO("Waiting for service move_base/make_plan to become available");
}
/*初始化客户端,(nav_msgs/GetPlan)
Allows an external user to ask for a plan to a given pose from move_base without causing move_base to execute that plan.
允许用户从move_base 请求一个plan,并不会导致move_base 执行此plan
*/
ros::ServiceClient serviceClient = nh.serviceClient<nav_msgs::GetPlan>(service_name, true);
if (!serviceClient) {
ROS_FATAL("Could not initialize get plan service from %s",
serviceClient.getService().c_str());
return -1;
}
nav_msgs::GetPlan srv;
//请求服务:规划路线
fillPathRequest(srv.request);
if (!serviceClient) {
ROS_FATAL("Persistent service connection to %s failed",
serviceClient.getService().c_str());
return -1;
}
ROS_INFO("conntect to %s",serviceClient.getService().c_str());
callPlanningService(serviceClient, srv);
}

CMakeList中添加

add_executable(make_plan src/make_plan.cpp)
 target_link_libraries(make_plan
   ${catkin_LIBRARIES}
 )

 

编译运行:

cd ~/catkin_ws
catkin_make
source devel/setup.bash
rosrun navigation_example make_plan

 

运行结果:

 

MoveBase::MoveBase(tf2_ros::Buffer &tf) : tf_(tf), as_(NULL), planner_costmap_ros_(NULL), controller_costmap_ros_(NULL), bgp_loader_("nav_core", "nav_core::BaseGlobalPlanner"), blp_loader_("nav_core", "nav_core::BaseLocalPlanner"), recovery_loader_("nav_core", "nav_core::RecoveryBehavior"), planner_plan_(NULL), latest_plan_(NULL), controller_plan_(NULL), runPlanner_(false), setup_(false), p_freq_change_(false), c_freq_change_(false), new_global_plan_(false) { // as_ = new MoveBaseActionServer(ros::NodeHandle(), "move_base", boost::bind(&MoveBase::executeCb, this, _1), false); ros::NodeHandle private_nh("~"); ros::NodeHandle nh; recovery_trigger_ = PLANNING_R; // get some parameters that will be global to the move base node std::string local_planner; // private_nh.param("base_global_planner", global_planner, std::string("navfn/NavfnROS")); private_nh.param("move_base/saveMapping", saveMapping, false); private_nh.param("savePath", savePath, std::string("/home/duzhong/dzacs/src/dzglobalplanner/mapping.txt")); private_nh.param("base_local_planner", local_planner, std::string("dwa_local_planner/DWAPlannerROS")); // private_nh.param("base_local_planner", local_planner, std::string("teb_local_planner/TebLocalPlannerROS")); private_nh.param("global_costmap/robot_base_frame", robot_base_frame_, std::string("base_link")); private_nh.param("global_costmap/global_frame", global_frame_, std::string("map")); private_nh.param("planner_frequency", planner_frequency_, 1.0); private_nh.param("controller_frequency", controller_frequency_, 3.0); private_nh.param("planner_patience", planner_patience_, 5.0); private_nh.param("controller_patience", controller_patience_, 15.0); private_nh.param("max_planning_retries", max_planning_retries_, -1); // disabled by default printf("savePath----move_base-->-=%s\n\n\n\n", savePath.c_str()); private_nh.param("oscillation_timeout", oscillation_timeout_, 0.0); private_nh.param("oscillation_distance", oscillation_distance_, 0.5); // set up plan triple buffer planner_plan_ = new std::vector<geometry_msgs::PoseStamped>(); latest_plan_ = new std::vector<geometry_msgs::PoseStamped>(); controller_plan_ = new std::vector<geometry_msgs::PoseStamped>(); // set up the planner's thread planner_thread_ = new boost::thread(boost::bind(&MoveBase::planThread, this)); // for commanding the base vel_pub_ = nh.advertise<geometry_msgs::Twist>("cmd_vel", 1); current_goal_pub_ = private_nh.advertise<geometry_msgs::PoseStamped>("current_goal", 0); plan_pub_ = private_nh.advertise<nav_msgs::Path>("plan", 1); all_plan_pub_ = private_nh.advertise<nav_msgs::Path>("allplan", 1); ros::NodeHandle action_nh("move_base"); action_goal_pub_ = action_nh.advertise<move_base_msgs::MoveBaseActionGoal>("goal", 1); // we'll provide a mechanism for some people to send goals as PoseStamped messages over a topic // they won't get any useful information back about its status, but this is useful for tools // like nav_view and rviz ros::NodeHandle simple_nh("move_base_simple"); goal_sub_ = simple_nh.subscribe<geometry_msgs::PoseStamped>("goal", 1, boost::bind(&MoveBase::goalCB, this, _1)); // we'll assume the radius of the robot to be consistent with what's specified for the costmaps private_nh.param("local_costmap/inscribed_radius", inscribed_radius_, 0.325); private_nh.param("local_costmap/circumscribed_radius", circumscribed_radius_, 0.46); private_nh.param("clearing_radius", clearing_radius_, circumscribed_radius_); private_nh.param("conservative_reset_dist", conservative_reset_dist_, 0.21); private_nh.param("shutdown_costmaps", shutdown_costmaps_, false); private_nh.param("clearing_rotation_allowed", clearing_rotation_allowed_, true); private_nh.param("recovery_behavior_enabled", recovery_behavior_enabled_, true); private_nh.param("road_paths_savePath", road_paths_savePath, std::string("/home/duzhong/dzacs/src/resource/road_paths")); private_nh.param("stop_points_savePath", stop_points_savePath, std::string("/home/duzhong/dzacs/src/resource/stop_points")); if (saveMapping) { printf("move_base--> saveMapping = true\n"); } else if (!saveMapping) { printf("move_base--> saveMapping = false\n"); } // create the ros wrapper for the planner's costmap... and initializer a pointer we'll use with the underlying map planner_costmap_ros_ = new costmap_2d::Costmap2DROS("global_costmap", tf_); planner_costmap_ros_->pause(); // initialize the global planner /* try { planner_ = bgp_loader_.createInstance(global_planner); planner_->initialize(bgp_loader_.getName(global_planner), planner_costmap_ros_); } catch (const pluginlib::PluginlibException &ex) { ROS_FATAL("Failed to create the %s planner, are you sure it is properly registered and that the containing library is built? Exception: %s", global_planner.c_str(), ex.what()); exit(1); } */ // create the ros wrapper for the controller's costmap... and initializer a pointer we'll use with the underlying map controller_costmap_ros_ = new costmap_2d::Costmap2DROS("local_costmap", tf_); controller_costmap_ros_->pause(); // create a local planner try { tc_ = blp_loader_.createInstance(local_planner); ROS_INFO("Created local_planner %s", local_planner.c_str()); tc_->initialize(blp_loader_.getName(local_planner), &tf_, controller_costmap_ros_); } catch (const pluginlib::PluginlibException &ex) { ROS_FATAL("Failed to create the %s planner, are you sure it is properly registered and that the containing library is built? Exception: %s", local_planner.c_str(), ex.what()); exit(1); } // Start actively updating costmaps based on sensor data planner_costmap_ros_->start(); controller_costmap_ros_->start(); // advertise a service for getting a plan make_plan_srv_ = private_nh.advertiseService("make_plan", &MoveBase::planService, this); // advertise a service for clearing the costmaps clear_costmaps_srv_ = private_nh.advertiseService("clear_costmaps", &MoveBase::clearCostmapsService, this); // if we shutdown our costmaps when we're deactivated... we'll do that now if (shutdown_costmaps_) { ROS_DEBUG_NAMED("move_base", "Stopping costmaps initially"); planner_costmap_ros_->stop(); controller_costmap_ros_->stop(); } // load any user specified recovery behaviors, and if that fails load the defaults if (!loadRecoveryBehaviors(private_nh)) { loadDefaultRecoveryBehaviors(); } // initially, we'll need to make a plan state_ = PLANNING; // we'll start executing recovery behaviors at the beginning of our list recovery_index_ = 0; foundObstacleFlag = 0; pursuitSpeed = 0.6; pubtargetSpeed = 0.6; recvScanFlag = 0; saveMappingMsg.data = 0; road_points_index = 0; stop_point_signal_msg.data = 0; sub_lasersScan = nh.subscribe("scan", 1, &MoveBase::callback_lasersScan, this); sub_saveMapping = nh.subscribe("savemapping", 1, &MoveBase::callback_saveMapping, this); hgglobalplannerpub = private_nh.advertise<move_base_msgs::hgpathplanner>("hgglobalplanner", 10); hglocationpub = private_nh.advertise<move_base_msgs::hglocation>("hglocation", 10); angle_pub = nh.advertise<geometry_msgs::Twist>("pursuitAngle", 1); vis_pub = nh.advertise<visualization_msgs::Marker>("visualization_marker", 10); stop_point_signal = private_nh.advertise<std_msgs::UInt8>("stop_signal",1); std::vector<std::string> mapFolders = { road_paths_savePath, stop_points_savePath}; loadAllMaps(mapFolders); roadPoints = road_paths[road_points_index]; stopPoints = stop_Points[0]; doplanner(); }分析一下这一段ROS代码的用处,我想添加一个接受其他几个节点话题发布的消息,对订阅的消息进行综合判断,进而指定导航路线。我该怎么做,事自己写一个类还是在这个MoseBase里面写
最新发布
07-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值