news 2026/6/10 5:33:18

Informed RRT*实现椭圆启发式采样

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Informed RRT*实现椭圆启发式采样

我来为您添加Informed RRT*功能,在找到第一条路径后使用椭圆采样来加速收敛。以下是需要新增的函数和修改:
以下代码只含新增的部分

classRRTStar{private:// 在私有成员变量中添加boolpathFound;doublebestPathCost;std::shared_ptr<Node>goalNode;// ... 其他现有成员public:// 在构造函数中初始化新变量RRTStar(constPoint&start,constPoint&goal,doublestepSize=0.5,doublegoalRadius=0.5,doublesearchRadius=1.0,intmaxIterations=5000):start(start),goal(goal),stepSize(stepSize),goalRadius(goalRadius),searchRadius(searchRadius),maxIterations(maxIterations),nodeCounter(0),gen(rd()),pathFound(false),bestPathCost(std::numeric_limits<double>::max()),goalNode(nullptr){minX=std::min(start.x,goal.x)-5;maxX=std::max(start.x,goal.x)+5;minY=std::min(start.y,goal.y)-5;maxY=std::max(start.y,goal.y)+5;xDist=std::uniform_real_distribution<>(minX,maxX);yDist=std::uniform_real_distribution<>(minY,maxY);addNode(std::make_shared<Node>(0,start,-1,0.0));}// 新增函数:生成椭圆内的随机点PointgenerateEllipseRandomPoint(doublecBest){// cBest是当前最佳路径长度// cMin是起点到终点的直线距离(椭圆焦距距离)doublecMin=start.distanceTo(goal);// 如果cBest小于cMin或未找到路径,返回整个空间的随机点if(cBest<cMin||!pathFound){returngenerateRandomPoint(0.1);}// 计算椭圆中心、旋转角和半轴长度Pointcenter((start.x+goal.x)/2.0,(start.y+goal.y)/2.0);// 椭圆的长轴长度doublea=cBest/2.0;// 计算短轴长度:b = sqrt(cBest² - cMin²) / 2doubleb=std::sqrt(std::pow(cBest,2)-std::pow(cMin,2))/2.0;// 计算旋转角(从起点指向终点)doubletheta=std::atan2(goal.y-start.y,goal.x-start.x);// 在单位圆内生成随机点std::uniform_real_distribution<>angleDist(0.0,2.0*M_PI);std::uniform_real_distribution<>radiusDist(0.0,1.0);doubler=std::sqrt(radiusDist(gen));// 均匀分布在圆内doublephi=angleDist(gen);// 将单位圆内的点映射到椭圆doublex=r*std::cos(phi);doubley=r*std::sin(phi);// 应用椭圆变换:缩放、旋转、平移doubletransformedX=center.x+a*x*std::cos(theta)-b*y*std::sin(theta);doubletransformedY=center.y+a*x*std::sin(theta)+b*y*std::cos(theta);returnPoint(transformedX,transformedY);}// 修改后的generateRandomPoint函数,添加椭圆采样逻辑PointgenerateRandomPoint(doublegoalBias=0.1){// 如果已经找到路径,使用椭圆采样if(pathFound){// 10%的概率使用原始采样策略,90%的概率使用椭圆采样std::uniform_real_distribution<>strategyDist(0.0,1.0);if(strategyDist(gen)<0.9){returngenerateEllipseRandomPoint(bestPathCost);}}// 原始采样策略std::uniform_real_distribution<>biasDist(0.0,1.0);if(biasDist(gen)<goalBias){returngoal;}returnPoint(xDist(gen),yDist(gen));}// 新增函数:更新最佳路径voidupdateBestPath(std::shared_ptr<Node>newGoalNode){if(newGoalNode){doublenewCost=newGoalNode->getCost();if(newCost<bestPathCost){bestPathCost=newCost;goalNode=newGoalNode;pathFound=true;std::cout<<"更新最佳路径,成本: "<<bestPathCost<<std::endl;// 动态调整搜索半径(可选)// searchRadius = std::min(10.0 * stepSize,// std::max(stepSize, bestPathCost / 10.0));}}}// 修改后的plan函数,包含Informed RRT*逻辑boolplan(){for(inti=0;i<maxIterations;i++){// 1. 生成随机点(现在会根据是否找到路径选择采样策略)Point randPoint=generateRandomPoint();// 2. 找到最近的节点autonearestNode=findNearestNode(randPoint);// 3. 生成新节点Point newPoint=steer(nearestNode->getPosition(),randPoint);// 4. 检查路径是否无碰撞if(!isPathCollisionFree(nearestNode->getPosition(),newPoint)){continue;}// 5. 查找附近的节点autonearNodes=findNearNodes(newPoint,searchRadius);// 6. 选择最佳父节点std::shared_ptr<Node>bestParent=nearestNode;doubleminCost=nearestNode->getCost()+nearestNode->getPosition().distanceTo(newPoint);for(auto&node:nearNodes){doublenewCost=node->getCost()+node->getPosition().distanceTo(newPoint);if(newCost<minCost&&isPathCollisionFree(node->getPosition(),newPoint)){minCost=newCost;bestParent=node;}}// 7. 创建新节点intnewNodeId=++nodeCounter;autonewNode=std::make_shared<Node>(newNodeId,newPoint,bestParent->getId(),minCost);addNode(newNode);// 8. 重新连接for(auto&node:nearNodes){if(node->getId()==bestParent->getId()){continue;}doublepotentialCost=newNode->getCost()+newNode->getPosition().distanceTo(node->getPosition());if(potentialCost<node->getCost()&&isPathCollisionFree(newNode->getPosition(),node->getPosition())){node->setParentId(newNode->getId());node->setCost(potentialCost);// 如果被重新连接的节点是目标节点的祖先,需要更新目标节点成本if(goalNode&&isDescendantOf(node,goalNode)){updateGoalNodeCost();}}}// 9. 检查是否到达目标if(newPoint.distanceTo(goal)<=goalRadius){if(isPathCollisionFree(newPoint,goal)){// 添加目标节点intgoalNodeId=++nodeCounter;doublegoalCost=newNode->getCost()+newPoint.distanceTo(goal);autonewGoalNode=std::make_shared<Node>(goalNodeId,goal,newNode->getId(),goalCost);addNode(newGoalNode);// 更新最佳路径updateBestPath(newGoalNode);if(!pathFound){std::cout<<"找到第一条路径!迭代次数: "<<i+1<<",成本: "<<goalCost<<std::endl;pathFound=true;bestPathCost=goalCost;goalNode=newGoalNode;}}}// 每100次迭代打印进度if((i+1)%1000==0){std::cout<<"迭代 "<<i+1;if(pathFound){std::cout<<",当前最佳路径成本: "<<bestPathCost;}std::cout<<std::endl;}}if(pathFound){std::cout<<"\n最终最佳路径成本: "<<bestPathCost<<std::endl;returntrue;}else{std::cout<<"未找到路径,达到最大迭代次数"<<std::endl;returnfalse;}}// 新增函数:检查一个节点是否是另一个节点的后代boolisDescendantOf(std::shared_ptr<Node>ancestor,std::shared_ptr<Node>descendant){autocurrent=descendant;while(current){if(current->getId()==ancestor->getId()){returntrue;}if(current->getParentId()==-1){break;}current=tree[current->getParentId()];}returnfalse;}// 新增函数:更新目标节点成本(当重新连接影响目标节点路径时)voidupdateGoalNodeCost(){if(!goalNode)return;doublenewCost=0.0;autocurrent=goalNode;std::vector<std::shared_ptr<Node>>pathNodes;// 收集路径上的所有节点while(current){pathNodes.push_back(current);if(current->getParentId()==-1){break;}current=tree[current->getParentId()];}// 反向计算累积成本std::reverse(pathNodes.begin(),pathNodes.end());newCost=0.0;for(size_t i=0;i<pathNodes.size();i++){if(i>0){newCost+=pathNodes[i-1]->getPosition().distanceTo(pathNodes[i]->getPosition());pathNodes[i]->setCost(newCost);}else{pathNodes[i]->setCost(0.0);}}// 如果成本有改善,更新最佳路径if(newCost<bestPathCost){bestPathCost=newCost;std::cout<<"通过重新连接优化路径,新成本: "<<bestPathCost<<std::endl;}}// 修改后的getPath函数std::vector<Point>getPath(){std::vector<Point>path;if(!goalNode){// 如果没有设置goalNode,尝试查找for(constauto&pair:tree){if(pair.second->getPosition().distanceTo(goal)<=goalRadius){goalNode=pair.second;break;}}}if(!goalNode){returnpath;}// 反向追踪路径autocurrent=goalNode;while(current){path.push_back(current->getPosition());if(current->getParentId()==-1){break;}current=tree[current->getParentId()];}std::reverse(path.begin(),path.end());returnpath;}// 新增函数:获取当前最佳路径成本doublegetBestPathCost()const{returnbestPathCost;}// 新增函数:检查是否已找到路径boolisPathFound()const{returnpathFound;}// 新增函数:获取椭圆采样区域信息(用于可视化)voidgetEllipseInfo(double&a,double&b,double&theta,Point&center)const{doublecMin=start.distanceTo(goal);center=Point((start.x+goal.x)/2.0,(start.y+goal.y)/2.0);a=bestPathCost/2.0;b=std::sqrt(std::pow(bestPathCost,2)-std::pow(cMin,2))/2.0;theta=std::atan2(goal.y-start.y,goal.x-start.x);}};

主要新增功能和修改:

  1. 新增成员变量

· pathFound: 标记是否已找到路径
· bestPathCost: 当前最佳路径成本
· goalNode: 指向目标节点的指针

  1. 椭圆采样函数

· generateEllipseRandomPoint(): 在连接起点和终点的椭圆内生成随机点
· 椭圆焦点:起点和终点
· 椭圆长轴长度:当前最佳路径长度
· 短轴长度:根据勾股定理计算

  1. 改进的采样策略

· generateRandomPoint(): 在找到路径后,90%的概率使用椭圆采样,10%的概率使用原始采样
· 这确保了在找到路径后,搜索集中在有希望找到更好路径的区域

  1. 路径更新机制

· updateBestPath(): 当找到新的更好路径时更新状态
· updateGoalNodeCost(): 当重新连接影响目标节点路径时更新成本

  1. 进度监控

· 每1000次迭代打印当前状态
· 显示当前最佳路径成本

  1. 辅助函数

· isDescendantOf(): 检查节点间的祖孙关系
· getEllipseInfo(): 获取椭圆采样区域信息(可用于可视化)

使用示例:

intmain(){Pointstart(0,0);Pointgoal(10,10);RRTStarplanner(start,goal,0.5,0.5,1.5,20000);// ... 添加障碍物和设置边界boolsuccess=planner.plan();if(success){std::vector<Point>path=planner.getPath();std::cout<<"最终路径成本: "<<planner.getBestPathCost()<<std::endl;// 获取椭圆信息(可用于可视化)doublea,b,theta;Point center;if(planner.isPathFound()){planner.getEllipseInfo(a,b,theta,center);std::cout<<"椭圆采样区域 - 中心: ("<<center.x<<", "<<center.y<<"), 长轴: "<<a<<", 短轴: "<<b<<", 旋转角: "<<theta<<" rad"<<std::endl;}}return0;}

这个Informed RRT实现能够在找到第一条路径后显著加速优化过程,通过椭圆采样将搜索集中在有希望找到更好路径的区域,从而比标准RRT更快收敛到最优路径。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/7 5:37:05

拿一句 “油腻情话”,把你家男人甜到起鸡皮疙瘩

1️⃣ 你能帮我递个东西吗&#xff1f;递什么&#xff1f;递我的真心给你呀&#xff5e;2️⃣ 你是属磁铁的吧&#xff1f;不然我怎么老想黏着你&#xff01;3️⃣ 今天喝了杯奶茶&#xff0c;什么茶&#xff1f;想你想到茶不思饭不想&#xff5e;4️⃣ 我最近在练一项技能&…

作者头像 李华
网站建设 2026/6/6 0:40:39

AI产品经理转型+大模型实战:收藏这套系统化学习资源,小白也能变专家

文章介绍AI产品经理职责、与传统产品经理的区别(需懂技术)、类型分类及必备技能&#xff0c;重点分享AI大模型学习资源&#xff0c;包括七阶段学习路线、300视频教程、数百本技术文档和面试题&#xff0c;帮助小白和程序员系统掌握大模型应用开发技能。1.AI产品经理是什么 回答…

作者头像 李华
网站建设 2026/6/7 20:02:22

基于Vue的电商后台管理系统的设计与实现qyf0i(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末

系统程序文件列表 系统功能 用户,商品分类,品牌信息,商家,商品信息,促销商品,咨询商家 开题报告内容 《基于Vue的电商后台管理系统的设计与实现》开题报告 一、选题背景、研究意义及国内外研究现状 1. 选题背景 随着互联网技术的快速发展和数字化转型的深入推进&#xff0…

作者头像 李华
网站建设 2026/6/9 14:08:34

RK3568 Android14 集成 HYM8563 外部 RTC (I2C接口)

RK3568 Android14 集成 HYM8563 外部 RTC (I2C接口) 前言 虽然 RK3568 SoC 内部自带了 RTC 控制器&#xff08;rtc-rkw808&#xff09;&#xff0c;但在很多工业板卡或手持设备设计中&#xff0c;为了更低的待机功耗和更灵活的电池备份方案&#xff0c;硬件工程师往往会选择外挂…

作者头像 李华
网站建设 2026/6/10 5:28:27

进程的状态及其 CPU 占用

1. R —— 唯一的 CPU 消费者这是最直观的状态&#xff0c;但这里有一个必须厘清的概念。定义&#xff1a;在内核源码中&#xff0c;R 并不意味着进程一定正在 CPU 上跑。它表明进程“要么是在运行中&#xff0c;要么在运行队列 (runqueue) 里” 。对 CPU 的占用&#xff1a;正…

作者头像 李华