(6-3-02)D* Lite 算法:基于 D* Lite的路径规划器(2) 实现路径规划算法

6.3.2  实现路径规划算法

文件d_star_lite.py实现了D* Lite算法,用于路径规划,适用于动态环境中的自动驾驶场景。首先读取地图图像并进行网格化处理,将地图分成若干小网格。每个网格对应一个节点对象,并标识是否为障碍物。起始节点和目标节点初始化后,通过优先队列和一系列更新规则计算出最短路径。当有新障碍物出现时,算法会实时更新路径,保证路径的动态最优性。最终,计算出的路径在地图上显示出来,适用于自动驾驶中对障碍物和路径的实时更新与避让。文件d_star_lite.py的具体实现流程如下所示。

(1)定义类Node,代表路径规划中的一个节点。每个节点具有以下属性:位置pos,到起点的估计成本g,从起点到节点的最小成本rhs,节点的键值k,指向前驱节点的指针p,以及一个标志位is_obs表示是否为障碍物。该类用于在路径规划算法中存储和处理节点的信息。

class Node(object):
    def __init__(self, pos):
        self.pos = pos
        self.g = float('inf')
        self.rhs = float('inf')
        self.k = [float('inf'), float('inf')]
        self.p = None
        self.is_obs = False

(2)定义类D_STAR_LITE的构造方法 __init__,该方法初始化了D* Lite算法的方向列表 self.directions,表示八个可能的移动方向。接着,它调用了 self.MapGridding 方法,将给定的地图路径 map_path、起始点 qstart、目标点 qgoal 和网格大小 grid_size 进行网格化处理,准备路径规划所需的数据结构。

class D_STAR_LITE(object):
    def __init__(self, map_path, qstart, qgoal, grid_size):
        self.directions = [[-1, -1], [-1, 0], [-1, 1],
                           [0, -1], [0, 1],
                           [1, -1], [1, 0], [1, 1]]
        self.MapGridding(map_path, qstart, qgoal, grid_size)
        return

(3)定义方法MapGridding,用于将输入的地图图像进行网格化处理。该方法首先读取并转换地图图像为灰度图,然后通过二值化处理得到二值图像。接着,计算地图的网格尺寸,将地图分成若干小网格,并为每个网格初始化一个 Node 对象,存储在二维数组 self.S 中。起始点和目标点也在此过程中被初始化。随后,该方法检查每个网格是否包含障碍物,并绘制网格线将地图可视化显示出来。

    def MapGridding(self, map_path, qstart, qgoal, grid_size, color=(0, 0, 0)):
        '''
        grid map 网格化地图
        '''
        self.src_map = cv2.imread(map_path)
        self.map = cv2.cvtColor(self.src_map, cv2.COLOR_BGR2GRAY)
        _, self.map = cv2.threshold(
            self.map, 0, 255, cv2.THRESH_BINARY_INV)

        self.map_shape = np.shape(self.map)
        self.grid_size = grid_size
        self.rows = int(self.map_shape[0] / grid_size)
        self.cols = int(self.map_shape[1] / grid_size)
        # 地图栅格, 初始化地图所有路径点
        self.S = []
        for row in range(self.rows):
            items_rows = []
            for col in range(self.cols):
                items_rows.append(Node([row, col]))
            self.S.append(items_rows)

        self.qstart = self.S[int(qstart[0] / grid_size)][int(qstart[1] / grid_size)]
        self.qgoal = self.S[int(qgoal[0] / grid_size)][int(qgoal[1] / grid_size)]
        for row in range(self.rows):
            for col in range(self.cols):
                if self.IsObstacle(self.S[row][col]):
                    self.S[row][col].is_obs = True
        # 绘制地图栅格
        for row in range(self.rows + 1):
            pt1 = (0, int(row * self.grid_size))
            pt2 = (int(self.cols * self.grid_size), int(row * self.grid_size))
            cv2.line(self.src_map, pt1, pt2, color)
            cv2.imshow('D_STAR_LITE', self.src_map)
            cv2.waitKey(2)

        for col in range(self.cols + 1):
            pt1 = (int(col * self.grid_size), 0)
            pt2 = (int(col * self.grid_size), int(self.rows * self.grid_size))
            cv2.line(self.src_map, pt1, pt2, color)
            cv2.imshow('D_STAR_LITE', self.src_map)
            cv2.waitKey(2)

        cv2.imshow('D_STAR_LITE', self.src_map)
        cv2.waitKey(50)
        return

(4)定义方法IsObstacle,用于判断节点 s 所在的网格是否有障碍物。该方法通过计算节点所在网格区域的像素值总和,来确定该区域是否存在障碍物。如果区域内的像素值总和不为零,说明有障碍物,返回 True;否则返回 False。该判断基于地图图像的反二值化处理。

    def CollisionFree(self, s1, s2):
        '''
        检查以s1->s2是否可行,必要时增加s1,s2之间的栅格检查
        '''
        half_grid_size = int(self.grid_size / 2)
        row_start = int((s1.pos[0] + s2.pos[0]) * self.grid_size / 2)
        col_start = int((s1.pos[1] + s2.pos[1]) * self.grid_size / 2)
        area = self.map[row_start: row_start +
                        self.grid_size, col_start: col_start + self.grid_size]
        if np.sum(area):
            return False
        return s1.is_obs == False and s2.is_obs == False

(5)定义方法CollisionFree,用于检查从节点 s1 到节点 s2 的路径是否无障碍物。该方法计算两节点之间区域的像素值总和,如果总和不为零,说明存在障碍物,返回 False。此外,它还检查 s1 和 s2 节点本身是否为障碍物。如果两节点之间区域无障碍物且两节点本身不是障碍物,则返回 True。

    def CollisionFree(self, s1, s2):
        '''
        检查以s1->s2是否可行,必要时增加s1,s2之间的栅格检查
        '''
        half_grid_size = int(self.grid_size / 2)
        row_start = int((s1.pos[0] + s2.pos[0]) * self.grid_size / 2)
        col_start = int((s1.pos[1] + s2.pos[1]) * self.grid_size / 2)
        area = self.map[row_start: row_start +
                        self.grid_size, col_start: col_start + self.grid_size]
        if np.sum(area):
            return False
        return s1.is_obs == False and s2.is_obs == False

(6)下面的代码定义了三个方法,用于计算两点之间的不同距离度量:

  1. ChebyshevDistance:计算并返回两点之间的切比雪夫距离,即网格中两点在水平或垂直方向上的最大距离,乘以网格大小。
  2. EuclideanDistance:计算并返回两点之间的欧几里得距离,即两点间直线距离的整数值,乘以网格大小。
  3. DiagonalDistance:计算并返回两点之间的对角距离,即两点水平和垂直方向距离之和,加上对角移动的额外代价,乘以网格大小。
    def ChebyshevDistance(self, p1, p2):
        return self.grid_size * max(abs(p1[0] - p2[0]), abs(p1[1] - p2[1]))

    def EuclideanDistance(self, p1, p2):
        return self.grid_size * int(math.sqrt((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2))

    def DiagonalDistance(self, p1, p2):
        dx = abs(p1[0] - p2[0])
        dy = abs(p1[1] - p2[1])
        return self.grid_size * (dx + dy) + int((math.sqrt(2) - 2) * self.grid_size) * min(dx, dy)

(7)定义方法Cost,用于估计两个节点 s1 和 s2 之间的移动代价。首先,调用 CollisionFree 方法检查从 s1 到 s2 的路径是否无障碍物。如果路径无障碍,则返回两节点之间的对角距离(使用 DiagonalDistance 计算);如果路径有障碍,则返回无穷大(表示不可达)。

    def Cost(self, s1, s2):
        '''
        节点 s1 和 s2 估计距离
        '''
        if self.CollisionFree(s1, s2):
            return self.DiagonalDistance(s1.pos, s2.pos)
        else:
            return float('inf')

(8)下面的代码定义了三个方法,用于路径规划中的关键值计算和优先队列操作:

  1. HScore:计算并返回节点 s 到起始点的估计距离,使用对角距离(DiagonalDistance)度量。
  2. CalculateKey:计算并返回节点 s 的键值。键值是一个包含两个元素的列表,其中第一个元素是 s 的估计成本 g 和最小成本 rhs 中较小者与 HScore(s) 之和,第二个元素是较小的 g 或 rhs 值。这个键值用于优先队列中的排序。
  3. TopKey:返回优先队列 U 中键值最小的键值,即队列中的顶键值,用于确定当前最优节点。
    def HScore(self, s):
        '''
        节点 s 到起始点的估计距离
        '''
        return self.DiagonalDistance(self.qstart.pos, s.pos)

    def CalculateKey(self, s):
        '''
        计算节点 Key值
        '''
        key2 = min(s.g, s.rhs)
        return [key2 + self.HScore(s), key2]

    def TopKey(self):
        '''
        返回有限队列 topkey
        '''
        return min([X.k for X in self.U])

(9)定义方法Successors,用于寻找与节点 s 相邻且无障碍物的节点列表。首先遍历预先定义的八个方向(包括水平、垂直和对角线方向),计算每个方向上的相邻节点位置。然后检查这些相邻节点是否在地图范围内,并且是否没有障碍物。符合条件的相邻节点会被添加到 succ_list 列表中,并最终返回。这个方法在路径规划中用于获取当前节点 s 的可行邻接节点列表。

    def Successors(self, s):
        '''
        8 邻接节点:与 s 可以联通(s和succ均无障碍物)
        '''
        succ_list = []
        for direction in self.directions:
            row = s.pos[0] + direction[0]
            if row < 0 or row >= self.rows:
                continue
            col = s.pos[1] + direction[1]
            if col < 0 or col >= self.cols:
                continue
            neighbor = self.S[row][col]
            if neighbor.is_obs == False:
                succ_list.append(neighbor)
        return succ_list

(10)定义方法Predessors,它实际上是 Successors 方法的一个别名。该方法的功能是返回与给定节点 s 相邻且无障碍物的节点列表,与 Successors 方法完全一致。在某些路径规划算法中,包括D* Lite算法,节点的前驱(predecessor)与后继(successor)具有相同的意义,因此这里使用 Predessors 方法来直接调用 Successors 方法以简化代码逻辑。

    def Predessors(self, s):
        return self.Successors(s)

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
D*lite算法是一种用于路径规划的增量搜索算法,可以用于实现无碰撞的多AGV路径规划。其主要思路是从起点开始,通过不断更新地图信息和搜索路径,逐步到达终点。 具体来说,可以采用以下步骤来实现无碰撞的多AGV路径规划算法: 1. 确定地图信息:首先需要确定地图信息,包括起点、终点、障碍物等,以便进行路径规划。 2. 初始化路径:通过D*lite算法计算出第一个AGV的路径,并将其作为初始路径。 3. 检测路径冲突:对于后续的AGV,需要检测其路径是否与前面AGV的路径发生冲突,如果发生冲突,则通过修改路径来避免碰撞。 4. 更新地图信息:通过实时监测AGV的位置信息,更新地图信息,以便于后续路径规划的计算。 5. 重新规划路径:对于需要修改路径的AGV,通过重新进行D*lite算法的计算,产生新的路径。 6. 合并路径:将所有AGV的路径合并起来,并检查是否有冲突,如果有冲突,则返回第3步,重新进行路径修改,直到所有路径均无冲突。 7. 重复执行:在实际应用中,需要不断地对地图信息进行更新和路径规划,以适应不同的环境变化。 通过以上步骤,可以实现无碰撞的多AGV路径规划算法,其中D*lite算法的增量搜索思想可以有效地避免路径重新规划时的计算复杂度过高问题,同时也能够更好地适应实际环境的变化,提高路径规划的实时性和可靠性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农三叔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值