当前位置:   article > 正文

室外低速自动导航车的设计(8)——A*算法在ROS上的移植_ros中a*1算法的总体思路

ros中a*1算法的总体思路

A*算法是一种Greedy算法,ROS中的navigation导航包中的global_planner中就能找到。

今天,我们从头入手,自己移植并完成关于A*算法在ROS上的移植和实现。

首先来说一下我们最后想实现的目的:

我们首先画一个200*200像素的“交通路段”,如下图,将其保存为BMP图片文件(当然,大家可以自己画,白色为道路,黑色为障碍)。

 

现在,我们以图片的最中央为起点,实现点击任意一个白色位置,即道路上任意一点,让程序自动规划出路线,并显示出来(类似下图)。

 

 

在开始我们的算法之前,首先感谢网友[一路向北]的开源A*算法,他MFC界面的源代码网址如下:

              点击打开链接

我移植好的代码地址如下:

 

A*算法的具体实现我们并不关心,我们的目的提取它的核心算法,然后加入ROS相关的接口,并进行封装。

首先,算法移植前,我们一定要关注A*的核心类:

先看“一路向北”的原始代码,在这里由于源代码太长,我只列出封装的类:

 

  1. class AStartFindPath
  2. {
  3. public:
  4. AStartFindPath();
  5. virtual ~AStartFindPath(){};
  6. int GetPos(int &x,int &y);
  7. void FindDestinnation(OpenList* open,CloseList* close);
  8. OpenList* FindMinInOpen(OpenList* open);
  9. bool Insert2OpenList(OpenList* , int x, int y);
  10. bool IsInOpenList(OpenList*, int x, int y);
  11. bool IsInCloseList(OpenList*, int x, int y);
  12. void IsChangeParent(OpenList*, int x, int y);
  13. bool IsAviable(OpenList* , int x, int y);
  14. unsigned int DistanceManhattan(int d_x, int d_y, int x, int y);
  15. unsigned int steps;
  16. int startpoint_x;
  17. int startpoint_y;
  18. int endpoint_x;
  19. int endpoint_y;
  20. int m_height,m_width;
  21. double m_resolution;
  22. //Lists
  23. OpenList* openlist;
  24. CloseList* closelist ;
  25. int x,y,des_x,des_y;
  26. char Thrs;
  27. };


可以看到,这个AStarFindPath类有很多函数,但最主要的还是这个:

 

void FindDestinnation(OpenList* open,CloseList* close);

我们针对这个类做移植。

首先,我们可以新建一个接口类,比如AStarInterface,一端调用AStarFindPath的函数,另一端连接ROS的标准协议。

我们也可以采用更为简单的方法,就是直接在AStarFindPath中添加ROS相关代码:

下面的代码为我修改后的代码:大家对照之前的代码,看加了一些什么内容。

 

  1. class AStartFindPath
  2. {
  3. public:
  4. ros::NodeHandle n;
  5. Node **m_node;
  6. AStartFindPath();
  7. virtual ~AStartFindPath(){};
  8. int GetPos(int &x,int &y);
  9. void FindDestinnation(OpenList* open,CloseList* close);
  10. OpenList* FindMinInOpen(OpenList* open);
  11. bool Insert2OpenList(OpenList* , int x, int y);
  12. bool IsInOpenList(OpenList*, int x, int y);
  13. bool IsInCloseList(OpenList*, int x, int y);
  14. void IsChangeParent(OpenList*, int x, int y);
  15. bool IsAviable(OpenList* , int x, int y);
  16. unsigned int DistanceManhattan(int d_x, int d_y, int x, int y);
  17. /*以下是加入的ROS接口代码*/
  18. void map_Callback(const nav_msgs::OccupancyGrid::ConstPtr& msg);
  19. void start_Callback(const geometry_msgs::PoseStamped::ConstPtr& msg);
  20. void end_Callback(const geometry_msgs::PoseStamped::ConstPtr& msg);
  21. ros::Subscriber map_sub;
  22. ros::Subscriber start_sub;
  23. ros::Subscriber end_sub;
  24. ros::Publisher nav_plan;
  25. //TF Scalar Listener
  26. tf::TransformListener AGV_transform_listener;
  27. tf::StampedTransform AGV_transform;
  28. private:
  29. unsigned int steps;
  30. int startpoint_x;
  31. int startpoint_y;
  32. int endpoint_x;
  33. int endpoint_y;
  34. int m_height,m_width;
  35. double m_resolution;
  36. //Lists
  37. OpenList* openlist;
  38. CloseList* closelist ;
  39. int x,y,des_x,des_y;
  40. char Thrs;
  41. ros::Publisher map_pub;
  42. };

我在一个部分前加了注释,表明那个类是我移植后加入的ROS相关,其中添加了3个函数:

void map_Callback(const nav_msgs::OccupancyGrid::ConstPtr& msg);
void start_Callback(const geometry_msgs::PoseStamped::ConstPtr& msg);
void end_Callback(const geometry_msgs::PoseStamped::ConstPtr& msg);

 

这种类型的函数通常被成为回调函数,回调函数是ROS收信息的接口;比如map_Callback就是收地图信息的函数,start_Callback是收到用户目标点激发的函数等等。

另外,在类的末尾,我加入了一个这个东西:ros::Publisher map_pub;这个Publisher叫消息发送器,消息发送器是ROS发信息的接口。现在我们在原来的类中加入了ROS的消息收发接口。

既然我们定义好了接口,那就要对其实现。首先是地图的收取接口

 

  1. void AStartFindPath::map_Callback(const nav_msgs::OccupancyGrid::ConstPtr& msg)
  2. {
  3. nav_msgs::OccupancyGrid m_map;
  4. m_height=msg->info.height;
  5. m_width=msg->info.width;
  6. m_resolution=msg->info.resolution;
  7. m_map.info.height=msg->info.height;
  8. m_map.info.width=msg->info.width;
  9. m_map.info.resolution=msg->info.resolution;
  10. if(m_node!=NULL)
  11. {
  12. for(int i=0;i<m_height;i++)delete [] m_node[i];
  13. delete [] m_node;
  14. m_node=NULL;
  15. }
  16. m_node=new Node*[m_height];
  17. for(int i=0;i<m_height ;i++)
  18. {
  19. m_node[i]=new Node[m_width];
  20. for(int j=0;j<m_width;j++)
  21. {
  22. m_node[i][j].location_x = j;
  23. m_node[i][j].location_y =i;
  24. m_node[i][j].parent = NULL;
  25. m_node[i][j].gray_val=msg->data[(i)*m_width+j];
  26. if(msg->data[(i)*m_width+j]!=0)m_node[i][j].flag = WALL;
  27. else m_node[i][j].flag = VIABLE;
  28. }
  29. }
  30. m_map.data.resize(m_height*m_width);
  31. for(int i=0;i<m_height;i++)
  32. for(int j=0;j<m_width;j++)
  33. m_map.data[i*m_width +j]=m_node[i][j].gray_val;
  34. map_pub.publish(m_map);
  35. printf("收到地图:长:%d Pixels----宽 %d Pixels\n",m_height,m_width);
  36. }

 

      这个代码后边会再给大家讲,总之,申明了一个接口,一定要实现就可以了。

按照上述方案,把多个接口都完成,就可以参考我的另一篇文章点击打开链接对程序进行编译。

我完成的代码可以从下面这个网址下载:

点击打开链接

把代码复制到工作空间内可以直接编译,如果编译过程中有问题,可以在评论区留言。

关于代码的使用大家可以自己根据代码思考,后续我会再发布相关技术博客。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/339127
推荐阅读
相关标签
  

闽ICP备14008679号