自动驾驶算法(二):A*算法讲解与代码实现

news2024/12/28 19:03:40

目录

1 A* 算法提出的动机

2 A*算法代码详解

3 A*算法完整代码


1 A* 算法提出的动机

        减少收录的珊格树目,增加搜索速度。在Dijkstra算法中,我们考虑收录栅格时我们考虑的是到起点的距离,我们会考虑收录距离起点较近的珊格进行收录。在A*算法,我们增加启发式函数,加快其导向终点的速度。

        举个例子:

        图中两个红色光晕节点,下面的点距离起点较近(蓝色的),所以Dijkstra会选择下面的节点进行收录。我们在这基础上增加这两个节点到终点的距离。我们发现上面节点到终点的距离会更加小,我们就会收录上面的节点。从而在收录节点的时候就会更加快速的导向终点。

        看一下算法对比:

A*
Dijkstra

        算法和Dijkstra相比仅多了一个启发项,因此代码架构只需要更改一点即可:

        当然,启发项不是随便加的,我们需要保证算法还是找到的最优路径。我们需要保证h(n) <= *h(n),这里*h(n)是最优解。

        比如我们从1-->3这个节点要寻找一条路径:

        我们回顾一下open list和close list:上方的h表示预计到终点的距离。(假设的...)

openlist:      2(1+6)      3(5+0)
closelist:     1(0)

        那么我会选择收录三号点。我们认为最优路径是1-->3而不是1-->2-->3我们就不能保证最优性了。但是1-->3的扩展点更加少,一部分程度上来说增加了速度。(有好有坏)

2 A*算法代码详解

        相比较于Dijkstra算法就增加了一个启发函数:

            # 选择扩展点 f(n) = g(n) + h(n)
            c_id = min(
                open_set,
                key=lambda o: open_set[o].cost + self.calc_heuristic(goal_node,
                                                                     open_set[
                                                                         o]))

        我们看一下这个启发函数:

    def calc_heuristic(n1, n2):
        w = 1.0  # weight of heuristic
        d = w * math.hypot(n1.x - n2.x, n1.y - n2.y)
        return d

        先来看函数调用,goal_node是目标点。

        d = w * math.hypot(n1.x - n2.x, n1.y - n2.y):使用欧几里得距离公式计算了两个节点在二维平面上的距离,其中n1.xn1.y分别表示节点n1的x坐标和y坐标,n2.xn2.y分别表示节点n2的x坐标和y坐标。将得到的距离乘以权重w得到启发式值d。也就是计算出了该节点到终点的距离作为启发项。其余与Dijkstra算法一致,不再赘述。

3 A*算法完整代码

"""

A* grid planning

author: Atsushi Sakai(@Atsushi_twi)
        Nikos Kanargias (nkana@tee.gr)

See Wikipedia article (https://en.wikipedia.org/wiki/A*_search_algorithm)

"""

import math

import matplotlib.pyplot as plt

show_animation = True


class AStarPlanner:

    def __init__(self, ox, oy, resolution, rr):
        """
        Initialize grid map for a star planning

        ox: x position list of Obstacles [m]
        oy: y position list of Obstacles [m]
        resolution: grid resolution [m]
        rr: robot radius[m]
        """

        self.resolution = resolution
        self.rr = rr
        self.min_x, self.min_y = 0, 0
        self.max_x, self.max_y = 0, 0
        self.obstacle_map = None
        self.x_width, self.y_width = 0, 0
        self.motion = self.get_motion_model()
        self.calc_obstacle_map(ox, oy)

    class Node:
        def __init__(self, x, y, cost, parent_index):
            self.x = x  # index of grid
            self.y = y  # index of grid
            self.cost = cost
            self.parent_index = parent_index

        def __str__(self):
            return str(self.x) + "," + str(self.y) + "," + str(
                self.cost) + "," + str(self.parent_index)

    def planning(self, sx, sy, gx, gy):
        """
        A star path search

        input:
            s_x: start x position [m]
            s_y: start y position [m]
            gx: goal x position [m]
            gy: goal y position [m]

        output:
            rx: x position list of the final path
            ry: y position list of the final path
        """

        start_node = self.Node(self.calc_xy_index(sx, self.min_x),
                               self.calc_xy_index(sy, self.min_y), 0.0, -1)
        goal_node = self.Node(self.calc_xy_index(gx, self.min_x),
                              self.calc_xy_index(gy, self.min_y), 0.0, -1)

        open_set, closed_set = dict(), dict()
        open_set[self.calc_grid_index(start_node)] = start_node

        while 1:
            if len(open_set) == 0:
                print("Open set is empty..")
                break

            # 选择扩展点 f(n) = g(n) + h(n)
            c_id = min(
                open_set,
                key=lambda o: open_set[o].cost + self.calc_heuristic(goal_node,
                                                                     open_set[
                                                                         o]))
            current = open_set[c_id]

            # show graph
            if show_animation:  # pragma: no cover
                plt.plot(self.calc_grid_position(current.x, self.min_x),
                         self.calc_grid_position(current.y, self.min_y), "xc")
                # for stopping simulation with the esc key.
                plt.gcf().canvas.mpl_connect('key_release_event',
                                             lambda event: [exit(
                                                 0) if event.key == 'escape' else None])
                if len(closed_set.keys()) % 10 == 0:
                    plt.pause(0.001)

            if current.x == goal_node.x and current.y == goal_node.y:
                print("Find goal")
                goal_node.parent_index = current.parent_index
                goal_node.cost = current.cost
                break

            # Remove the item from the open set
            del open_set[c_id]

            # Add it to the closed set
            closed_set[c_id] = current

            # expand_grid search grid based on motion model
            for i, _ in enumerate(self.motion):
                node = self.Node(current.x + self.motion[i][0],
                                 current.y + self.motion[i][1],
                                 current.cost + self.motion[i][2], c_id)
                n_id = self.calc_grid_index(node)

                # If the node is not safe, do nothing
                if not self.verify_node(node):
                    continue

                if n_id in closed_set:
                    continue

                if n_id not in open_set:
                    open_set[n_id] = node  # discovered a new node
                else:
                    if open_set[n_id].cost > node.cost:
                        # This path is the best until now. record it
                        open_set[n_id] = node

        rx, ry = self.calc_final_path(goal_node, closed_set)

        return rx, ry

    def calc_final_path(self, goal_node, closed_set):
        # generate final course
        rx, ry = [self.calc_grid_position(goal_node.x, self.min_x)], [
            self.calc_grid_position(goal_node.y, self.min_y)]
        parent_index = goal_node.parent_index
        while parent_index != -1:
            n = closed_set[parent_index]
            rx.append(self.calc_grid_position(n.x, self.min_x))
            ry.append(self.calc_grid_position(n.y, self.min_y))
            parent_index = n.parent_index

        return rx, ry

    @staticmethod
    def calc_heuristic(n1, n2):
        w = 1.0  # weight of heuristic
        d = w * math.hypot(n1.x - n2.x, n1.y - n2.y)
        return d

    def calc_grid_position(self, index, min_position):
        """
        calc grid position

        :param index:
        :param min_position:
        :return:
        """
        pos = index * self.resolution + min_position
        return pos

    def calc_xy_index(self, position, min_pos):
        return round((position - min_pos) / self.resolution)

    def calc_grid_index(self, node):
        return node.y * self.x_width + node.x

    def verify_node(self, node):
        px = self.calc_grid_position(node.x, self.min_x)
        py = self.calc_grid_position(node.y, self.min_y)

        if px < self.min_x:
            return False
        elif py < self.min_y:
            return False
        elif px >= self.max_x:
            return False
        elif py >= self.max_y:
            return False

        # collision check
        if self.obstacle_map[node.x][node.y]:
            return False

        return True

    def calc_obstacle_map(self, ox, oy):

        self.min_x = round(min(ox))
        self.min_y = round(min(oy))
        self.max_x = round(max(ox))
        self.max_y = round(max(oy))
        print("min_x:", self.min_x)
        print("min_y:", self.min_y)
        print("max_x:", self.max_x)
        print("max_y:", self.max_y)

        self.x_width = round((self.max_x - self.min_x) / self.resolution)
        self.y_width = round((self.max_y - self.min_y) / self.resolution)
        print("x_width:", self.x_width)
        print("y_width:", self.y_width)

        # obstacle map generation
        self.obstacle_map = [[False for _ in range(self.y_width)]
                             for _ in range(self.x_width)]
        for ix in range(self.x_width):
            x = self.calc_grid_position(ix, self.min_x)
            for iy in range(self.y_width):
                y = self.calc_grid_position(iy, self.min_y)
                for iox, ioy in zip(ox, oy):
                    d = math.hypot(iox - x, ioy - y)
                    if d <= self.rr:
                        self.obstacle_map[ix][iy] = True
                        break

    @staticmethod
    def get_motion_model():
        # dx, dy, cost
        motion = [[1, 0, 1],
                  [0, 1, 1],
                  [-1, 0, 1],
                  [0, -1, 1],
                  [-1, -1, math.sqrt(2)],
                  [-1, 1, math.sqrt(2)],
                  [1, -1, math.sqrt(2)],
                  [1, 1, math.sqrt(2)]]

        return motion


def main():
    print(__file__ + " start!!")

    # start and goal position
    sx = -5.0  # [m]
    sy = -5.0  # [m]
    gx = 50.0  # [m]
    gy = 50.0  # [m]
    grid_size = 2.0  # [m]
    robot_radius = 1.0  # [m]

    # set obstacle positions
    ox, oy = [], []
    for i in range(-10, 60):
        ox.append(i)
        oy.append(-10.0)
    for i in range(-10, 60):
        ox.append(60.0)
        oy.append(i)
    for i in range(-10, 61):
        ox.append(i)
        oy.append(60.0)
    for i in range(-10, 61):
        ox.append(-10.0)
        oy.append(i)
    for i in range(-10, 40):
        ox.append(20.0)
        oy.append(i)
    for i in range(0, 40):
        ox.append(40.0)
        oy.append(60.0 - i)

    if show_animation:  # pragma: no cover
        plt.plot(ox, oy, ".k")
        plt.plot(sx, sy, "og")
        plt.plot(gx, gy, "xb")
        plt.grid(True)
        plt.axis("equal")

    a_star = AStarPlanner(ox, oy, grid_size, robot_radius)
    rx, ry = a_star.planning(sx, sy, gx, gy)

    if show_animation:  # pragma: no cover
        plt.plot(rx, ry, "-r")
        plt.pause(0.001)
        plt.show()


if __name__ == '__main__':
    main()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1161750.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

关于打包css找不到报错

背景&#xff1a;最近公司产品升级为v3项目&#xff0c;打包总是报css缺失 问题&#xff1a;报错提示如下&#xff0c;找不到css 出现原因分析&#xff1a;由于项目比较老&#xff0c;很多人写的&#xff0c;代码风格不统一导致的&#xff0c;比如父组件A使用<style><…

日志数据库写入数据频繁内存占用越来越大

一直写数据&#xff0c;内存越来越高。查看内存占用命令&#xff1a;htop 解决方式&#xff1a;日志数据库的模式改为【简单】 完整会把你的所有操作记录早日志文件&#xff0c;简单就不会

虾总管:16年磨一剑,引领餐饮新现象级潮流

在繁忙的都市生活中&#xff0c;我们常常追求一种简单而美好的生活。美食&#xff0c;则是让我们忘却烦恼&#xff0c;回归初心的一种方式。在河北承德&#xff0c;就有这样一家美食品牌虾总管&#xff0c;用一份鸭虾锅带给无数人美好和喜悦。 16年始终如一&#xff0c;初心不改…

teambition迁移云效

由于TB(行云)停止运营了&#xff0c;可惜了&#xff0c;非常好用的一个工具&#xff0c;项目管理&#xff0c;代码管理&#xff0c;自动化构建等&#xff0c;都支持。现需要切换到云效(https://codeup.aliyun.com/)。这个工作量确实挺大的&#xff0c;像我有N个公司*N个项目的&…

win10 vs2015 构建xp适配

整理中&#xff1a; LIB_CPPFLAGS-D"_WIN32_WINNT0x502"

跨模块边界分配和释放内存

我想&#xff0c;有一条编程铁律已经深深的刻入到你的头脑中了&#xff1a;使用成套的函数来分配和释放内存&#xff0c;例如&#xff0c;如果使用 LocalAlloc 分配内存&#xff0c;则应该使用 LocalFree&#xff0c;类似的例子还有&#xff1a;GlobalAlloc 对应 GlobalFree&am…

手把手教你使用Vue2.0实现动态路由展示

文章目录 VUE2相关组件版本原始菜单数据数据库数据树形数据 前端项目配置静态路由配置路由守卫左侧路由回显代码 使用Vue2实现动态路由展示 思路&#xff1a; 后端返回树形数据根据数据渲染左侧菜单根据数据组装路由数据 注意&#xff1a;本文主要目的讲解是一种思路&#xff0…

47GB水经微图从入门到精通视频教程

本视频教程共47GB&#xff0c;为了方便大家观看&#xff0c;同时录制了横版视频教程和竖版视频教程。 本视频教程的内容主要包括快速入门、地图标注、影像下载、高程下载和矢量下载几部分。 本文将列出所有视频教程所有内容。 快速入门&#xff08;23.1GB&#xff09; 如何…

串口实用解说

我们学习单片机&#xff0c;首先接触的可能是点灯&#xff08;GPIO&#xff09;&#xff0c;再次就是串口&#xff08;UART&#xff09;。 串口是常用的一种通信接口&#xff0c;也是学嵌入式必备掌握的一项知识&#xff0c;但我发现有很多小伙伴只知道用串口输出或者打印一些数…

《windows核心编程》第4章 进程

一、进程基本概念 1、进程&#xff1a;一个进程就是一个正在运行的程序&#xff0c;一个程序可以产生多个进程。进程包含下面两个东西 ● 进程内核对象&#xff1a;一个内核对象被系统用来管理某个进程&#xff0c;内核对象就是代表这个进程。这个内核对象中&#xff0c;还包…

CTS分析思路

目录 原理简介&#xff1a; Cts测试原理&#xff1a; CTS报告与日志目录 CTS报告目录如下​编辑 log查看 举例 原理简介&#xff1a; Cts环境搭建和测试方法&#xff0c;大家可以自行查询网上资料。 Cts测试原理&#xff1a; 输入命令后&#xff0c;会安装一系列的测试…

短视频账号矩阵系统/剪辑/矩阵/无人直播/文案引流爆款

一、 短视频账号矩阵源码开发包含哪几方面&#xff1f; 1. 界面设计&#xff1a;需要根据用户需求&#xff0c;设计出优美简洁的UI界面&#xff0c;使用户可以方便快捷地管理自己的短视频账号。 2. 数据存储&#xff1a;需要将用户的账号信息、数据统计等信息存储在数据库中&a…

pytorch dropout 置零 + 补偿性放缩

一句话概括&#xff1a;&#xff08;训练过程中&#xff09;Dropout 操作 随机置零 非置零元素进行后补偿性放缩。以保证dropout前后数据scale不变。 详细解释(来自chatgpt): 在 PyTorch 中&#xff0c;dropout 的操作不仅仅是将某些元素置零。为了确保期望输出在训练和测试…

WoShop跨境电商商城源码(多语言多货币多商户进出口电商平台)

一、跨境电商商城系统源码包括以下几个部分 前端框架&#xff1a;uni-app,vue 后端框架&#xff1a;ThinkPHP5.wokerman 支付系统&#xff1a;PayPal、USDT等主流支付平台 语言包&#xff1a;跨境电商支持15种语言&#xff0c;后续会增加 前端&#xff1a;包含APP端、小程序端、…

无需数据搬迁,10倍性能提升!携程的统一分析之旅

作者&#xff1a;携程技术中心大数据总监 许鹏 携程自 2022 年起引入了 StarRocks&#xff0c;目前已经成为了集团内部的主要技术栈&#xff0c;应用到酒店、机票、商旅、度假、市场、火车票等多个关键业务线。目前&#xff0c;携程内部已经拥有超过 10 个 StarRocks 集群&…

c语言函数宏的几种封装方式

c语言函数宏的几种封装方式 在c语言开发中&#xff0c;除了使用函数封装代码之外&#xff0c;也经常使用宏来封装一些重要或简洁的代码。 宏在c开发有三种&#xff1a;预定义宏&#xff0c;不带参宏&#xff0c;和带参数宏&#xff0c;通常&#xff0c;带参数宏也叫函数宏&am…

HR应用人才测评来提升人才价值

对于企业而言&#xff0c;产出价值是最重要的&#xff0c;但企业拥有人才&#xff0c;才能产出更多的价值&#xff0c;做HR这么久发现很多企业&#xff0c;都欠缺人才管理的测评技术&#xff0c;导致很多人才被埋没或者浪费&#xff0c;这也说明一个很大的问题&#xff0c;一定…

Github 自动化部署到GitHub Pages

1.准备工作 新建仓库 新建项目 配置 vite.config.ts base: ./,部署应用包时的基本URL&#xff0c;例&#xff1a;vue-cli 5.x 配置 publicPath 推送到远程仓库 2.配置 GitHub Token 点击 Settings -> Actions -> General 找到 Workflow permissions&#xff0c;选中第…

sqlserver涉及到三种排序后生成的数字

with temp as (select 1 标识,2023-01-01 日期,a 项目union all select 1,2023-01-01,a union all select 2,2023-01-01,a union all select 2,2023-01-01,b union all select 3,2023-01-01,a union all select 3,2023-01-01,b union all select 3,2023-01-01,c union all …

耳朵小戴什么耳机合适,2023年适合小耳道的蓝牙无线耳机分享

你们是否曾为了追求音乐的同时&#xff0c;担心自己的听力健康呢&#xff1f;尤其是耳朵小的群体&#xff0c;佩戴入耳式时间一长&#xff0c;就会感觉耳道存在一定的疼痛感&#xff0c;不过别担心&#xff0c;现在有了一种完美的解决方案——骨传导耳机&#xff01;这种炫酷的…