Python A*算法产生的噪声路径

Python A*算法产生的噪声路径,python,algorithm,path,noise,Python,Algorithm,Path,Noise,我正在为一个机器人项目(一种“自动”汽车,使用一些传感器和SVG文件生成的地图进行自我定位)做前端工作 为了使机器人可控,我们必须在其当前位置和目标之间生成路径。我使用了最简单的算法:A* 我得到了一些奇怪的结果:汽车倾向于以45°的倍数行驶,还有一个特别恼人的问题:一些生成的路径非常嘈杂 在这种情况下,请参见橙色矩形附近的噪波路径: 是否有办法避免这些奇怪/嘈杂的结果?最终,我们希望构建一条航向角度变化次数最少的路径。(汽车可以在不移动的情况下转弯,因此我们不需要任何路径“平滑”) 以下是我

我正在为一个机器人项目(一种“自动”汽车,使用一些传感器和SVG文件生成的地图进行自我定位)做前端工作

为了使机器人可控,我们必须在其当前位置和目标之间生成路径。我使用了最简单的算法:A*

我得到了一些奇怪的结果:汽车倾向于以45°的倍数行驶,还有一个特别恼人的问题:一些生成的路径非常嘈杂

在这种情况下,请参见橙色矩形附近的噪波路径:

是否有办法避免这些奇怪/嘈杂的结果?最终,我们希望构建一条航向角度变化次数最少的路径。(汽车可以在不移动的情况下转弯,因此我们不需要任何路径“平滑”)

以下是我的A*实现:

def search(self, begin, goal):
    if goal.x not in range(self.width) or goal.y not in range(self.height):
        print "Goal is out of bound"
        return []
    elif not self.grid[begin.y][begin.x].reachable:
        print "Beginning is unreachable"
        return []
    elif not self.grid[goal.y][goal.x].reachable:
        print "Goal is unreachable"
        return []
    else:

        self.cl = set()
        self.ol = set()

        curCell = begin
        self.ol.add(curCell)

        while len(self.ol) > 0:

            # We choose the cell in the open list having the minimum score as our current cell
            curCell = min(self.ol, key = lambda x : x.f)

            # We add the current cell to the closed list
            self.ol.remove(curCell)
            self.cl.add(curCell)

            # We check the cell's (reachable) neighbours :
            neighbours = self.neighbours(curCell)

            for cell in neighbours:
                # If the goal is a neighbour cell :
                if cell == goal:
                    cell.parent = curCell
                    self.path = cell.path()
                    self.display()
                    self.clear()
                    return self.path
                elif cell not in self.cl:
                    # We process the cells that are not in the closed list
                    # (processing <-> calculating the "F" score)
                    cell.process(curCell, goal)

                    self.ol.add(cell)
编辑以下是邻居方法(根据用户1884905的答案更新):


似乎这个实现是不正确的,因为它正在移动到离目标最近(如乌鸦飞)的被检查单元中还没有的单元,而它应该尝试并在找到障碍物时撤销路径,以便找到最佳障碍物。请在维基百科上看到这一点,以了解这个想法

这里的问题与如何计算
cell.f
有关,在进行演算时,可能您没有添加当前单元格的分数,通常A*应该采取步骤并生成类似的次优路径

由于空间被划分为离散的单元,当连续世界中的最佳路径(总是像乌鸦一样)正好位于两个离散的移动之间时,它会尽可能地用这条奇怪的路径来逼近它

我在这里看到两种方法:

  • 修正算法()为每个计算的单元格保留正确的距离值(在粘贴的单元格中,没有关于如何计算
    cell.f
    的信息)
  • 使用Djikstra,它应该很容易实现,只需对当前算法进行一些更改。事实上,A*只是它的一个优化版本

  • 在看不到您是如何实现
    邻居
    距离
    功能的情况下,我仍然可以很好地猜测出哪里出了问题:

    如果允许对角遍历,则不应使用曼哈顿距离。

    目标函数中的曼哈顿距离应该是到目标的最短距离的度量。(如果你可以斜穿过建筑砌块,那就不是了。)

    解决这一问题的最简单方法是将曼哈顿距离作为目标函数,并将邻居的定义更改为仅包括四个左右上下相邻的单元格

    编辑

    您的代码仍然存在问题。以下伪代码取自。我已经标记了重要的行,你必须检查。您必须确保i)如果找到更好的解决方案,您正在更新开放集中的节点;ii)您始终考虑以前行驶的距离

    function A*(start,goal)
         closedset := the empty set    // The set of nodes already evaluated.
         openset := {start}    // The set of tentative nodes to be evaluated, initially containing the start node
         came_from := the empty map    // The map of navigated nodes.
    
         g_score[start] := 0    // Cost from start along best known path.
         // Estimated total cost from start to goal through y.
         f_score[start] := g_score[start] + heuristic_cost_estimate(start, goal)
    
         while openset is not empty
             current := the node in openset having the lowest f_score[] value
             if current = goal
                 return reconstruct_path(came_from, goal)
    
             remove current from openset
             add current to closedset
             for each neighbor in neighbor_nodes(current)
                 // -------------------------------------------------------------------
                 // This is the way the tentative_g_score should be calculated.
                 // Do you include the current g_score in your calculation parent.distance(self) ?
                 tentative_g_score := g_score[current] + dist_between(current,neighbor)
                 // ------------------------------------------------------------------- 
                 if neighbor in closedset
                     if tentative_g_score >= g_score[neighbor]
                         continue
    
                 // -------------------------------------------------------------------
                 // You never make this comparrison
                 if neighbor not in openset or tentative_g_score < g_score[neighbor]
                 // -------------------------------------------------------------------
                     came_from[neighbor] := current
                     g_score[neighbor] := tentative_g_score
                     f_score[neighbor] := g_score[neighbor] + heuristic_cost_estimate(neighbor, goal)
                     if neighbor not in openset
                         add neighbor to openset
    
         return failure
    
     function reconstruct_path(came_from, current_node)
         if current_node in came_from
             p := reconstruct_path(came_from, came_from[current_node])
             return (p + current_node)
         else
             return current_node
    
    功能A*(开始、目标)
    closedset:=空集//已计算的节点集。
    openset:={start}//要计算的暂定节点集,最初包含起始节点
    来自:=空映射//已导航节点的映射。
    g_分数[start]:=0//从开始沿最著名路径计算的成本。
    //从开始到目标到y的估计总成本。
    f_分数[开始]:=g_分数[开始]+启发式成本估算(开始,目标)
    而openset不是空的
    当前:=openset中具有最低f_分数[]值的节点
    如果当前=目标
    返回路径(来自,目标)
    从openset中删除当前
    将当前值添加到closedset
    对于邻居_节点中的每个邻居(当前)
    // -------------------------------------------------------------------
    //这是计算暂定分数的方法。
    //您是否将当前的g_分数包括在计算父距离(self)中?
    暂定分数:=g分数[当前]+之间的距离(当前,邻居)
    // ------------------------------------------------------------------- 
    如果近邻在closedset中
    如果暂定评分>=g评分[邻居]
    持续
    // -------------------------------------------------------------------
    //你从来没有做过这样的比较
    如果邻居不在openset或暂定的_g_分数
    那是A*还是dijkstra?启发式部分在哪里?请查看调用
    启发式成本估算()函数的this。你的代码没有这样做,所以它没有找到最短路径。@GeraldSv:我使用的启发式方法是“曼哈顿距离”,它实际上没有显示在我发布的代码片段中(它在“进程”函数中)。我马上就发。谢谢你的洞察力!我在原来的问题中添加了函数计算cell.f(
    process
    method);但我看不出我到底做错了什么。你所说的“如果你遇到障碍,这条路就必须取消”是什么意思?此外,如果不同的算法能够提供更少的“角度”路径,我也愿意使用不同的算法
    def neighbours(self, cell, radius = 1, unreachables = False, diagonal = True):
        neighbours = set()
        for i in xrange(-radius, radius + 1):
            for j in xrange(-radius, radius + 1):
                x = cell.x + j
                y = cell.y + i
                if 0 <= y < self.height and 0 <= x < self.width and ( self.grid[y][x].reachable or unreachables ) and (diagonal or (x == cell.x or y == cell.y)) :
                    neighbours.add(self.grid[y][x])
    
        return neighbours
    
    def manhattanDistance(self, cell):
        return abs(self.x - cell.x) + abs(self.y - cell.y)
    
    def diagonalDistance(self, cell):
    
        xDist = abs(self.x - cell.x)
        yDist = abs(self.y - cell.y)
    
        if xDist > yDist:
            return 1.4 * yDist + (xDist - yDist)
        else:
            return 1.4 * xDist + (yDist - xDist)
    
    function A*(start,goal)
         closedset := the empty set    // The set of nodes already evaluated.
         openset := {start}    // The set of tentative nodes to be evaluated, initially containing the start node
         came_from := the empty map    // The map of navigated nodes.
    
         g_score[start] := 0    // Cost from start along best known path.
         // Estimated total cost from start to goal through y.
         f_score[start] := g_score[start] + heuristic_cost_estimate(start, goal)
    
         while openset is not empty
             current := the node in openset having the lowest f_score[] value
             if current = goal
                 return reconstruct_path(came_from, goal)
    
             remove current from openset
             add current to closedset
             for each neighbor in neighbor_nodes(current)
                 // -------------------------------------------------------------------
                 // This is the way the tentative_g_score should be calculated.
                 // Do you include the current g_score in your calculation parent.distance(self) ?
                 tentative_g_score := g_score[current] + dist_between(current,neighbor)
                 // ------------------------------------------------------------------- 
                 if neighbor in closedset
                     if tentative_g_score >= g_score[neighbor]
                         continue
    
                 // -------------------------------------------------------------------
                 // You never make this comparrison
                 if neighbor not in openset or tentative_g_score < g_score[neighbor]
                 // -------------------------------------------------------------------
                     came_from[neighbor] := current
                     g_score[neighbor] := tentative_g_score
                     f_score[neighbor] := g_score[neighbor] + heuristic_cost_estimate(neighbor, goal)
                     if neighbor not in openset
                         add neighbor to openset
    
         return failure
    
     function reconstruct_path(came_from, current_node)
         if current_node in came_from
             p := reconstruct_path(came_from, came_from[current_node])
             return (p + current_node)
         else
             return current_node