RRT_star MATLAB

news2024/11/17 11:47:09
  • colormap 函数 创建栅格地图

clc
clear
close all

%% 构建颜色MAP图
cmap = [1 1 1; ...       % 1-白色-空地
    0 0 0; ...           % 2-黑色-静态障碍
    1 0 0; ...           % 3-红色-动态障碍
    1 1 0;...            % 4-黄色-起始点 
    1 0 1;...            % 5-品红-目标点
    0 1 0; ...           % 6-绿色-到目标点的规划路径   
    0 1 1];              % 7-青色-动态规划的路径

% 构建颜色MAP图
colormap(cmap);

%% 构建栅格地图场景
% 栅格界面大小:行数和列数
rows = 10;
cols = 10; 

% 定义栅格地图全域,并初始化空白区域
field = ones(rows, cols);

% 障碍物区域
obsRate = 0.3;
obsNum = floor(rows*cols*obsRate);
obsIndex = randi([1,rows*cols],obsNum,1);
field(obsIndex) = 2;

% 起始点和目标点
startPos = 2;
goalPos = rows*cols-2;
field(startPos) = 4;
field(goalPos) = 5;

%% 画栅格图
image(1.5,1.5,field);
grid on;
set(gca,'gridline','-','gridcolor','k','linewidth',2,'GridAlpha',0.5);
set(gca,'xtick',1:cols+1,'ytick',1:rows+1);
axis image;

RRT* (渐进最优)

算法原理

与RRT类似,通过采样来确定路径。优点:在每次步骤中会比较找出路径中最短的一条,通过不断优化迭代,找出路径最短的路线。核心为对生成的树重新剪枝得到最优的。

  • 参数初始化

    clear all; close all; clc;
    %% 参数初始化
    x_I = 1; y_I = 1;           % 设置初始点
    x_G = 750; y_G = 750;       % 设置目标点
    GoalThreshold = 30;         % 设置目标点阈值
    Delta = 30;                 % 设置扩展步长 default:30
    RadiusForNeib = 80;         % rewire的范围,半径r
    MaxIterations = 1200;       % 最大迭代次数
    UpdateTime = 50;            % 更新路径的时间间隔
    DelayTime = 0.0;            % 绘图延迟时间
    
    %% 建树初始化:T是树,v是节点  结构体实现
    T.v(1).x = x_I;             % 把起始节点加入到T中
    T.v(1).y = y_I; 
    T.v(1).xPrev = x_I;         % 节点的父节点坐标:起点的父节点是其本身
    T.v(1).yPrev = y_I;
    T.v(1).totalCost = 0;       % 从起始节点开始的累计cost,这里取欧氏距离
    T.v(1).indPrev = 0;         % 父节点的索引
    
    %% 开始构建树
    figure(1);
    ImpRgb = imread('map.png');
    Imp = rgb2gray(ImpRgb);
    imshow(Imp)
    xL = size(Imp,1);   % 地图x轴长度
    yL = size(Imp,2);   % 地图y轴长度
    hold on
    plot(x_I, y_I, 'mo', 'MarkerSize',10, 'MarkerFaceColor','m');   % 绘制起点和目标点
    plot(x_G, y_G, 'go', 'MarkerSize',10, 'MarkerFaceColor','g');
    count = 1;
    
    pHandleList = [];
    lHandleList = [];
    resHandleList = [];
    findPath = 0;
    update_count = 0;
    path.pos = [];   % 最终回溯路径
    
  • 环境中随机采样状态点,Xrand

%Step 1: 在地图中随机采样一个点x_rand (Sample)
    x_rand = [unifrnd(0,xL),unifrnd(0,yL)];	%产生随机点(x,y)
  • 遍历树,找到最近的节点, xnear, 第一次遍历,最近节点为初始点
%Step 2: 遍历树,从树中找到最近邻近点x_near (Near)
    minDis = sqrt((x_rand(1) - T.v(1).x)^2 + (x_rand(2) - T.v(1).y)^2);
    minIndex = 1;
    for i = 2:size(T.v,2)	% T.v按行向量存储,size(T.v,2)获得节点总数  
    	distance = sqrt((x_rand(1) - T.v(i).x)^2 + (x_rand(2) - T.v(i).y)^2);   %两节点间距离
        if(distance < minDis)        %% 找到最短距离
            minDis = distance;
            minIndex = i;            %%  index 赋值
        end     
    end
    
    x_near(1) = T.v(minIndex).x;    % 找到当前树中离x_rand最近的节点
    x_near(2) = T.v(minIndex).y;
    temp_parent = minIndex;         % 临时父节点的索引
    temp_cost = Delta + T.v(minIndex).totalCost;   % 临时累计代价  
  • 开始树的生长过程 xnew. 连接xnear和xrand,方向即为生长方向。根据步长生成形成新的节点,xnew. 同时检测节点是否在障碍物内。(到这里就完成了RRT,只要不断重复采样直到生成到达目标点的路径即可。但路径并不优化,而且对于narrow 很难找到
%Step 3: 扩展得到x_new节点 (Steer)
    theta = atan2((x_rand(2) - x_near(2)),(x_rand(1) - x_near(1)));
    x_new(1) = x_near(1) + cos(theta) * Delta;
    x_new(2) = x_near(2) + sin(theta) * Delta;  
    %plot(x_rand(1), x_rand(2), 'ro', 'MarkerSize',10, 'MarkerFaceColor','r');
    %plot(x_new(1), x_new(2), 'bo', 'MarkerSize',10, 'MarkerFaceColor','b');
    
    % 检查节点是否是collision-free 点估计
    if ~collisionChecking(x_near,x_new,Imp)  
        continue;   %有障碍物
    end
  • 以生成的xnew为圆心,在半径内重新搜索节点是否有到达此处更近的路径
%Step 4: 在以x_new为圆心,半径为R的圆内搜索节点 (NearC)
    disToNewList = [];    % 距离 每次循环要把队列清空  xnew改变
    nearIndexList = [];   % index
    for index_near = 1:count  %% count是实际的节点多少 每插入一个 count+1
        disTonew = sqrt((x_new(1) - T.v(index_near).x)^2 + (x_new(2) - T.v(index_near).y)^2);
        if(disTonew < RadiusForNeib)    % 满足条件:欧氏距离小于R
            disToNewList = [disToNewList disTonew];     % 满足条件的所有节点到x_new的cost
            nearIndexList = [nearIndexList index_near];     % 满足条件的所有节点基于树T的索引
        end
    end
  • 搜索完成后,重新选择xnew的父节点,是否有更近的路径使得xnew的累计cost更小
%Step 5: 选择x_new的父节点,使x_new的累计cost最小 (ChooseParent)
    for cost_index = 1:length(nearIndexList)    % 在上个step中寻找到的节点 cost_index是基于disToNewList的索引,不是整棵树的索引
        costToNew = disToNewList(cost_index) + T.v(nearIndexList(cost_index)).totalCost;
        if(costToNew < temp_cost)    % temp_cost为通过minDist节点的路径的cost
            x_mincost(1) = T.v(nearIndexList(cost_index)).x;     % 符合剪枝条件节点的坐标
            x_mincost(2) = T.v(nearIndexList(cost_index)).y;
            if ~collisionChecking(x_mincost,x_new,Imp) 
            	continue;   %有障碍物
            end
        	temp_cost = costToNew;  % 重新赋值 cost min
        	temp_parent = nearIndexList(cost_index); %% xnew新的父节点 index
        end
    end
  • 新的父节点已经生成,现在需要将xnew插入到树中
 %Step 6: 将x_new插入树T (AddNodeEdge)
    count = count+1;    %最新节点的索引
    
    T.v(count).x = x_new(1);          
    T.v(count).y = x_new(2); 
    T.v(count).xPrev = T.v(temp_parent).x;     
    T.v(count).yPrev = T.v(temp_parent).y;
    T.v(count).totalCost = temp_cost;   %  到达当前点的 cost
    T.v(count).indPrev = temp_parent;     %其父节点x_near的index
    
   l_handle = plot([T.v(count).xPrev, x_new(1)], [T.v(count).yPrev, x_new(2)], 'b', 'Linewidth', 2); %% 线句柄
   p_handle = plot(x_new(1), x_new(2), 'ko', 'MarkerSize', 4, 'MarkerFaceColor','k'); %% 点句柄
   
   pHandleList = [pHandleList p_handle];    %绘图的句柄索引即为count
   lHandleList = [lHandleList l_handle];
   pause(DelayTime);
  • 最核心的部分,把多余的节点 进行剪枝
%Step 7: 剪枝 (rewire)  核心  %% 不是最小cost的节点
    for rewire_index = 1:length(nearIndexList)  %%  半径内剪枝
        if(nearIndexList(rewire_index) ~= temp_parent)    % 若不是之前计算的最小cost的节点
            newCost = temp_cost + disToNewList(rewire_index);    % 计算neib经过x_new再到起点的代价          
            if(newCost < T.v(nearIndexList(rewire_index)).totalCost)    % 计算neib经过x_new再到起点的代价小于该点回到起点 需要剪枝
                x_neib(1) = T.v(nearIndexList(rewire_index)).x;     % 符合剪枝条件节点的坐标
                x_neib(2) = T.v(nearIndexList(rewire_index)).y;
                if ~collisionChecking(x_neib,x_new,Imp) 
                    continue;   %有障碍物
                end
                T.v(nearIndexList(rewire_index)).xPrev = x_new(1);      % 父节点改变为 xnew 对该neighbor信息进行更新
                T.v(nearIndexList(rewire_index)).yPrev = x_new(2);
                T.v(nearIndexList(rewire_index)).totalCost = newCost;
                T.v(nearIndexList(rewire_index)).indPrev = count;       % x_new的索引
                
                %delete(pHandleList());
                %delete(lHandleList(nearIndexList(rewire_index)));
                lHandleList(nearIndexList(rewire_index)) = plot([T.v(nearIndexList(rewire_index)).x, x_new(1)], [T.v(nearIndexList(rewire_index)).y, x_new(2)], 'r', 'Linewidth', 2);

                %pHandleList = [pHandleList p_handle];    %绘图的句柄索引即为count
                %lHandleList = [lHandleList l_handle];
            end
        end
    end
  • 终点检测
%Step 8:检查是否到达目标点附近 
    disToGoal = sqrt((x_new(1) - x_G)^2 + (x_new(2) - y_G)^2);
    if(disToGoal < GoalThreshold && ~findPath)    % 找到目标点,此条件只进入一次
        findPath = 1;

        count = count+1;    %手动将Goal加入到树中
        Goal_index = count;
        T.v(count).x = x_G;          
        T.v(count).y = y_G; 
        T.v(count).xPrev = x_new(1);     
        T.v(count).yPrev = x_new(2);
        T.v(count).totalCost = T.v(count - 1).totalCost + disToGoal;
        T.v(count).indPrev = count - 1;     %其父节点x_near的index
    end
  • 沿着终点回溯到起点
 if(findPath == 1)
        update_count = update_count + 1;
        if(update_count == UpdateTime)  %%  更新路径的间隔
            update_count = 0;
            j = 2;
            path.pos(1).x = x_G; 
            path.pos(1).y = y_G;
            pathIndex = T.v(Goal_index).indPrev;
            while 1     
                path.pos(j).x = T.v(pathIndex).x;  % 回溯
                path.pos(j).y = T.v(pathIndex).y;
                pathIndex = T.v(pathIndex).indPrev;    % 沿终点回溯到起点
                if pathIndex == 0
                    break
                end
                j=j+1;
            end  
            
            for delete_index = 1:length(resHandleList)
            	delete(resHandleList(delete_index));
            end
            for j = 2:length(path.pos)
                res_handle = plot([path.pos(j).x; path.pos(j-1).x;], [path.pos(j).y; path.pos(j-1).y], 'g', 'Linewidth', 4);
                resHandleList = [resHandleList res_handle];
            end
        end
    end  
	pause(DelayTime); %暂停DelayTime s,使得RRT*扩展过程容易观察
  • 碰撞检测 确保生成的点 和 生成的路径不在障碍物内
%%  每次迭代一个小步长来判断是否碰撞
function feasible=collisionChecking(startPose,goalPose,map)
feasible=true;
%dir=atan2(goalPose(1)-startPose(1),goalPose(2)-startPose(2));
dir = atan2(goalPose(2)-startPose(2),goalPose(1)-startPose(1));
for r = 0:0.5:sqrt(sum((startPose-goalPose).^2))      %以0.5为步长,从startPose开始递增的检查是否有障碍
    %posCheck = startPose + r.*[sin(dir) cos(dir)];      %直线距离增加0.5后的坐标
    posCheck = startPose + r.*[cos(dir) sin(dir)];      %直线距离增加0.5后的坐标
    %将一个小数(x,y)向4个方向取整,确保该点没有触碰障碍
    
    if ~(feasiblePoint(ceil(posCheck),map) && feasiblePoint(floor(posCheck),map) ...
        && feasiblePoint([ceil(posCheck(1)) floor(posCheck(2))],map) ...
        && feasiblePoint([floor(posCheck(1)) ceil(posCheck(2))],map))
        feasible = false;
        break;
    end
    
    if ~feasiblePoint([floor(goalPose(1)),ceil(goalPose(2))],map)
        feasible = false; 
    end
end

function feasible = feasiblePoint(point,map)
feasible = true;
if ~(point(1)>=1 && point(1)<=size(map,1) && point(2)>=1 ...
    && point(2)<=size(map,2) && map(point(2),point(1))==255)  %% 225  是否是白的
    feasible = false;   %有障碍
end

在这里插入图片描述

  • 针对采样方法也可以做出调整,比如在一定区域内采样而不是直接在整个地图内进行均匀采样

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

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

相关文章

Canal同步mysql binlog至pulsar

Canal 一、简介 canal [kə’nl]&#xff0c;主要用途是基于 MySQL 数据库增量日志解析&#xff0c;提供增量数据订阅和消费 基于日志增量订阅和消费的业务包括 数据库镜像数据库实时备份索引构建和实时维护(拆分异构索引、倒排索引等)业务 cache 刷新带业务逻辑的增量数据处…

【数据结构】队列(链式队列)

作者&#xff1a;一个喜欢猫咪的的程序员 专栏&#xff1a;《数据结构》 喜欢的话&#xff1a;世间因为少年的挺身而出&#xff0c;而更加瑰丽。 ——《人民日报》 目录 队列的结构和概念&#xff1a; Queue.h文件 Queue.c文件 Test.c文件&am…

ElasticSearch分布式架构原理

一个ES集群中有多个Server节点&#xff0c;每个Server节点中含有多个Index。 主节点&#xff08;Master&#xff09; 主资格节点的主要职责是和集群操作相关的内容&#xff0c;如创建或删除索引&#xff0c;跟踪哪些节点是集群的一部分&#xff0c;并决定哪些分片分配给相关的…

文件系统篇

目录 1.文件系统的基本组成 1.1.文件 1.1.1.目录项和目录是一个东西吗&#xff1f; 1.1.2.那文件数据是如何存储在磁盘的呢&#xff1f; 2.page cache 2.1.进程写文件时&#xff0c;进程发生了崩溃&#xff0c;已写入的数据会丢失吗 2.2.page cache是什么&#xff1f; …

Docker:网络配置

目录 一、网络模式简介 二、bridge模式以及host模式的命令演示 bridge模式 host模式 三、自定义网络 一、网络模式简介 Docker在创建容器时有四种网络模式&#xff1a;bridge/host/container/none&#xff0c;bridge为默认不需要用--net去指定&#xff0c;其他三种模式需要…

CAS机制和synchronize的原理及其优化机制(锁消除 偏向锁 自旋锁 膨胀锁 锁粗化)

乐观锁的问题&#xff1a;并不总是能处理所有问题&#xff0c;所以会引入一定的系统复杂度。 读写锁 把加锁操作分成了俩种 一是读锁二是写锁 也就是说在读和读之间是没有互斥的 但是在读写和写写之间就会存在互斥 如果一个场景是一写多度 那么使用这个效率就会很高 重量级锁…

【数据结构与算法】B_树

目录 前言&#xff1a; 一、B树 1、B树概念 2、B树查找 3、B树插入 4、B树前序遍历 5、B树性能 二、B、B*树 1、B树概念 2、B树的插入 2、B*树概念 3、总结 三、B系列树的应用 总结 前言&#xff1a; 我们已经有很多索引的数据结构了 例如&#xff1a; 顺序查找 …

CAD外部参照文件的分解

最近遇到一个编图要求&#xff1a; “图纸文件的内容主要由模型空间和布局空间内的信息组成&#xff0c;尽量减少外部参照的使用。” 我们的综合图分幅主要依照外部参照来的&#xff0c;图件的本体只有1个&#xff0c;分幅图中只有布局试图有点线面等实体存在&#xff0c;模型…

阿里二面:用过GC日志可视化工具进行JVM调优吗?

上周有个小伙伴面了阿里&#xff0c;在二面中被问到GC日志分析&#xff0c;感觉回答的不是很好&#xff0c;过来找我复盘&#xff0c;大致听了他的回答&#xff0c;虽然回答出了部分&#xff0c;但是没抓到重点。 GC日志分析算是JVM调优中比较难的部分&#xff0c;今天这篇文章…

0123 双指针 Day12

剑指 Offer 25. 合并两个排序的链表 输入两个递增排序的链表&#xff0c;合并这两个链表并使新链表中的节点仍然是递增排序的。 示例1&#xff1a; 输入&#xff1a;1->2->4, 1->3->4 输出&#xff1a;1->1->2->3->4->4 /*** Definition for si…

安科瑞嵌入式多功能计量表AEM96 精度0.5S级 2-31次分次谐波

安科瑞 王晶淼/刘芳 一、产品概述 AEM系列三相嵌入式电能计量表是一款主要针对电力系统、工矿企业、公用设施的电能统计、管理需求而设计的智能电能表&#xff0c;集成三相电力参数测量及电能计量与考核管理&#xff0c;提供上24时&#xff0c;上31日以及上12月的电能数据统计…

DNS 区域传送漏洞(dns-zone-tranfer)学习

DNS 区域传送漏洞&#xff08;dns-zone-tranfer&#xff09;学习 ———— 相关知识理解 DNS&#xff08;域名系统&#xff09;就像一个互联网电话簿。它负责将人类可读的主机名解析为机器可读的 IP 地址。 DNS服务器分为主服务器&#xff0c;备份服务器&#xff0c;缓存服务…

【Docker】多个容器和宿主机之间如何进行数据同步和数据共享?容器数据卷从介绍到常用操作图文教程

专栏往期文章 《Docker是什么&#xff1f;Docker从介绍到Linux安装图文详细教程》《30条Docker常用命令图文举例总结》《Docker如何构建自己的镜像&#xff1f;从镜像构建到推送远程镜像仓库图文教程》 前言 你是否担心 Docker 容器被删除后&#xff0c;容器内的重要数据就丢…

VFIDILDKVENAIHNAAQVGIGFAKPFEKLINPK,果蝇抗菌肽

果蝇抗菌肽是一种含有Lys的抗菌多肽&#xff0c;序列中包含34个氨基酸&#xff0c;是一种含有α-折叠的抗菌多肽。 编号: 223981中文名称: 果蝇抗菌肽&#xff0c;Andropin英文名: Antimicrobial Peptide Andropin单字母: H2N-VFIDILDKVENAIHNAAQVGIGFAKPFEKLINPK-OH三字母: H2…

自然语言处理(NLP)数据集汇总 3(附下载链接)

&#x1f384;&#x1f384;【自然语言处理NLP】简介 &#x1f384;&#x1f384; 自然语言处理(Natural Language Processing, NLP)是计算机科学领域与人工智能领域中的一个重要方向。它研究能实现人与计算机之间用自然语言进行有效通信的各种理论和方法。自然语言处理是一门…

Allure:根据step动态设置description

背景 使用pytestAllure进行自动化的时候,为了报告展示更明确会使用 with allure.step(xxx)和 allure.step(xxx)测试结束后就可以看到 测试步骤 Allure还支持配置Description 之前直接在case中编写,例如 """ [用例描述]: 专家问诊 [前置步骤]:1. 打开h5页面…

ScheduledExecutorService的使用及守护线程

只运行一次 private static ScheduledExecutorService scheduler; public static void main(String[] args) throws Exception { scheduler Executors.newScheduledThreadPool(5); // 循环任务&#xff0c;按照上一次任务的发起时间计算下一次任务的开始时间 scheduler.schedu…

解决mysql存储emoji表情唯一索引报错问题

问题发现&#xff1a; 1、正常上班的一天&#xff0c;突然间有运营同事反馈&#xff0c;我们在添加数据的时候&#xff0c;发现添加了&#x1f438;之后&#xff0c;对应的&#x1f4a9;没有了&#xff0c;添加了&#x1f4a9;然后&#x1f438;就没有了&#xff0c;需要研发帮…

【Linux】四、Linux 进程概念(四)|进程地址空间

目录 十、进程地址空间 10.1 回顾C/C 地址空间 10.2 测试 10.3 感性理解虚拟地址空间 10.4 如何画大饼&#xff1f; 10.5 如何理解区域划分和区域调整 10.6 虚拟地址空间、页表和物理地址 10.7 为什么存在地址空间 10.7.1 保证物理内存的安全性 10.7.2 保证进程的独立…

铁蛋白-海藻酸钠纳米包埋ACE抑制肽|海藻酸钠修饰碳纳米管(SAL-MWNTs)

铁蛋白-海藻酸钠纳米包埋ACE抑制肽|海藻酸钠修饰碳纳米管(SAL-MWNTs) 铁蛋白-海藻酸钠纳米包埋ACE抑制肽产品描述&#xff1a;利用铁蛋白在较酸条件下可逆组装特性和海藻酸钠(sodium alginate,SA)的控释作用,以马脾脱铁铁蛋白(horse spleen apoferritin,HSF)和SA作为纳米载体,…