前言

ROS中编写自己全局路径规划插件实现固定路线规划(1)中实现了自定义全局路径插件的注册,本文进行具体的实现。

实现固定路线发布:
   1.确定固定路线
   2.固定路线发布
   3.全局路径插件接收路线并发布
其中,前两个步骤的实现可以控制机器人机器人按照我们期望的轨迹走一遍,然后将路径保存下来,之后再将路径发布,具体可参考读取机器人移动轨迹并在RVIZ界面中显示,这里主要介绍第三步的实现。


一、全局路径插件接收路线并发布

假定:固定路线发布的话题名为:/exist_path。
全局路径规划插件需要将路径点一个接一个的获取,并发布。

二、具体实现

1.global_path_planner.h

private:
   void receive_path_callback(const nav_msgs::Path::ConstPtr &msg);
   void reach_goal(const move_base_msgs::MoveBaseActionResult::ConstPtr &msg);
   void pub_path(std::vector<geometry_msgs::PoseStamped> &plan);

函数声明,receive_path_callback()路径接收函数;reach_goal()到达目标点;pub_path()路径发布

private:
        bool initialized_;  //初始化标志位
        std::string map_frame_;  //地图坐标系名
        double path_length_;   //路径长度
        int direction_;       //方向
        int start_index_;   //起始索引
        int goal_index_;   // 目标索引
        
        //ros
        ros::NodeHandle nh_;
        ros::Publisher sub_path_pub_;  
        ros::Subscriber path_sub_;
        ros::Subscriber res_sub_;
        nav_msgs::Path record_path_;   //存储路径
        geometry_msgs::PoseStamped goal_cache_;

成员变量,包含初始化标志、地图坐标系名称、路径长度、索引等。

inline double distance(const geometry_msgs::PoseStamped &from, geometry_msgs::PoseStamped &to) {
    double delta_x = from.pose.position.x - to.pose.position.x;
    double delta_y = from.pose.position.y - to.pose.position.y;
    return delta_x * delta_x + delta_y * delta_y;
}

功能函数: 两点间距计算

inline int positive_modulo(int i,int n){
    return ( i%n + n)% n;
}

功能函数:求模计算

inline int min_distance_index(const geometry_msgs::PoseStamped &from, nav_msgs::Path &path) {
    int index = -1;
    double min_value = std::numeric_limits<double>::max();
    double dis;
    for (size_t i = 0; i < path.poses.size(); i++) {
        dis = distance(from, path.poses.at(i));
        if (dis < min_value) {
            min_value = dis;
            index = static_cast<int>(i);
        }
    }
    return index;
}

起始时,机器人位置和路径上最近距离点的索引获取

inline int min_distance_index_inner(const geometry_msgs::PoseStamped &from,nav_msgs::Path path,size_t from_index,size_t to_index)
{
    int index = static_cast<int>(from_index);
    double min_value = std::numeric_limits<double>::max();
    double dis;
    for(int i = static_cast<int>(from_index);positive_modulo(i,static_cast<int>(path.poses.size()))!=to_index;i = i+direction_)
    {
        auto tmp_index = static_cast<size_t>(positive_modulo(i,static_cast<int>(path.poses.size())));
        dis = distance(from,path.poses.at(tmp_index));
        if(dis < min_value)
        {
            min_value = dis;
            index = static_cast<int>(tmp_index);
        }
    }
    return index;
}

机器人出发后,机器人当前位置和路径点最近距离索引

2.global_path_planner.cpp

    GlobalPathPlanner::GlobalPathPlanner():initialized_(false),start_index_(-1),goal_index_(-1) {
    }

构造函数,初始化列表对变量初始化。

void GlobalPathPlanner::initialize(std::string name, costmap_2d::Costmap2DROS *costmap_ros)
{
    if(!initialized_)
    {
    	//参数
        ros::NodeHandle private_nh("~/" +name);
        private_nh.param<std::string>("map_frame",map_frame_,std::string("map"));
        private_nh.param<double>("path_length",path_length_,0.5);
        private_nh.param<int>("direction",direction_,1);
        
        //函数定义
        sub_path_pub_ = private_nh.advertise<nav_msgs::Path>("sub_path",1,true);
        res_sub_ = nh_.subscribe<move_base_msgs::MoveBaseActionResult>("/move_base/result",1,&GlobalPathPlanner::reach_goal,this);
        path_sub_ = nh_.subscribe<nav_msgs::Path>("exist_path",10,&GlobalPathPlanner::receive_path_callback,this);
        initialized_ = true;
    }
}

初始化函数实现:定义变量的初始值,以及发布和接收函数定义

void GlobalPathPlanner::reach_goal(const move_base_msgs::MoveBaseActionResult::ConstPtr &msg)
{
    if(msg->status.status == 3)
    {
        ROS_INFO("goal reach !");
    }
}

达到终点函数接收

void GlobalPathPlanner::receive_path_callback(const nav_msgs::Path::ConstPtr &msg)
{
    ROS_INFO("Recv Path ~");
    record_path_ = *msg;
}

接收固定路径信息,保存在变量record_path_中,用于后期发布。

void GlobalPathPlanner::pub_path(std::vector<geometry_msgs::PoseStamped> &plan)
{
    nav_msgs::Path sub_path;
    sub_path.header.frame_id= map_frame_;
    sub_path.header.stamp = ros::Time::now();
    sub_path.poses = plan;
    sub_path_pub_.publish(sub_path);
}

发布路径函数实现

    bool GlobalPathPlanner::makePlan(const geometry_msgs::PoseStamped &start,
                      const geometry_msgs::PoseStamped &goal, std::vector<geometry_msgs::PoseStamped> &plan)
    {
    	
    }

路径规划make_plan()函数实现

三、结果

放张导航图吧~~~
注意:这里仅仅是全局路径插件的实现,并没有运动控制的实现。


总结

本文实现了简单自定义固定路线的发布实现,用于机器人后期沿着固定线路进行运动。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐