无障碍 关怀版
评论

全局路径规划 - RRT算法原理及实现

计算机视觉life”,选择“星标”

快速获得最新干货

文章转载古月居

无人驾驶路径规划

众所周知,无人驾驶大致可以分为三个方面的工作:感知,决策及控制。

路径规划是感知和控制之间的决策阶段,主要目的是考虑到车辆动力学、机动能力以及相应规则和道路边界条件下,为车辆提供通往目的地的安全和无碰撞的路径。

路径规划问题可以分为两个方面:

(一)全局路径规划:全局路径规划算法属于静态规划算法,根据已有的地图信息(SLAM)为基础进行路径规划,寻找一条从起点到目标点的最优路径。

通常全局路径规划的实现包括Dijikstra算法,A*算法,RRT算法等经典算法,也包括蚁群算法、遗传算法等智能算法;

(二)局部路径规划:局部路径规划属于动态规划算法,是无人驾驶汽车根据自身传感器感知周围环境,规划处一条车辆安全行驶所需的路线,常应用于超车,避障等情景。通常局部路径规划的实现包括动态窗口算法(DWA),人工势场算法,贝塞尔曲线算法等,也有学者提出神经网络等智能算法。

本系列就从无人驾驶路径规划的这两方面进行展开,对一些经典的算法原理进行介绍,并根据个人的一些理解和想法提出了一些改进的意见,通过Matlab2019对算法进行了仿真和验证。过程中如果有错误的地方,欢迎在评论区留言讨论,如有侵权请及时联系。

那么废话不多说,直接进入第一部分的介绍,全局路径规划算法-RRT算法。

全局路径规划 - RRT算法原理

RRT算法,即快速随机树算法(Rapid Random Tree),是LaValle在1998年首次提出的一种高效的路径规划算法。RRT算法以初始的一个根节点,通过随机采样的方法在空间搜索,然后添加一个又一个的叶节点来不断扩展随机树。

当目标点进入随机树里面后,随机树扩展立即停止,此时能找到一条从起始点到目标点的路径。算法的计算过程如下:

step1:初始化随机树。将环境中起点作为随机树搜索的起点,此时树中只包含一个节点即根节点;

stpe2:在环境中随机采样。在环境中随机产生一个点,若该点不在障碍物范围内则计算随机树中所有节点到的欧式距离,并找到距离最近的节点,若在障碍物范围内则重新生成并重复该过程直至找到;

stpe3:生成新节点。在和连线方向,由指向固定生长距离生成一个新的节点,并判断该节点是否在障碍物范围内,若不在障碍物范围内则将添加到随机树 中,否则的话返回step2重新对环境进行随机采样;

step4:停止搜索。当和目标点之间的距离小于设定的阈值时,则代表随机树已经到达了目标点,将作为最后一个路径节点加入到随机树中,算法结束并得到所规划的路径 。

RRT算法由于其随机采样及概率完备性的特点,使得其具有如下优势:

(1)不需要对环境具体建模,有很强空间搜索能力;

(2)路径规划速度快;

(3)可以很好解决复杂环境下的路径规划问题。

但同样是因为随机性,RRT算法也存在很多不足的方面:

(1)随机性强,搜索没有目标性,冗余点多,且每次规划产生的路径都不一样,均不一是最优路径;

(2)可能出现计算复杂、所需的时间过长、易于陷入死区的问题;

(3)由于树的扩展是节点之间相连,使得最终生成的路径不平滑;

(4)不适合动态环境,当环境中出现动态障碍物时,RRT算法无法进行有效的检测;

(5)对于狭长地形,可能无法规划出路径。

RRT算法Matlab实现

使用matlab2019来编写RRT算法,下面将贴出部分代码进行解释。

1、生成障碍物

在matlab中模拟栅格地图环境,自定义障碍物位置。

%% 生成障碍物 ob1 = [ 0, -10, 10, 5]; % 三个矩形障碍物 ob2 = [ -5, 5, 5, 10]; ob3 = [ -5, -2, 5, 4]; ob_limit_1 = [ -15, -15, 0, 31]; % 边界障碍物 ob_limit_2 = [ -15, -15, 30, 0]; ob_limit_3 = [ 15, -15, 0, 31]; ob_limit_4 = [ -15, 16, 30, 0]; ob = [ob1;ob2;ob3;ob_limit_1;ob_limit_2;ob_limit_3;ob_limit_4]; % 放到一个数组中统一管理 x_left_limit = -16; % 地图的边界 x_right_limit = 15; y_left_limit = -16; y_right_limit = 16;

我在这随便选择生成三个矩形的障碍物,并统一放在ob数组中管理,同时定义地图的边界。

2、初始化参数设置

初始化障碍物膨胀范围、地图分辨率,机器人半径、起始点、目标点、生长距离和目标点搜索阈值。

%% 初始化参数设置 extend_area = 0.2; % 膨胀范围 resolution = 1; % 分辨率 robot_radius = 0.2; % 机器人半径 goal = [ -10, -10]; % 目标点 x_start = [ 13, 10]; % 起点 grow_distance = 1; % 生长距离 goal_radius = 1.5; % 在目标点为圆心, 1.5m内就停止搜索

3、初始化随机树

初始化随机树,定义树结构体tree以保存新节点及其父节点,便于后续从目标点回推规划的路径。

%% 初始化随机树 tree.child = []; % 定义树结构体,保存新节点及其父节点 tree.parent = []; tree.child = x_start; % 起点作为第一个节点 flag = 1; % 标志位 new_node_x = x_start( 1, 1); % 将起点作为第一个生成点 new_node_y = x_start( 1, 2); new_node = [new_node_x, new_node_y];

4、主函数部分

主函数中首先生成随机点,并判断是否在地图范围内,若超出范围则将标志位置为0。

rd_x = 30* rand - 15; % 生成随机点 rd_y = 30* rand - 15; if(rd_x >= x_right_limit || rd_x <= x_left_limit ||... % 判断随机点是否在地图边界范围内 rd_y >= y_right_limit || rd_y <= y_left_limit) flag = 0; end

调用函数cal_distance计算tree中距离随机点最近的节点的索引,并计算该节点与随机点连线和x正向的夹角。

[angle, min_idx] = cal_distance(rd_x, rd_y, tree); % 返回tree中最短距离节点索引及对应的和x正向夹角

cal_distance函数定义如下:

function [angle, min_idx] = cal_distance(rd_x, rd_y, tree) distance = []; i = 1; whilei<=size(tree.child, 1) dx = rd_x - tree.child(i, 1); dy = rd_y - tree.child(i, 2); d = sqrt(dx^ 2+ dy^ 2); distance(i) = d; i = i+ 1; end [~, min_idx] = min(distance); angle = atan2(rd_y - tree.child(min_idx, 2),rd_x - tree.child(min_idx, 1)); end

随后生成新节点。

new_node_x = tree.child(min_idx, 1)+grow_distance* cos(angle);% 生成新的节点 new_node_y = tree.child(min_idx, 2)+grow_distance* sin(angle); new_node = [new_node_x, new_node_y];

接下来需要对该节点进行判断:

① 新节点是否在障碍物范围内;

② 新节点和父节点的连线线段是否和障碍物有重合部分。

若任意一点不满足,则将标志位置为0。实际上可以将两个判断结合,即判断新节点和父节点的连线线段上的点是否在障碍物范围内。

fork= 1: 1:size(ob, 1) fori=min(tree.child(min_idx, 1),new_node_x): 0.01:max(tree.child(min_idx, 1),new_node_x) % 判断生长之后路径与障碍物有无交叉部分 j = (tree.child(min_idx, 2) - new_node_y)/(tree.child(min_idx, 1) - new_node_x) *(i - new_node_x) + new_node_y; if(i >=ob(k, 1)-resolution && i <= ob(k, 1)+ob(k, 3) && j >= ob(k, 2)-resolution && j <= ob(k, 2)+ob(k, 4)) flag = 0; break end end end

在这我采用的方法是写出新节点和父节点连线的直线方程,然后将x变化范围限制在min(tree.child(min_idx,1),new_node_x)max(tree.child(min_idx,1),new_node_x)内,0.01即坐标变换的步长,步长越小判断的越精确,但同时会增加计算量;

步长越大计算速度快但是很可能出现误判,如下图所式。

左图:合适的步长 右图:步长过大

判断标志位若为1,则可以将该新节点加入到tree中,注意保存新节点和它的父节点,同时显示在figure中,之后重置标志位。

if(flag == true) % 若标志位为 1,则可以将该新节点加入tree中 tree.child(end+ 1,:) = new_node; tree.parent(end+ 1,:) = [tree.child(min_idx, 1), tree.child(min_idx, 2)]; plot(rd_x, rd_y, '.r'); hold on plot(new_node_x, new_node_y, '.g') ; hold on plot([tree.child(min_idx, 1),new_node_x], [tree.child(min_idx, 2),new_node_y], '-b') ; end flag = 1; % 标志位归位

最后就是把障碍物、起点终点等显示在figure中,并判断新节点到目标点距离。若小于阈值则停止搜索,并将目标点加入到node中,否则重复该过程直至找到目标点。

%% 显示 fori= 1: 1:size(ob, 1) % 绘制障碍物 fill([ob(i, 1)-resolution, ob(i, 1)+ob(i, 3),ob(i, 1)+ob(i, 3),ob(i, 1)-resolution],... [ob(i, 2)-resolution,ob(i, 2)-resolution,ob(i, 2)+ob(i, 4),ob(i, 2)+ob(i, 4)], 'k'); end hold on plot(x_start( 1, 1) -0.5*resolution, x_start( 1, 2) -0.5*resolution, 'b^', 'MarkerFaceColor', 'b', 'MarkerSize', 4*resolution) ; % 起点 plot(goal( 1, 1) -0.5*resolution, goal( 1, 2) -0.5*resolution, 'm^', 'MarkerFaceColor', 'm', 'MarkerSize', 4*resolution); % 终点 set(gca, 'XLim',[x_left_limit x_right_limit]); % X轴的数据显示范围 set(gca, 'XTick',[x_left_limit:resolution:x_right_limit]); % 设置要显示坐标刻度 set(gca, 'YLim',[y_left_limit y_right_limit]); % Y轴的数据显示范围 set(gca, 'YTick',[y_left_limit:resolution:y_right_limit]); % 设置要显示坐标刻度 grid on title( 'D-RRT') ; xlabel( '横坐标 x'); ylabel( '纵坐标 y'); pause( 0.05); if( sqrt((new_node_x - goal( 1, 1))^ 2+ (new_node_y- goal( 1, 2))^ 2) <= goal_radius) % 若新节点到目标点距离小于阈值,则停止搜索,并将目标点加入到node中 tree.child(end+ 1,:) = goal; % 把终点加入到树中 tree.parent(end+ 1,:) = new_node; disp( 'find goal!'); break end

5、绘制最优路径

从目标点开始,依次根据节点及父节点回推规划的路径直至起点,要注意tree结构体中parent的长度比child要小1。最后将规划的路径显示在figure中。

%% 绘制最优路径 temp = tree.parent(end,:); trajectory = [tree.child(end, 1) -0.5*resolution, tree.child(end, 2) -0.5*resolution]; fori=size(tree.child, 1): -1: 2 if(size(tree.child(i,:), 2) ~= 0& tree.child(i,:) == temp) temp = tree.parent(i -1,:); trajectory(end+ 1,:) = tree.child(i,:); if(temp == x_start) trajectory(end+ 1,:) = [temp( 1, 1) - 0.5*resolution, temp( 1, 2) - 0.5*resolution]; end end end plot(trajectory(:, 1), trajectory(:, 2), '-r', 'LineWidth', 2) ; pause( 2);

程序运行最终效果如下:

红点都是生成点随机点,绿点是tree中节点,红色路径即为RRT算法规划的路径。

6、路径平滑(B样条曲线)

由于规划的路径都是线段连接,在节点处路径不平滑,这也是RRT算法的弊端之一。一般来说轨迹平滑的方法有很多种,类似于贝塞尔曲线,B样条曲线等。

我在这采用B样条曲线对规划的路径进行平滑处理,具体的方法和原理我后续有时间再进行说明,这里先给出结果:

黑色曲线即位平滑处理后的路径。

多组结果对比

① 相邻两次仿真结果对比:

可以看出由于随机采样的原因,任意两次规划的路径都是不一样的。

② 复杂环境下的路径规划。选取一个相对复杂的环境,仿真结果如下:

可以看出RRT算法可以很好解决复杂环境下的路径规划问题。

③ 狭窄通道下的路径规划。选取一个狭窄通道环境,仿真结果如下:

由于环境采样的随机性,在狭长通道内生成随机点的概率相对较低,导致可能无法规划出路径。

结语

由最终仿真结果可以看出,RRT算法通过对空间的随机采样可以规划出一条从起点到终点的路径,规划速度很快,同时不依赖于环境。但规划过程随机性很强,没有目的性,会产生很多冗余点,且每次规划的路径都不一样,对于狭窄通道可能无法规划出路径。

下篇文章我将对RRT算法的优化提出一些自己的想法,并在现有的程序上进行修改,最终对比改进前后的RRT算法效果。

本文仅用于学术分享,如有侵权联系删除

独家重磅课程官网:cvlife.net

全国最大的机器人SLAM开发者社区

技术交流群

— 版权声明 —

本公众号原创内容版权属计算机视觉life所有;从公开渠道收集、整理及授权转载的非原创文字、图片和音视频资料,版权属原作者。如果侵权,请联系我们,会及时删除返回搜狐,查看更多

责任编辑:

平台声明:该文观点仅代表作者本人,搜狐号系信息发布平台,搜狐仅提供信息存储空间服务。
阅读 ()
大家都在看
推荐阅读

深圳SEO优化公司潍坊外贸网站建设推荐永新百度竞价报价天水百度关键词包年推广推荐塔城网站优化推广公司垦利百搜标王推荐吉祥建站龙岗网络广告推广多少钱南平网站建设报价舟山网站推广工具推荐怀化推广网站推荐大庆关键词排名价格泸州网站推广系统价格果洛网站改版多少钱乐山网站建设设计报价湛江建网站坪地设计网站哪家好合肥网站改版价格中山百度网站优化排名公司辽源英文网站建设多少钱贵港百度竞价推荐蚌埠百搜标王推荐同乐网站推广工具多少钱烟台建站推荐绵阳网站制作哪家好延安设计网站推荐马鞍山百度爱采购多少钱喀什网站排名优化报价包头营销型网站建设公司驻马店模板网站建设公司株洲百度竞价包年推广推荐歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

深圳SEO优化公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化