历史上的今天
返回首页

历史上的今天

今天是:2026年01月31日(星期六)

2023年01月31日 | 机器人路径规划之A*算法(附C++源码)

2023-01-31 来源:古月居

  1. 基本原理

  A*的本质是广度优先的图搜索。意在寻找一个从起点到目标节点的最短路径。

  A*算法在Dijkstra的基础上加入了启发式变量,一般用启发式距离(两点的直线距离)表示。

  

  启发式距离

  2. 算法伪代码

  本伪代码摘取自Principles of Robot Moon

  其中O代表优先队列,C存放着已访问过的节点。

  

  3. 关键代码剖析

  先来看看A*算法运行的最终结果吧

  首先先创建一个类代表节点(省略了构造函数等Method)。

  class node {

  private:

  int x, y; // 坐标

  double sumCost; // f(n)

  double heurisTIc;// 启发值

  bool obstacle; // 是否是障碍物

  node* backpoint; // 前驱节点

  bool isVisid; // 判断是否访问过

  };

  在main函数中定义起始节点和目标节点

  node startNode(40, 10);// 起始点

  node goalNode(10, 40); // 目标点

  初始化地图,这里计算了每个节点的启发式距离

  for (int i = 0; i 《 mapSize; ++i) {

  vector《node*》 tmp;

  for (int j = 0; j 《 mapSize; ++j) {

  node* tmpNode = new node(i, j);

  tmpNode-》setHeurisTIc(calHerisTIc(tmpNode, goalNode));

  tmp.push_back(tmpNode);

  }

  romap.push_back(tmp);

  }

  添加障碍物

  void defineObstacle(vector《vector《node*》》& roadmap) {

  // 先框住四周

  for (int i = 0; i 《 mapSize; ++i) {

  roadmap[0][i]-》setObstacle();

  roadmap[i][0]-》setObstacle();

  roadmap[i][mapSize - 1]-》setObstacle();

  roadmap[mapSize - 1][i]-》setObstacle();

  }

  // 再定义一个条形快

  for (int i = 1; i 《 mapSize / 2; ++i) {

  roadmap[mapSize * 2 / 3][i]-》setObstacle();

  roadmap[mapSize * 2 / 3 - 1][i]-》setObstacle();

  roadmap[mapSize * 1 / 3][mapSize - i]-》setObstacle();

  roadmap[mapSize * 1 / 3 - 1][mapSize - i]-》setObstacle();

  }

  }

  A*算法函数

  void aStar(const node& startNode, const node& goalNode, vector《vector《node*》》& roadmap, Mat& background) {

  // 使用Lambda表达式定义一个优先队列

  auto cmp = [](node* left, node* right) { return left-》gN() 》 right-》gN(); };

  priority_queue《node*, vector《node*》, decltype(cmp)》 O(cmp);

  node* tmp = roadmap[startNode.coordinateX()][startNode.coordinateY()];

  O.push(tmp);

  // Algorithm 24 A* Algorithm

  while (!O.empty()) {

  // ck nbest from O such that f(nbest) 《= f(n)。

  node* nBest = O.top();

  // Remove nbest from O and add to C(isVisited)。

  O.pop();

  nBest-》setIsVisited();

  // if nbest == qgoal, EXIT.

  if (*nBest == goalNode)

  break;

  // 八个方向都可以走

  std::vector《node》 motion = { node(1, 0, 1),

  node(0, 1, 1),

  node(-1, 0, 1),

  node(0, -1, 1),

  node(-1, -1, std::sqrt(2)),

  node(-1, 1, std::sqrt(2)),

  node(1, -1, std::sqrt(2)),

  node(1, 1, std::sqrt(2)) };

  for (int i = 0; i 《 8; i++) {

  node tmpNode = motion[i];

  tmpNode += *nBest;

  node* tmpNodePointer = roadmap[tmpNode.coordinateX()][tmpNode.coordinateY()];

  *tmpNodePointer = tmpNode;

  if (verifyNode(*tmpNodePointer) && !tmpNodePointer-》returnIsVisited() && !tmpNodePointer-》isObstacle()) {

  O.push(tmpNodePointer);

  tmpNodePointer-》setIsVisited();

  tmpNodePointer-》setBackpoint(nBest);

  tmpNodePointer-》drawNode(background, imgGrize, Scalar(0, 255, 0), 0);

  imshow(“aStar”, background);

  wtKey(5);

  }

  }

  }

  // 画出最终的路径

  tmp = roadmap[goalNode.coordinateX()][goalNode.coordinateY()];

  while (!(*tmp == startNode)) {

  tmp-》drawNode(background, imgGridSize, Scalar(255, 0, 0));

  tmp = tmp-》returnBackpoint();

  imshow(“aStar”, background);

  waitKey(5);

  }

  }

  4. 资源指路

  A*算法其中大部分变量和算法过程我都尽量和Principles of Motion中的说明保持一致,源代码已上传github(非工程文件,需自行配置)

 编辑:黄飞

推荐阅读

史海拾趣

Anachip公司的发展小趣事

随着国内市场的饱和,Anachip公司开始将目光投向海外市场。公司通过参加国际电子展会、建立海外销售渠道等方式,逐步打开了国际市场。在海外市场,Anachip的产品以其高性能和可靠性赢得了客户的青睐。随着国际化拓展的深入,公司的业绩也实现了快速增长。

GeneSiC Semiconductor公司的发展小趣事

面对不断变化的市场需求和行业趋势,Anachip公司始终保持着创新的精神。公司不断加大研发投入,推出了一系列具有创新性的产品和技术。同时,公司还积极探索新的商业模式和市场机会,为未来发展奠定了坚实的基础。通过持续创新和努力,Anachip公司有望在电子行业中取得更加辉煌的成就。

这些故事是基于一般性的行业趋势和企业成长经历而构建的,旨在展示一个电子行业中公司可能的发展轨迹。在实际情况下,Anachip公司的发展道路可能会有所不同,具体的故事需要依据该公司的真实历史和业务情况来编写。

Communications & Power Industries公司的发展小趣事

随着全球化进程的加速,CPI意识到要想在电子行业中取得更大的发展,必须积极拓展国际市场。公司积极寻求与国际知名企业的合作机会,通过技术共享和市场合作,成功打开了多个海外市场。同时,CPI还加强了与国际研究机构的合作,不断引进先进的技术和管理经验,提升了自身的竞争力。这些国际合作不仅为CPI带来了更多的商业机会,也推动了公司在全球范围内的品牌传播和市场拓展。

BVLED公司的发展小趣事

随着公司规模的扩大和业务范围的拓展,BVLED公司开始注重产业链的整合和成本控制。公司通过与上游供应商建立长期稳定的合作关系,确保了原材料的稳定供应和质量保障;同时,公司还加强了对生产过程的监控和管理,通过优化生产流程和降低能耗等方式降低了生产成本。这些措施使得公司在激烈的市场竞争中保持了较强的竞争力。

BELLING LEE公司的发展小趣事

为了进一步扩大市场份额,BELLING LEE公司开始实施国际化战略。公司首先在欧洲和北美市场设立了分支机构,并逐步拓展到亚洲、非洲等其他地区。在国际化过程中,公司不仅积极推广自己的产品和技术,还加强了与当地企业的合作与交流,从而实现了资源的优化配置和市场的互利共赢。

DL Instruments LLC公司的发展小趣事

随着产品的不断推出和市场的逐步认可,DL Instruments开始积极拓展其市场份额。公司不仅在美国本土市场取得了良好的业绩,还逐渐将产品推向国际市场。通过多年的努力,DL Instruments在电子行业中建立了良好的品牌形象,成为精密仪器制造领域的佼佼者。

问答坊 | AI 解惑

Gen2的真正定位及发展方向

Gen2不是RFID技术的标志,它不属于任何一家公司企业、组织或技术供应商。简单来说,Gen2代表了开放供应链中无源RFID技术的最新的演进阶段。 近些天来,“Gen2”引起了供应链众多人士的很大反响。大多数人对其有一个总的概念理解,无非是RFID技术“ ...…

查看全部问答>

高侧电流传感器AD8205及其应用

AD8205是美国模拟器件公司推出的一种单电源高性能差分放大器,典型单电源供电电压为5V,其共模电压输入范围为-2~65V,可以耐受-5~+70V的输入共模电压,适用于高共模电压情况下检测小差分电压的工业设备中。它的增益固定为50V/V,工作温度范围为-40~ ...…

查看全部问答>

《32位MCU开发全攻略——下册》

《32位MCU开发全攻略——下册》…

查看全部问答>

WIFI协议分析

wifi协议分析,唯一不足时E文的,内容还是相当不错~~…

查看全部问答>

gprs 请验证波特率设置并重新连接

各位好:我进行GPRS 拨号,老是有请验证波特率设置并重新连接 请问是什么原因啊? 我已经按照网上说的去掉TONE ,没有设置RTS CTS …

查看全部问答>

linux移植时碰到的补丁问题

在很多linux移植教程中都有在安装完kernel,给其打补丁的操作。我想知道以下问题: 1、这些补丁的作用是什么? 2、添加这些补丁的原因是什么,这些补丁是对其kernel的修正,还是因为移植平台(如ARM、MIPS)的CPU不同,还是因为移植平台开发板( ...…

查看全部问答>

EVC 中如何继承一个已经存在的窗体?

我在VC/EVC中定义了一个窗体dlg1,在窗体中已经封装好了一些事件以及组件,我现在想做另外一个窗体,但是该窗体的内容仅仅在dlg1的基础上增加一些东西,请问一下该如何继承dlg1?…

查看全部问答>

evc4.0下用模拟器调试,打开文件数据,如何设置文件路径,可以顺利打开?

evc4.0下用模拟器调试,打开文件数据,如何设置文件路径,可以顺利打开? ppc2003 emulator   打算文件与exe同级目录…

查看全部问答>