自动驾驶算法(五):基于遗传算法的路径规划(上)

news2024/11/27 8:39:58

目录

1 遗传算法介绍

2 遗传算法代码详解--绘制地图与种群初始化代码讲解


1 遗传算法介绍

        模拟生物进化过程,物竞天择,适者生存。

        我们先为栅格地图进行编码:从起点0出发到终点24这个栅格。我们首先有一条路径(0,6,7,13,19,24),我们用这个方法表示一个个体,我们首先要产生很多这样的个体。这就是种群初始化的过程:

        1.我们发现每行至少要选择一个栅格,因此我们要每行选择一个栅格,起点要选择,第二行选择6,第三行选择13,第四行选择19,第五行选择24(终点)。

        2.判断相邻的栅格是否连续(是否可以一步走过去)(为地图建立一个坐标系,为每个栅格分配一个(X,Y)坐标。)如果两个栅格的最大X,Y的坐标差小于等于1是可以走过来的。(表示两个栅格是对角的或者相邻的)

        3.如果发现两个栅格不连续进行插入栅格方式,直到连续(6号与13号不连续),插入7号再判断2。如果有碰撞的话会有更复杂的操作,这个我们会接下来说。

        比如6号栅格的坐标为(2,2),13号栅格为(4,3),我们取中间的栅格(3,2)(7号栅格)

        总体流程如下:

        种群初始化就是产生出很多条这样的路径,在初始化以后,我们就要进入遗传算法的循环了,首先第一步就是选择,如下图:

        我们有两条路径对应两个个体,我们要选择较好的个体,选择标准可以是路径的长度d,我们选择路径的倒数为适应度,越短的路径它的适应度就越大。还有就是路径的顺滑性,以相邻的三个点为例子,会组成一个三角形,我们就希望三个点连起来的角度越大,我们可以通过余弦定理来得到加入适应度函数。我们根据经验计算每个适应度的权重a,b,这个通过经验或者实验获得。我们有了每条路径的适应度的值,我们会对每个个体计算保留的概率pi。

        第二步就是交叉,如下图:

        上图中的两条路经在13号点出现了交叉,我们可以交换交叉点前后的路径生成两条新的路径,这样就丰富了个体。

        第三步就是变异,如下图:

        我们先随机的在路径中选择两个栅格(在这里我们选择1、13号栅格),采用种群初始化的方式在两个栅格间产生新的路径(比如1、7、13),我们循环执行这三步。每次选择更好的路径保存下来再通过交叉变异产生新的路径,整个种群都会向着更好的方向发展

2 遗传算法代码详解--绘制地图与种群初始化代码讲解

        先看一下运行效果:

        看下代码,我们首先绘制地图:

clc;
clear;
% Grid Map
G=  [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
     0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
     0 0 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0;
     0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0;
     0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0;
     0 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
     0 1 1 1 0 0 1 1 1 0 0 0 0 0 0 0 0 0 0 0;
     0 0 0 0 0 0 1 1 1 0 1 0 1 1 0 0 0 0 0 0;
     0 1 1 1 0 0 0 0 0 0 1 0 1 1 0 0 0 0 0 0;
     0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0;
     0 0 0 0 0 0 0 1 1 0 1 1 1 1 0 0 0 0 0 0;
     0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0;
     0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 1 1 1 1 0;
     0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0;
     0 0 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0;
     0 0 1 1 0 0 1 1 1 0 1 0 0 0 0 0 0 0 0 0;
     0 0 0 0 0 0 1 1 1 0 1 0 0 0 0 0 0 1 1 0; 
     0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 1 0;
     0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0;
     0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0];

        注意,这是反过来的!!!!我们第一行是图形的最下面。

        随后我们初始化了一些变量:

p_start = 0;   % 开始的index
p_end = 399;   % 结束的index
NP = 200;      % 种群大小
max_gen = 50;  % 最大进化次数
pc = 0.8;      % 交叉处理频率
pm = 0.2;      % 变异频率
init_path = [];
z = 1;  
new_pop1 = {}; % 路径
[y, x] = size(G);  % 地图的x和y的数量 x=y=20
% x的起点 p_start对应开始的栅格
% xs = 1  ys = 1
% 举个例子  p_start 的值是 10,x 的值是 3,那么表达式的计算过程如下 mod(10, 3) + 1 = 1+1 = 2
xs = mod(p_start, x) + 1; 
% y的起点 p_start对应开始的栅格
% 如果 p_start 的值是 10,x 的值是 3,那么表达式的计算过程如下 fix(10 / 3) + 1 = fix(3.333333) + 1 = 3+1=4 
ys = fix(p_start / x) + 1;

% x、y的终点栅格坐标 
% mod(399,20) + 1 = 19 + 1 = 20
% fix(399/20) + 1 = 19 + 1 = 20
xe = mod(p_end, x) + 1;
ye = fix(p_end / x) + 1;

% step1 种群初始化
% pass_num 20 - 20 + 1 = 1
pass_num = ye - ys + 1;

% 种群有NP = 200个个体 每个个体的路径个数初始化为起点到终点的y距离(好像是不太够呀) 
pop = zeros(NP, pass_num);

        我们在下面这段代码进行种群初始化:

% 种群初始化代码
for i = 1 : NP
    % 无论是哪一条路径 起点肯定是起点 pop(1,:)存储的是第一个种群 pop(1,1)就是第一个种群的读一个节点
    pop(i, 1) = p_start;
    j = 1;
    % yk = 2 : 19  遍历每一个路径的每一行
    % 更新pop(1,1) pop(1,2) ... pop(1,20)
    for yk = ys+1 : ye-1
        j = j + 1;
        % 存储一行的可行点
        can = []; 
        % xk = 1 : 20
        for xk = 1 : x
            % 栅格编号 没有障碍物
            no = (xk - 1) + (yk - 1) * x;
            if G(yk, xk) == 0
                % 将变量 no 添加到数组 can 的末尾。
                can = [can no];
            end
        end
        can_num = length(can);
        % 产生随机整数
        index = randi(can_num);
        % 为每一行添加一个可行点 can存储着一行的可行点  can(index)
        pop(i, j) = can(index);
    end
    pop(i, end) = p_end;
    % pop
    % 将上述必经节点联结成无间断路径
    single_new_pop = generate_continuous_path(pop(i, :), G, x);
    % init_path = [init_path, single_new_pop];
    if ~isempty(single_new_pop)
       new_pop1(z, 1) = {single_new_pop};
        z = z + 1;
    end
end

        我们拿第一个种群的生成举例子吧:

        pop被我们初始化为zeros(NP, pass_num); 也就是200*20的空矩阵,也就是每一列存储着一个种群的路径。也就是:pop(1,1) pop(2,1).....pop(20,1)存储着第一个种群的信息。那么第一个种群的起始点一定是我们导航的初始坐标pop(1,1) = start,然后我们更新第2-19列的值,先看第一个for循环,我们把每一行的可行点(除去障碍物点的点都加入了can列表中,我们随机生成一个和列表长度相同的索引将这个索引代表的点作为这一行的路径)

        但是这些路径未必连通,我们需要将路径连通,我们用generate_continuous_path函数去保证路径连通:

% 传入参数 个体的路径 地图 一行有多少个元素x
% 它告诉 MATLAB 这是一个名为 generate_continuous_path 的函数,它接受三个输入参数 single_pop,G 和 x,并且它会返回一个名为 single_new_pop 的变量。
function [single_new_pop] = generate_continuous_path(single_pop, G, x)
i = 1;
single_new_pop = single_pop;
% 这行代码调用了 size 函数来获取变量 single_new_pop 的大小,并将结果存储在了 single_path_num 变量中。
% 在这里,使用了波浪线 ~ 来表示忽略了 size 函数返回的第一个值(也就是行数),只保留了列数。
% single_new_pop 是一个 1 * 20的向量
% single_path_num
[~, single_path_num] = size(single_new_pop);

% 遍历每一列 1-20
while i ~= single_path_num
    % 点i所在列 (从左到右编号)
    x_now = mod(single_new_pop(1, i), x) + 1; 
    % 点i所在行 (从上到下编号)
    y_now = fix(single_new_pop(1, i) / x) + 1;
    % 点i+1所在行 (从上到下编号)
    x_next = mod(single_new_pop(1, i + 1), x) + 1;
    y_next = fix(single_new_pop(1, i + 1) / x) + 1;
    
    % 初始化最大迭代次数
    max_iteration = 0;
    
    % 如果他们不相连的话
    while max(abs(x_next - x_now), abs(y_next - y_now)) > 1
        x_insert = floor((x_next + x_now) / 2);
        y_insert = floor((y_next + y_now) / 2);
        
        % 取得两者中点值
        if G(y_insert, x_insert) == 0  
            % 栅格值
            num_insert = (x_insert - 1) + (y_insert - 1) * x;
            % single_new_pop 是一个数组,这段代码的目的是将 num_insert 插入到 single_new_pop 的第 i 个位置之后。
            % single_new_pop(1, 1:i) 表示取 single_new_pop 中第1行,从第1列到第i列的元素。
            % single_new_pop(1, i+1:end) 表示取 single_new_pop 中第1行,从第i+1列到最后一列的元素。
            single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];
            
        % 如果是障碍物的话
        else   
            % 它检查该点左面是否有路径 
            % (x_insert - 2) + (y_insert - 1) * x 是否不等于 single_new_pop(1, i)。
            if G(y_insert, x_insert - 1) == 0 && ((x_insert - 2) + (y_insert - 1) * x ~= single_new_pop(1, i)) && ((x_insert - 2) + (y_insert - 1) * x ~= single_new_pop(1, i+1))
                x_insert = x_insert - 1;
                % 索引号
                num_insert = (x_insert - 1) + (y_insert - 1) * x;
                % 插入
                single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];
                               
            elseif G(y_insert, x_insert + 1) == 0 && (x_insert + (y_insert - 1) * x ~= single_new_pop(1, i)) && (x_insert + (y_insert - 1) * x ~= single_new_pop(1, i+1))
                x_insert = x_insert + 1;
                num_insert = (x_insert - 1) + (y_insert - 1) * x;
                single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];
                
            elseif G(y_insert + 1, x_insert) == 0 && ((x_insert - 1) + y_insert * x ~= single_new_pop(1, i)) && ((x_insert - 1) + y_insert * x ~= single_new_pop(1, i+1))
                y_insert = y_insert + 1;
                num_insert = (x_insert - 1) + (y_insert - 1) * x;
                single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];

            elseif  G(y_insert - 1, x_insert) == 0 && ((x_insert - 1) + (y_insert - 2) * x ~= single_new_pop(1, i)) && ((x_insert - 1) + (y_insert-2) * x ~= single_new_pop(1, i+1))
                y_insert = y_insert - 1;
                num_insert = (x_insert - 1) + (y_insert - 1) * x;
                single_new_pop = [single_new_pop(1, 1:i), num_insert, single_new_pop(1, i+1:end)];
                
            % 左右上下都是占据的则删去路径
            else
                %break_pop = single_new_pop
                single_new_pop = [];
                break
            end    
        end
        
        x_next = x_insert;
        y_next = y_insert;
        max_iteration = max_iteration + 1;
        if max_iteration > 20000
            single_new_pop = [];
            break
        end
        
    end
    
    if isempty(single_new_pop)
        break
    end
    
    [~, single_path_num] = size(single_new_pop);
    i = i + 1;
end

        到此为止,我们已经完成了种群初始化环节,规划出了很多条路径。

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

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

相关文章

最近面了12个人,发现连这种基础题都答不上来.....

一般面试我都会问一两道很基础的题目,来考察候选人的“地基”是否扎实,有些是操作系统层面的,有些是 python语言方面的,还有些… 深耕IT行业多年,我们发现,对于一个程序员而言,能去到一线互联网…

golang工程中间件——redis常用结构及应用(string, hash, list)

Redis 命令中心 【golang工程中间件——redisxxxxx】这些篇文章专门以应用为主,原理性的后续博主复习到的时候再详细阐述 string结构以及应用 字符数组,redis字符串是二进制安全字符串,可以存储图片等二进制数据,同时也可以存…

ns3入门基础教程

ns3入门基础教程 文章目录 ns3入门基础教程ns环境配置测试ns3环境ns3简单案例 ns环境配置 官方网站:https://www.nsnam.org/releases/ 代码仓库:https://gitlab.com/nsnam/ns-3-dev 如果安装遇到问题,可以参考以下博文: https://…

19、Flink 的Table API 和 SQL 中的内置函数及示例(1)

Flink 系列文章 1、Flink 部署、概念介绍、source、transformation、sink使用示例、四大基石介绍和示例等系列综合文章链接 13、Flink 的table api与sql的基本概念、通用api介绍及入门示例 14、Flink 的table api与sql之数据类型: 内置数据类型以及它们的属性 15、Flink 的ta…

吴恩达《机器学习》6-4->6-7:代价函数、简化代价函数与梯度下降、高级优化、多元分类:一对多

一、代价函数 逻辑回归的代价函数是用来度量模型预测与实际结果之间的差异的。与线性回归使用均方误差不同,逻辑回归使用的代价函数在数学上更为复杂。为了理解逻辑回归的代价函数,首先要明白逻辑回归的假设函数: ℎ𝜃(&#x1…

【高德地图API】JS高德地图API实现多边形绘画,高德获取多边形提交数据

目录 前言效果实现引入js 在项目中使用效果图引入htmlCSS具体实现JS调用说明添加的时候修改的时候判断是否在范围内 java绘画和判断是否在范围内pom.xml依赖引入import引入实现 前言 高德地图官方API:https://lbs.amap.com/demo/javascript-api/example/overlayers…

计算机编程软件编程基础知识,中文编程工具下载分享

计算机编程软件编程基础知识,中文编程工具下载分享 给大家分享一款中文编程工具,零基础轻松学编程,不需英语基础,编程工具可下载。 这款工具不但可以连接部分硬件,而且可以开发大型的软件,象如图这个实例…

LangChain+LLM实战---用AI(大模型)重构推荐系统

原文:Reimagining the Recommendation Engine AI助手的崛起 人工智能正在改变我们与在线应用程序互动的方式。目前,我们使用搜索引擎、新闻源和精心设计的菜单来导航,这些菜单引导我们找到所需的信息或服务。然而,我相信目前人工…

【IK分词器安装】

安装IK分词器: 下载链接(如果es版本不同可以修改下版本号):https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.12.1/elasticsearch-analysis-ik-7.12.1.zip 通常下载是比较慢的:有需要可以从…

OFDM同步--载波频率偏差CFO

参考书籍:《MIMO-OFDM无线通信技术及MATLAB实现》 实验图基本都截取自该本书 一、什么是CFO OFDM解调是采用同步检波的方式,需要在接收机使用与发射机相同的载波信号进行向下变换恢复出基带信号。但在实际使用中无法获得完全相同的载波信号,…

Mybatis-Plus自动填充功能配置和使用 [MyBatis-Plus系列] - 第494篇

历史文章(文章累计490+) 《国内最全的Spring Boot系列之一》 《国内最全的Spring Boot系列之二》 《

测试开发之自动化篇-有效测试数据管理

我们知道在测试设计时,对于一些操作相似的场景,可以采用步骤同数据相分离的方法来描述。这样的用例内容精炼、逻辑清晰,也利于未来自动化测试脚本的复用。 数据驱动测试是一种流行的软件测试方法,用于归纳性、结构化和集中化地描…

Linux开发板移植FTP服务器和OpenSSH时发现的问题

先上结论:如果在linux开发板上移植了OpenSSH,那么不仅可以远程登录Linux开发板,还可以用FileZilla在windows和Linux开发板之间传输文件,这时候就不需要移植vsftpd(移植vsftpd后windows可以用FileZilla跟Linux开发板传输文件)了&am…

【Unity ShaderGraph】| 快速制作一个 表面水纹叠加效果

前言 【Unity ShaderGraph】| 快速制作一个 表面水纹叠加效果一、效果展示二、表面水纹叠加效果三、应用实例 前言 本文将使用ShaderGraph制作一个表面水纹叠加效果,可以直接拿到项目中使用。对ShaderGraph还不了解的小伙伴可以参考这篇文章:【Unity Sh…

CentOS/RHEL7环境下更改网卡名称为CentOS6的传统命名规则

图片 CentOS/RHEL7网卡命名规则介绍 图片 传统的Linux服务器网卡的名称命名方式是从eth0,eth1,eth2....这种方式命名的,但是这个编号往往不一定准确对应网卡接口的物理顺序,常规模式下我们使用的服务器设备可能只有一张网卡,若网卡较多的情…

抖音10月榜单有哪些看点?

10月20日,抖音双11好物节在抖音平台正式开启抢跑,据数据显示,截止10月31日平台多项双11销售增长记录再次被刷新。 *新抖双十一活动也已开启,最高可省30788元,活动详情👉 抖音平台内大促氛围火爆&#xff0…

桶装水订水系统水厂送水小程序开发;

桶装水小程序正式上线,支持多种商品展示形式,会员卡、积分、分销等功能; 开发订水送水小程序系统,基于用户、员工、商品、订单、配送站和售后管理模块,对每个模块进行统计分析,简化了分配过程,提…

虹科教您 | 如何选择超声波储罐液位传感器(一)

在储罐中安装传感器时需要考虑: 1.避开障碍物 - 罐壁或罐内的其他障碍物会导致测距读数不准确。 2.放置会影响读数 - 初始的过滤设置是让传感器优先考虑大目标而不是小目标和噪音源。这有利于储罐液位监测的应用,因为液位往往会产生最大的返回声波。 …

ES 报错问题汇总

报错1: curl -XGET http://192.168.56.115:9200/_license解决方式 在 es/config/elasticsearch.yml文件,把开启密码验证把此处也修改成false xpack.security.enabled: false 报错2: 解决方式: 查看服务器es的license信息,发现 …

信驰达RF-DG-52PAS CC2652P Zigbee 3.0 USB Dongle烧录指南

一、使用前准备 RF-DG-52PAS是信驰达科技基于美国 TI CC2652P和CP2102为核心设计的Zigbee 3.0 USB Dongle,可烧录 Z-Stack 3.x.0协调器固件,可以直接连接到计算机或树莓派,通过ZHA或 Zigbee2MQTT连接到 Home Assistant或其他开源物联网平台。还可以烧录…