Astar路径规划算法复现-python实现

# -*- coding: utf-8 -*-
"""
Created on Fri May 24 09:04:23 2024


"""

import os
import sys
import math
import heapq
import matplotlib.pyplot as plt
import time

'''
传统A*算法
'''


class Astar:
    '''
    AStar set the cost + heuristics as the priority
    AStar将成本+启发式设置为优先级
    '''

    def __init__(self, s_start, s_goal, heuristic_type, xI, xG):
        self.s_start = s_start
        self.s_goal = s_goal
        self.heuristic_type = heuristic_type
        self.u_set = [(-1, 0), (0, 1), (1, 0), (0, -1)]

        # self.obs = self.obs_map()  # 障碍物位置
        self.Open = []  # 优先级序列,open集合
        self.Closed = []  # 相邻点集合,访问visited序列
        self.parent = dict()  # 相邻父节点
        self.g = dict()  # 成本
        self.x_range = 51  # 设置背景大小
        self.y_range = 51

        self.xI, self.xG = xI, xG
        self.obs = self.obs_map()

    def animation(self, path_l, visited_l, name, path_color='g'):

        # 绘制地图基础元素
        obs_x = [x[0] for x in self.obs]
        obs_y = [x[1] for x in self.obs]
        plt.plot(self.xI[0], self.xI[1], "bs")  # 起点
        plt.plot(self.xG[0], self.xG[1], "gs")  # 终点
        plt.plot(obs_x, obs_y, "sk")  # 障碍物
        plt.title(name)
        plt.axis("equal")

        # 移除起点和终点于visited_l列表中,避免它们被标记为已访问点
        visited_l = [node for node in visited_l if node != self.xI and node != self.xG]

        # 绘制所有已访问节点
        for x in visited_l:
            plt.plot(x[0], x[1], color='gray', marker='o')

        # 绘制路径
        path_x = [point[0] for point in path_l]
        path_y = [point[1] for point in path_l]
        plt.plot(path_x, path_y, linewidth=3, color=path_color)

        # 显示最终图形
        plt.show(block=True)

    def obs_map(self):
        """
        Initialize obstacles' positions
        :return: map of obstacles
        初始化障碍物位置
        返回:障碍物
        """
        x = 51
        y = 31
        self.obs = set()

        # 绘制边界
        self.obs.update((i, 0) for i in range(x))

        self.obs.update((i, y - 1) for i in range(x))

        self.obs.update((0, i) for i in range(y))

        self.obs.update((x - 1, i) for i in range(y))

        # 给出障碍物坐标集1
        self.obs.update((i, 15) for i in range(10, 21))
        self.obs.update((20, i) for i in range(15))

        # 给出障碍物坐标集2
        self.obs.update((30, i) for i in range(15, 30))

        # 给出障碍物坐标集3
        self.obs.update((40, i) for i in range(16))

        return self.obs

    def searching(self):
        """
        A_star Searching.
        :return: path, visited order

        Astart搜索,返回路径、访问集,
        """

        self.parent[self.s_start] = self.s_start  # 初始化 起始父节点中只有起点。
        self.g[self.s_start] = 0  # 初始代价为0
        self.g[self.s_goal] = math.inf  # 目标节点代价为无穷大

        # 将元素(self.f_value(self.s_start), self.s_start)插入到Open堆中,
        # 并保持堆的性质(最小堆中父节点的值总是小于或等于其子节点的值))
        # 这行代码的意思是:计算起始节点s_start的评估值f_value(self.s_start),
        # 然后将这对值(f_value, self.s_start)作为一个元组插入到self.Open这个最小堆中。
        # 这样做的目的是在诸如A*搜索算法等需要高效管理待探索节点的场景下,
        # 确保每次可以从堆顶(也就是当前评估值最小的节点)取出下一个待处理的节点。
        # 这对于寻找最短路径、最小成本解决方案等问题非常有用。
        heapq.heappush(self.Open, (self.f_value(self.s_start), self.s_start))

        while self.Open:
            # heappop会取出栈顶元素并将原始数据从堆栈中删除
            # 在这个例子中,heappop返回的元素假设是一个包含两个元素的元组,
            # 但代码中只关心第二个元素(实际的数据,比如一个状态、节点或其他任何类型的数据),
            # 所以用_占位符丢弃了第一个元素(通常是评估值或优先级),而把第二个元素赋值给了变量s
            _, s_current = heapq.heappop(self.Open)  # s_current存储的是当前位置的坐标
            # print('栈顶元素为{0}'.format(s_current))

            self.Closed.append(s_current)

            if s_current == self.s_goal:  # 迭代停止条件,判断出栈顶元素是否为目标点,如果为目标点,则退出
                break
            # 如果不是,更新该点附近的代价值
            # get_neighbor为获取附近点的坐标
            for s_next in self.get_neighbor(s_current):
                new_cost = self.g[s_current] + self.cost(s_current, s_next)

                if s_next not in self.g:
                    self.g[s_next] = math.inf

                if new_cost < self.g[s_next]:
                    self.g[s_next] = new_cost
                    self.parent[s_next] = s_current
                    # heappush入栈时需要存储的该点的代价值的计算方式为
                    heapq.heappush(self.Open, (self.f_value(s_next), s_next))

        # self.animation(self.extract_path(self.parent), self.Closed, "A*")
        return self.extract_path(self.parent), self.Closed

    def get_neighbor(self, s_current):
        """

        :param s_current:
        :return: 相邻点集合
        """
        return [(s_current[0] + u[0], s_current[1] + u[1]) for u in self.u_set]

    def cost(self, s_current, s_next):
        """
        :param s_current 表示当前点
        :param s_next 表示相邻点
        :return 若与障碍物无冲突,则范围欧式距离成本,否则为无穷大成本
        计算当前点与相邻点的距离成本
        """
        # 判断是否与障碍物冲突
        if self.is_collision(s_current, s_next):
            return math.inf
        # 这里返回欧式距离成本
        return math.hypot(s_next[0] - s_current[0], s_next[1] - s_current[1])

    def is_collision(self, s_current, s_next):
        """
            check if the line segment (s_start, s_end) is collision.
            :param s_current: start node
            :param s_next: end node
            :return: True: is collision / False: not collision
            检查起终点线段与障碍物是否冲突
        如果线段的起点或终点之一位于障碍物集合 self.obs 内,则直接判定为碰撞,返回 True。
        若线段不垂直也不水平(即斜线段),则分为两种情况检查:
            若线段为45度线(斜率为1:1或-1),则检查线段的端点形成的矩形框内是否有障碍物。
            否则检查线段端点形成的另一矩形框内是否有障碍物。
        若上述任一矩形框内有障碍,则判定为碰撞,返回 True
        若无碰撞情况,则返回 False
        """
        # obs是障碍物,如果遇到障碍物,则距离(成本)无穷大
        if s_current in self.obs or s_next in self.obs:
            return True
        ''''''
        # 如果该点s_start与相邻点s_end不相同
        if s_current[0] != s_next[0] and s_current[1] != s_next[1]:

            # 如果两点横纵坐标之差相等,即线段不垂直也不水平。135度线
            if s_next[0] - s_current[0] == s_current[1] - s_next[1]:
                s1 = (min(s_current[0], s_next[0]), min(s_current[1], s_next[1]))

                s2 = (max(s_current[0], s_next[0]), max(s_current[1], s_next[1]))
            # 如果两点横纵坐标之差不相等
            else:
                s1 = (min(s_current[0], s_next[0]), max(s_current[1], s_next[1]))
                s2 = (max(s_current[0], s_next[0]), min(s_current[1], s_next[1]))
            # obs是障碍物
            if s1 in self.obs or s2 in self.obs:
                return True
        return False

    def f_value(self, s_currrent):
        """
        f = g + h. (g: Cost to come, h: heuristic value)
        :param s: current state
        :return: f
        """

        return self.g[s_currrent] + self.heuristic(s_currrent)

    def extract_path(self, parent):

        path = [self.s_goal]
        s = self.s_goal

        while True:
            s = parent[s]
            path.append(s)

            if s == self.s_start:
                break

        return list(path)

    def heuristic(self, s_current):

        heuristic_type = self.heuristic_type  # heuristic type
        goal = self.s_goal  # goal node
        # 如果为manhattan,则采用曼哈顿距离,s存储的是中间点
        if heuristic_type == "manhattan":
            return abs(goal[0] - s_current[0]) + abs(goal[1] - s_current[1])
        # 否则就是欧几里得距离,符合勾股定理
        else:
            return math.hypot(goal[0] - s_current[0], goal[1] - s_current[1])


if __name__ == '__main__':
    time_start = time.time()
    s_start = (5, 5)
    s_goal = (45, 26)

    star_m = Astar(s_start, s_goal, "ee", s_start, s_goal)

    path, visited = star_m.searching()
    star_m.animation(path, visited, "A*")  # animation
    time_end = time.time()
    print("程序运行时间:", time_end - time_start)
	

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】 使用CRT 库检测内存泄漏

CRT 库检测内存泄漏 一、CRT 库简介二、CRT 库的使用1、启用内存泄漏检测2、设置应用退出时显示内存泄漏报告3、丰富内存泄漏报告4、演示使用 内存泄漏是 C/C 应用程序中最微妙、最难以发现的 bug&#xff0c;存泄漏是由于之前分配的内存未能正确解除分配而导致的。 最开始的少…

面试(02)————Java集合篇

目录 一、为什么数组索引是从0开始&#xff1f;如果从1开始不行吗&#xff1f; 二、ArrayList底层的实现原理是什么&#xff1f; ​编辑三、ArrayList list new ArrayList(10)中的list扩容几次&#xff1f; 四、如何实现数组与List之间的转换&#xff1f; 五、ArrayList…

计算机图形学入门07:光栅化中的采样与走样

1.什么是光栅化&#xff1f; 在前面的章节里提过&#xff0c;光栅化(Rasterization)就是将物体投影在屏幕上的图形&#xff0c;依据像素打散&#xff0c;每一个像素中填充不同的颜色。 如下图中的老虎&#xff0c;可以看到屏幕上有各种多边形&#xff0c;这些多边形经过各种变换…

线性回归模型详解

一、引言 在机器学习中&#xff0c;线性回归模型是最基础也是最重要的预测模型之一&#xff0c;它是监督学习的一个简单但强大的工具&#xff0c;用于预测输出变量&#xff08;Y&#xff09;与一个或多个输入变量&#xff08;X&#xff09;之间的关系。线性回归模型以其容易理…

动态IP与静态IP的优缺点

在网络连接中&#xff0c;使用动态和静态 IP 地址取决于连接的性质和要求。静态 IP 地址通常更适合企业相关服务&#xff0c;而动态 IP 地址更适合家庭网络。让我们来看看动态 IP 与静态 IP 的优缺点。 1.静态IP的优点&#xff1a; 更好的 DNS 支持&#xff1a;静态 IP 地址在…

【因果推断python】19_局部平均效应2

目录 局部平均干预效果&#xff1a;后期 对参与度的影响 关键思想 局部平均干预效果&#xff1a;后期 局部平均处理效应明确了我们可以估计因果效应的人群。这也是查看 IV 的另一种方式&#xff0c;它提供了我们可以使用的其他很酷的直觉。在现代 IV 中&#xff0c;我们将工…

气膜乒乓球馆:新型体育设施的投资机遇—轻空间

乒乓球作为我国的国球&#xff0c;不仅在世界舞台上表现卓越&#xff0c;在国民的心目中也占有重要位置。随着科技的进步&#xff0c;气膜乒乓球馆作为一种新型体育设施&#xff0c;正逐渐走入大众视野&#xff0c;为乒乓球爱好者提供了一个舒适、安全、环保的运动场所。那么&a…

加强校园气膜体育馆建设的必要性—轻空间

在现代教育中&#xff0c;体育运动作为学生全面发展的重要组成部分&#xff0c;受到越来越多的重视。为了满足学生的运动需求&#xff0c;提供更好的运动场所&#xff0c;加强气膜体育馆在校园中的建设变得尤为重要。气膜体育馆作为一种新型体育设施&#xff0c;凭借其独特的优…

打造精细化运维新玩法(一)

一、SLO介绍——为什么需要SLO 二、SLO健康度——从0到1构建SLO 三、AIOps赋能——SLO和智能化结合 四、案例介绍——实践场景和运营探索 五、总结 精细化运维是运维演进的必由之路&#xff0c;是综合业务需求、研发效能、稳定性保障、成本优化、架构治理等多种因素驱动的必…

纷享销客集成平台(iPaaS)的应用与实践

案例一 企业系统集成的产品级解决方案 概况 随着国家出台一系列鼓励LED照明产业发展与创新的规划和政策&#xff0c;以及国际市场全球演唱会、音乐会的活跃以及线上零售、商业地产等行业回暖&#xff0c;LED显示行业发展形势积极向好。深圳市艾比森光电股份有限公司&#xff…

【Java】static 类方法中注意事项

static 类方法中注意事项 目录 代码示例&#xff1a; package suziguang_d4_staticNote;public class Student {public int score 66;public static String name "zhangsan";// 1.类方法中可以直接访问类的成员&#xff0c;不可以直接访问实例成员public static v…

Virustotal查询恶意进程

1、使用netstat查看可疑进程 执行ls -al /proc/$PID/exe确认可疑进程对应的文件&#xff1b;若文件未被删除&#xff0c;则直接上传文件到Virustotal进行检测&#xff0c;或者计算出文件对应的md5&#xff0c;使用md5去Virustotal进行查询&#xff1b;若文件已被删除&#xff0…

MacOS M系列芯片一键配置多个不同版本的JDK

第一步&#xff1a;下载JDK。 官网下载地址&#xff1a;Java Archive | Oracle 选择自己想要下载的版本&#xff0c;一般来说下载一个jdk8和一个jdk11就够用了。 M系列芯片选择这两个&#xff0c;第一个是压缩包&#xff0c;第二个是dmg可以安装的。 第二步&#xff1a;编辑…

十年数据分析经验分享

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

企业研发数据泄露损失严重,研发数据保护到底怎么才能有效落地?

数据已成为企业毋庸置疑的核心资产&#xff0c;而企业众多数据中&#xff0c;研发数据则占据着重要的角色&#xff0c;近年来&#xff0c;发生了多起企业研发数据被窃取或泄露的事件&#xff0c;给企业带来严重的名誉、经济损失&#xff1a; 小米公司&#xff1a;2023年1月&am…

java学习笔记(持续更新中...)

Java 中的基本数据类型主要包括以下7种&#xff1a; byte&#xff1a;字节型&#xff0c;占用 1 字节&#xff0c;范围-128 到 127。char&#xff1a;字符型&#xff0c;占用 2 字节&#xff0c;范围 0 到 65535。short&#xff1a;短整型&#xff0c;占用 2 字节&#xff0c;…

针对多智能体协作框架的元编程——METAGPT

M ETA GPT: M ETA P ROGRAMMING FOR M ULTI -A GENT COLLABORATIVE F RAMEWORK 1.概述 现有的多智能体系统主要面临以下问题&#xff1a; 复杂性处理不足&#xff1a;传统的多智能体系统主要关注简单任务&#xff0c;对于复杂任务的处理能力有限&#xff0c;缺乏深入探索和…

Dvws靶场

文章目录 一、XXE外部实体注入二、No-SQL注入三、Insecure Direct Object Reference四、Mass Assignment五、Information Disclosure六、Command Injection七、SQL注入 一、XXE外部实体注入 访问http://192.168.92.6/dvwsuserservice?wsdl&#xff0c;发现一个SOAP服务。在SO…

vite项目启动后用局域网不能访问

今天来解决一个问题&#xff1a;基于Vite构建的Vue项目在启动后只能通过localhost这种形式访问 如果把localhost换成本主机的局域网ip地址之后页面无法访问了。 就连用127.0.0.1都无法访问。尝试多次之后&#xff0c;最后证明只有使用localhost这种形式才可以 原因&#xff1…

解锁机器学习的无限可能:深入探究scikit-learn的强大功能

解锁机器学习的无限可能&#xff1a;深入探究scikit-learn的强大功能 第一部分&#xff1a;背景和功能介绍 在数据科学和机器学习领域&#xff0c;scikit-learn&#xff08;简称sklearn&#xff09;是一个广泛使用的Python库。它提供了简单高效的工具用于数据挖掘和数据分析&a…