Navigation中A*算法源码解释

A*算法原理

A*算法原理在之前的文章中也有提到,这次主要就是和Navigation中对应起来。
A*算法原理

A*源码

示例图
在这里插入图片描述nx_ = 6, ny_ = 6;
其中A为起始点,(1,2)。B为goal_i 为(4,4)。

calculatePotential 函数是对堆中F值最小的索引值取出,然后进行下一次的更新。

其中toIndex函数返回值为 start_x + nx_*start_y; 即索引

	queue_.clear(); //首先将堆清空
	//x,y点是全部数据的第几个,示例中即13。
    int start_i = toIndex(start_x, start_y);  
    //首先将start点以及其代价压入,即(13,0) 
    queue_.push_back(Index(start_i, 0));
	//potential,填充个数是ns_,值是POT_HIGH很大的一个值1e10.
    std::fill(potential, potential + ns_, POT_HIGH);  
    potential[start_i] = 0;//将起始点的代价设置为0
	//得到目标点的index即28。
    int goal_i = toIndex(end_x, end_y);
    int cycle = 0; //一个计数器,在dadu某个值就不再计算potentail

接下来就是计算potential,然后根据代价值大小进行排序。

	while (queue_.size() > 0 && cycle < cycles) {
        //将最小的代价的index取出给i,并且判断是否为目标点,若是return true。
        Index top = queue_[0];
        //进行小顶堆的排序。即有小到大排序。然后弹出并且删除第一个
        //对应于将这个点从open_list拿到close_list
        std::pop_heap(queue_.begin(), queue_.end(), greater1()); 
        queue_.pop_back();

        int i = top.i; //
        if (i == goal_i) //已经到达目标点
            return true;

        //只检测上下左右四个点.
        add(costs, potential, potential[i], i + 1, end_x, end_y);
        add(costs, potential, potential[i], i - 1, end_x, end_y);
        add(costs, potential, potential[i], i + nx_, end_x, end_y);
        add(costs, potential, potential[i], i - nx_, end_x, end_y);

        cycle++;
    }

add函数中首先是三个if的判断原因在注释中。

	//溢出
	if (next_i < 0 || next_i >= ns_) 
        return;
	// 其实只要不是POT_HIGH就行,表示之前已经检索过这个栅格
    if (potential[next_i] < POT_HIGH) 
        return;
	//有障碍或者是无信息的点
    if(costs[next_i]>=lethal_cost_ && !(unknown_ && costs[next_i]==costmap_2d::NO_INFORMATION)) 
        return;

接下来是计算potential值

 potential[next_i] = p_calc_->calculatePotential(potential, costs[next_i] + neutral_cost_, next_i, prev_potential);

calculate_potential函数如下:

		virtual float calculatePotential(float* potential, unsigned char cost, int n, float prev_potential=-1){
            if(prev_potential < 0){
                // get min of neighbors
                float min_h = std::min( potential[n - 1], potential[n + 1] ),
                      min_v = std::min( potential[n - nx_], potential[n + nx_]);
                prev_potential = std::min(min_h, min_v);
            }

            return prev_potential + cost;
        }

在不小于0的时候,返回的是prev_potential + cost,以start_cost为例,最开始给其赋值是0,因此返回就是cost,可以理解为到下一个栅格的距离,或者是分辨率。因此potential就是A*算法中 F = G + H中的G值。
在计算完potential后开始计算H值,即distance,利用的就是移动多少格子,只能上下左右移动

	// 得到在栅格地图中的(x,y)
	int x = next_i % nx_, y = next_i / nx_;  
    // F = G+H 中的H
    float distance = abs(end_x - x) + abs(end_y - y);  

还是以刚开始的图为例,A的i值是13,则add中的next_i分别是12,14,7,19。以14为例,则x = 2, y = 2。而B为(4,4)。因此distance = 2+2 =4; 由于这只是格子的个数,还有乘上每个格子的真实距离或者是分辨率,所以最后的H = distance *neutral_cost_。因此最后的F = potential[next_i] + distance *neutral_cost_

//将next_i以及对应的cost压入
queue_.push_back(Index(next_i, potential[next_i] + distance * neutral_cost_)); 

最后再进行排序,小顶堆。

 std::push_heap(queue_.begin(), queue_.end(), greater1()); 
 //堆排序,生成小顶堆。(数据结构还不熟悉)

在calculatepotential中对start_i周围的四个点进行add之后,进入下一次循环,这次循环的起始点是上一个点中四个点周围中最小的点。
然后依次进行,直到搜索到goal_i点。此时的potential赋值情况如下,阴影表示已经赋新值,空白是之前最开始的POT_HIGH。(以A的下一个点是14算,其实19也是,但是只弹出一个最小值的Index)。1/4表示的是potential为1,distance为4。

在这里插入图片描述

加入getPath函数

此时A*算法就完成了。
在得到路径方面,假如采用的grid_path。(gradient的插补还不太懂)则其就是检测goal_i周围8个点中最小的Potential。然后将此点加入Path,并且开始下一次计算。因此最后得到的轨迹如下图:
在这里插入图片描述

参考博客

ROS navigation planner–GlobalPlanner

  • 7
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
navigation包可以使用A*算法进行路径规划。A*算法是一种启发式搜索算法,其目的是寻找从起点到终点的最短路径。它需要一个启发式函数来估计每个状态到目标状态的代价,以指导搜索过程。 在navigation,使用A*算法进行路径规划的主要步骤如下: 1. 定义地图和起点终点:使用nav_msgs/OccupancyGrid消息类型表示地图,其包含了地图的栅格信息和障碍物信息。起点和终点可以使用geometry_msgs/PoseStamped消息类型表示。 2. 定义启发式函数:启发式函数用于估计每个状态到目标状态的代价,可以根据实际情况灵活设置。在navigation,可以使用默认的启发式函数,即欧几里得距离。也可以自定义启发式函数,例如曼哈顿距离、切比雪夫距离等。 3. 定义A*算法对象:使用nav_core::BaseGlobalPlanner接口定义一个A*算法对象。该接口提供了一系列方法,包括设置地图、设置起点和终点、进行路径规划等。可以根据需要实现自己的A*算法对象。 4. 进行路径规划:初始化A*算法对象后,调用makePlan()方法进行路径规划。该方法返回一个nav_msgs/Path消息类型,其包含起点到终点的路径信息。如果路径规划失败,返回一个空的路径。 在使用A*算法进行路径规划时,需要注意地图和启发式函数的设置,以及算法对象的实现和使用。如果遇到问题,可以参考ROS官方文档或者ROS论坛上的相关讨论。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值