移动机器人运动规划
常用地图结构#
occupancy grid map - 栅格地图
- Most Dense;
- Structural;
- Direct Index Query;
octo-map - 栅格地图的优化,在障碍物存在的地方稠密,无障碍物的地方稀疏
- Sparse;
- Structural;
- Indirect Index Query;
voxel hashing - 将坐标哈希化,通过哈希表查询地图信息
- Most Sparse;
- Structural;
- Indirect Index Query;
- Un-ordered;
- No Index Query;
基于图搜索的算法#
基础概念
- 机器人配置(Robot configuration):机器人上所有点的位置的描述;
- 机器人自由度(Robot degree of freedom, DOF):能够表示机器人配置空间最少需要的值的数量;
- 机器人配置空间(Robot configuration space):包含机器人所有可能的配置的 n 维向量空间,又称为 C-space;
- 机器人任何一个可能的位置都是在配置空间中的一个点;
2.1 Graph Search Basis#
算法核心思想
- Maintain a container to store all the nodes to be visited;
- The container is initialized with the start state ;
- Loop:
- Remove a node from the container according to some pre-defined score function;
- Visit a node;
- Expansion: Obtain all neighbors of the node;
- Discover all its neighbors;
- Push them (neighbors) into the container;
- Remove a node from the container according to some pre-defined score function;
- End loop;
Question 1:When to end the loop?
Answer:容器为空,或者目标节点已经被访问到;
Question 2:What if the graph is cyclic?
Answer:维护一个新的容器,存储被访问过的节点,避免节点被再次添加到容器中重复访问;
图的遍历
- 广度优先搜索(Breadth First Search, BFS)
- 先进先出,使用 queue;
- Strategy: 优先移除和扩张容器中最浅的节点;
- 深度优先搜索(Depth First Search, DFS)
- 先进后出,使用 stack;
- Strategy: 优先移除和扩张容器中最深的节点;
Dijkstra 算法#
- Strategy: expand/visit the node with cheapest accumulated cost ;
- :The current best estimates of the accumulated cost from the start state to node ;
- Update the accumulated costs for all unexpanded neighbors of node ;
- A node that has been expanded/visited is guaranteed to have the smallest cost from the start state.
算法流程:
- 初始时,S 集只包含起点 s,U 集包含除 s 外的其他节点,U 集中的节点 v 与起点 s 相邻,则该节点存储值为距起点 s 的距离,若与起点 s 不相邻,则距离为无限大;
- 从 U 集中选出距离起点最短的节点 k,并将节点 k 加入到 S 集中,同时从 U 集中移除节点 k;
- 更新 U 集中各个节点到起点 s 的距离。之所以更新 U 集中节点的距离,是因为由于上一步确定了节点 k 是求出最短路径的节点,从而可以利用节点 k 来更新其他节点的距离;例如,(s, v)的距离可能大于(s, k) + (k, v)的距离。
- 重复步骤 2 和步骤 3,直到遍历完所有节点。
2.3 A star 算法#
算法简介:
- A*算法是一种静态路网中求解最短路径最有效的直接搜索方法。广泛应用于室内机器人的路径搜索、游戏动画路径搜索等;
- A*算法结合了贪心算法(深度优先)和 Dijkstra 算法(广度优先),是一种启发式的搜索算法;
- 路径优劣评价公式为:,是在状态空间中从初始状态到状态 的实际代价,是从状态 到目标状态的最佳路径的估计代价。
- A*算法使用了两个状态表,分别称为OpenList和CloseList,OpenList存储待考察的节点,CloseList存储已考察过的节点。
地图预处理:
- 将地图栅格化,把每一个正方形格子的中央称为节点;
- 确定栅格属性,即每一个格子有两种状态:可走和不可走;
- 定义两个列表集合:OpenList 和 CloseList,OpenList 可以存储节点的 g 值;
- 确定起始节点和目标节点。
A* 算法流程:
- 初始时,定义起始节点为父节点,移入 CloseList 中;
- 逐个检查与父节点 相邻的周围的节点 ,忽略不可走节点和已经存在于 CloseList 中的节点:
- 若节点 不在 OpenList 中,则将节点 的父节点记为节点 ,计算节点 到节点 的距离 ,计算 ,并把它们加入到 OpenList 中成为待考察的对象;
- 若节点 已经在 OpenList 中,则检查这条路径是否更优,即经由节点 到达节点 是否有更小的 值:计算节点 到节点 的距离 ,若 小于 OpenList 中节点 存储的 ,则这条路径更优,更新 OpenList 中节点 存储的 值 ,并将节点 的父节点记为节点 ,若这条路径不是更优,则不进行任何操作;
- 计算 OpenList 中所有节点的 值:,从 OpenList 中取出 值最小的节点,放到 CloseList 中,并把它作为新的父节点 ;
- 这里启发式函数 一般用曼哈顿距离或者欧氏距离来替代。
- 重复步骤 2 和步骤 3,不断重复,直到搜索到目标节点,完成路径搜索。搜索出路径的结果可以直接遍历父节点得到。
Question 1:欧式距离(L2)作为启发式函数一定是最优的吗?
Amswer:是的
Question 2:曼哈顿(L1)作为启发式函数一定是最优的吗?
Amswer:不一定
Question 3: 作为启发式函数一定是最优的吗?
Amswer:是
Question 4:常值 0 作为启发式函数一定是最优的吗?
Amswer:退化成 Dijkstra 算法,保证最优
思考:
- 如果启发式函数 ,即启发式函数估计的距离小于真实距离,则保证路径的最优性。如果设计出的 ,可以视为更加贪心,牺牲路径的最优性来换取计算时间,这就是 weight A*。
weighted A*:
将 A* 中的 替换为 ,以牺牲路径最优性来换取计算时间上的效率。
若有 ,则:
- , 时为最贪心的路径;
- , 时为偏向贪心的路径;
- , 时为最优路径;
- , 时退化为 Dijkstra 算法;
Tie Breaker:
在寻找路径时,有时会出现多个节点的 相同的情况,这可能会在搜索的过程中导致 expand 很多节点,导致搜索效率低下。
解决:
- 方案一:当几个节点拥有相同的 值时,对 进行比较;
- 方案二:我们倾向于对角线抵达终点,在计算 时进行如下修正:
Jump Point Search 算法#
与 A* 的区别:
- A* 在扩张时考虑自然的邻居节点,而 JPS 考虑的是跳跃的邻居点;
- JPS 可以在空旷的区域进行大范围的跳跃;
Question:JPS 一定比 A* 好吗?
Answer:不是,如果在障碍物多的场景,JPS 具有较好的效果,但是如果在障碍物较少的场景,JPS 需要扩展大量的节点;
总结:
- 在大多数情况下,尤其是复杂环境,JPS 的效果比 A*好,因为 JPS 减少了加入到 Open List 中节点的数量,减少了内存消耗,和 Open List 中排序的次数等,但是 JPS 增加了对地图中节点状态(有无障碍物)查询的次数;
- JPS 只适用于 uniform grid map;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET10 - 预览版1新功能体验(一)