ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

PythonRobotics 弹性带(Elastic Bands)路径规划:从气泡模型到力驱动形变的完整实现指南

PythonRobotics 弹性带(Elastic Bands)路径规划:从气泡模型到力驱动形变的完整实现指南 PythonRobotics 弹性带Elastic Bands路径规划从气泡模型到力驱动形变的完整实现指南【免费下载链接】PythonRoboticsPython sample codes and textbook for robotics algorithms.项目地址: https://gitcode.com/GitHub_Trending/py/PythonRobotics弹性带Elastic Bands是一种把全局路径规划与局部避障衔接起来的经典算法先用全局规划器生成一条无碰撞的粗路径再将其建模为一条由气泡Bubble串成的弹性带在收缩力与排斥力的共同作用下动态形变最终得到既平滑、又远离障碍物的可行路径。本文以 PythonRobotics 仓库中 ElasticBands 模块 的实现为主线完整讲解气泡表示、人工势力场公式、重叠约束维护机制并给出可直接运行的参数配置与源码级解读读完即可在自己的机器人运动规划任务中复现与调参。1. Elastic Bands 是什么弹性带是一条由全局规划器初始化、可在环境中动态变形的无碰撞路径。与一次性输出固定路径的规划器不同弹性带把路径当作有弹性的带子当障碍物环境发生变化或路径需要调整时带子会在人工力的作用下持续变形始终维持无碰撞、尽量短、尽量平滑、尽量远离障碍物的四个目标。在 PythonRobotics 中该功能由 PathPlanning/ElasticBands/elastic_bands.py 提供其核心目标可归纳为缩短并平滑路径去除全局规划结果中的冗余绕行与折线最大化与障碍物的间距让路径尽量保持在自由空间中央维持全局路径的连通性起点、终点始终固定中间节点动态调整但不断链。2. 气泡Bubble表示路径的局部自由空间弹性带的核心数据结构是气泡。定义上配置点 :math:b处的一个气泡是该点附近的局部自由空间区域B(b) { q : ‖q − b‖ ρ(b) }其中 ρ(b) 是气泡半径表示从配置点 b 到最近障碍物的安全距离。路径上的每个节点都携带一个气泡整条路径就等价于一条气泡链bubble chain——相邻气泡是否重叠直接决定了路径的连续性与安全性。在源码中气泡由Bubble类实现并对半径做了上下限约束elastic_bands.py 第 42–49 行class Bubble: def __init__(self, position, radius): self.pos np.array(position) # Bubble center coordinates [x, y] self.radius radius # Safety distance radius ρ(b) if self.radius MAX_BUBBLE_RADIUS: self.radius MAX_BUBBLE_RADIUS if self.radius MIN_BUBBLE_RADIUS: self.radius MIN_BUBBLE_RADIUS半径 ρ(b) 并不是手动指定的而是直接从**带符号距离场SDF**中查询得到def compute_rho(self, position): Compute the distance field value at the position return self.distance_map[int(position[0]), int(position[1])]distance_map由 Mapping/DistanceMap/distance_map.py 中的compute_sdf_scipy一次性预计算elastic_bands.py 第 63 行。该函数利用scipy.ndimage.distance_transform_edt同时计算障碍物→自由空间与自由空间→障碍物两个方向的欧氏距离变换并相减得到正值为到最近障碍物距离、负值为深入障碍物内部的带符号距离场。相比纯 Python 实现的compute_sdf这一方式在 500×500 地图上可将计算时间从约 3 秒压缩到约 0.05 秒见 distance_map.py 第 20–44 行 的注释。3. 力驱动的路径形变Force-Based Deformation弹性带的形变由两类人工力驱动来自路径自身张力的内部收缩力以及来自障碍物排斥的外部排斥力。两类力叠加后作用于每个中间节点使其位置迭代更新。3.1 内部收缩力Internal Contraction Force收缩力的作用是消除路径冗余、缩短路径长度。对于内部节点 bᵢ它被两侧邻居 bᵢ₋₁ 与 bᵢ₊₁ 沿指向自己的单位方向共同拉动f_c(bᵢ) k_c · ( (bᵢ₋₁ − bᵢ)/‖bᵢ₋₁ − bᵢ‖ (bᵢ₊₁ − bᵢ)/‖bᵢ₊₁ − bᵢ‖ )其中 k_c 为收缩增益。源码实现位于contraction_force方法elastic_bands.py 第 78–90 行首尾节点i 0 或最后一个不参与受力返回零向量从而保证起点与终点固定def contraction_force(self, i): Calculate internal contraction force for the i-th bubble if i 0 or i len(self.bubbles) - 1: return np.zeros(2) prev self.bubbles[i - 1].pos next_ self.bubbles[i 1].pos current self.bubbles[i].pos # f_c kc * ( (prev-current)/|prev-current| (next-current)/|next-current| ) dir_prev (prev - current) / (np.linalg.norm(prev - current) 1e-6) dir_next (next_ - current) / (np.linalg.norm(next_ - current) 1e-6) return self.kc * (dir_prev dir_next)注意实现中对分母加1e-6做了防零保护避免节点重合时除零。3.2 外部排斥力External Repulsion Force排斥力的作用是把路径从障碍物附近推开。仅当气泡半径小于阈值 ρ₀ 时才生效否则返回零f_r(bᵢ) k_r · (ρ₀ − ρ(bᵢ)) · ∇ρ(bᵢ) 若 ρ(bᵢ) ρ₀ f_r(bᵢ) 0 否则其中 k_r 为排斥增益源码中取负值表示沿距离场梯度上升方向、即远离障碍物的方向施力ρ₀ 为排斥力作用的最大距离。距离场梯度 ∇ρ(bᵢ) 通过有限差分近似∂ρ/∂x ≈ (ρ(bᵢ h) − ρ(bᵢ − h)) / (2h)源码实现位于repulsive_force方法elastic_bands.py 第 92–108 行其中步长 h 取模块级常量STEP_SIZEdef repulsive_force(self, i): Calculate external repulsive force for the i-th bubble h self.step_size # Step size b self.bubbles[i].pos rho self.bubbles[i].radius if rho self.rho0: return np.zeros(2) # Finite difference approximation of the gradient ∂ρ/∂b dx np.array([h, 0]) dy np.array([0, h]) grad_x (self.compute_rho(b - dx) - self.compute_rho(b dx)) / (2 * h) grad_y (self.compute_rho(b - dy) - self.compute_rho(b dy)) / (2 * h) grad np.array([grad_x, grad_y]) return self.kr * (self.rho0 - rho) * grad4. 动态路径维护节点更新与重叠约束4.1 节点更新公式每个内部节点按下式迭代更新bᵢ_new bᵢ_old α · (f_c f_r)其中 α 为步长源码中取值为当前气泡半径 ρ(bᵢ_old)即自适应步长离障碍物越远移动越快。对应实现在update_bubbles方法elastic_bands.py 第 110–134 行f_total self.contraction_force(i) self.repulsive_force(i) v self.bubbles[i - 1].pos - self.bubbles[i 1].pos # Remove tangential component f_star f_total - f_total * v * v / (np.linalg.norm(v) ** 2 1e-6) alpha self.bubbles[i].radius # Adaptive step size new_pos self.bubbles[i].pos alpha * f_star new_pos np.clip(new_pos, 0, 499) new_radius self.compute_rho(new_pos)这里有两点值得注意的实现细节切向分量剔除f_star把合力在前后邻居连线方向即路径切向上的分量减掉避免节点沿路径滑动堆积只保留法向形变地图边界裁剪np.clip(new_pos, 0, 499)保证节点不会移出 500×500 的栅格地图边界。4.2 重叠约束Overlap Enforcement为保证气泡链连续、不出现空隙或冗余每次更新后都要执行重叠约束维护_maintain_overlapelastic_bands.py 第 136–162 行插入节点若相邻气泡 bᵢ 与 bⱼ 的中心距大于 λ·(ρᵢ ρⱼ)则在两者中点插入一个新气泡半径仍从距离场查询得到删除节点若气泡 bᵢ 的两侧邻居 bᵢ₋₁ 与 bᵢ₊₁ 的中心距不超过 λ·(ρᵢ₋₁ ρᵢ₊₁)说明 bᵢ 已被覆盖、属于冗余节点将其删除。其中 λ 为重叠约束因子源码默认 0.7。这一过疏则插、过密则删的机制正是弹性带能够自适应节点密度、维持路径连通性的关键# Insert bubbles i 0 while i len(self.bubbles) - 1: bi, bj self.bubbles[i], self.bubbles[i 1] dist np.linalg.norm(bi.pos - bj.pos) if dist self.lambda_ * (bi.radius bj.radius): new_pos (bi.pos bj.pos) / 2 rho self.compute_rho(new_pos) # Calculate new radius using environment model self.bubbles.insert(i 1, Bubble(new_pos, rho)) i 2 # Skip the processed region else: i 1 # Delete redundant bubbles i 1 while i len(self.bubbles) - 1: prev self.bubbles[i - 1] next_ self.bubbles[i 1] dist np.linalg.norm(prev.pos - next_.pos) if dist self.lambda_ * (prev.radius next_.radius): del self.bubbles[i] # Delete if redundant else: i 15. 模块级参数含义与调参建议ElasticBands的默认参数全部以模块级常量定义在 elastic_bands.py 第 22–39 行也可通过构造函数逐个覆盖参数默认值含义调参影响MAX_BUBBLE_RADIUS100气泡半径上限限制单节点最大安全距离防止空旷区域节点移动过快MIN_BUBBLE_RADIUS10气泡半径下限保证节点至少保留最小安全距离防止贴障碍物RHO020.0排斥力最大作用距离 ρ₀越大则越早开始避障路径越远离障碍物KC0.05收缩力增益 k_c越大路径收缩越剧烈但过大可能产生抖动KR−0.1排斥力增益 k_r负值绝对值越大避障越激进过大可能震荡LAMBDA0.7重叠约束因子 λ控制气泡链疏密越小越密、节点越多STEP_SIZE3.0梯度有限差分步长 h影响距离场梯度估计精度MAX_ITER50迭代次数上限决定形变收敛程度与运行耗时构造函数签名elastic_bands.py 第 53–62 行def __init__( self, initial_path, obstacles, rho0RHO0, kcKC, krKR, lambda_LAMBDA, step_sizeSTEP_SIZE, ):构造时传入initial_pathN×2 的路径点数组与obstacles500×500 的 0/1 栅格内部会立即计算距离场、按路径初始化气泡链并执行一次重叠维护。6. 运行示例交互模式与数据回放elastic_bands.py提供了两种运行方式均由ElasticBandsVisualizer承载elastic_bands.py 第 165–298 行方式一数据回放默认。将ENABLE_INTERACTIVE保持为False程序自动加载仓库预置的 path.npy 与 obstacles.npy 作为初始路径和障碍物直接开始 50 轮迭代规划python PathPlanning/ElasticBands/elastic_bands.py运行后弹窗展示路径形变全过程黄色圆点为初始路径点蓝色折线为弹性带路径绿色圆圈为各节点气泡半径即 ρ(b)黑色为障碍物。方式二交互式规划。将ENABLE_INTERACTIVE设为True后左键点击添加障碍物以点击点为中心、边长 30 的方块见add_obstacle右键点击添加路径点中键点击当路径点不少于 2 个时开始规划。若同时把ENABLE_SAVE_DATA设为True交互添加的路径与障碍物会在中键触发规划时保存回path.npy与obstacles.npy供下次回放复用。规划主循环plan_pathelastic_bands.py 第 285–294 行本质上就是对ElasticBands对象反复调用update_bubbles并重绘def plan_path(self): Plan the path initial_path self.path_points # Create an elastic band object and optimize self.elastic_band ElasticBands(initial_path, self.obstacles) for _ in range(MAX_ITER): self.elastic_band.update_bubbles() self.path_points [b.pos for b in self.elastic_band.bubbles] self.plot_background()运行环境依赖见 requirements/requirements.txt核心为numpy、scipy距离场计算与matplotlib可视化。7. 测试验证与源码结构仓库为弹性带模块提供了单元测试 tests/test_elastic_bands.py它从path.npy与obstacles.npy重建障碍物栅格构造ElasticBands对象并调用一次update_bubbles()用于验证构造、距离场查询与节点更新的基本正确性def test_1(): path np.load(PathPlanning/ElasticBands/path.npy) obstacles_points np.load(PathPlanning/ElasticBands/obstacles.npy) obstacles np.zeros((500, 500)) for x, y in obstacles_points: size 30 # Side length of the square half_size size // 2 x_start max(0, x - half_size) x_end min(obstacles.shape[0], x half_size) y_start max(0, y - half_size) y_end min(obstacles.shape[1], y half_size) obstacles[x_start:x_end, y_start:y_end] 1 elastic_bands ElasticBands(path, obstacles) elastic_bands.update_bubbles()可运行pytest tests/test_elastic_bands.py复现验证。整体来看弹性带模块的依赖链非常清晰PathPlanning/ElasticBands/elastic_bands.py (核心算法 可视化) │ 调用 compute_sdf_scipy ▼ Mapping/DistanceMap/distance_map.py (带符号距离场提供 ρ(b) 查询) │ 数据 ▼ PathPlanning/ElasticBands/path.npy、obstacles.npy (预置初始路径与障碍物)该模块也是 docs/modules/5_path_planning/elastic_bands/elastic_bands_main.rst 文档所对应的完整实现属于仓库 PathPlanning 路径规划系列中的一个独立算法样例其余样例见 docs/modules/5_path_planning/path_planning_main.rst。8. 总结与进一步探索弹性带算法把全局路径转化为可实时形变的局部轨迹非常适合动态环境下的路径重规划。其精髓可以概括为三句话用气泡描述局部自由空间ρ(b) 由带符号距离场查询得到天然编码了障碍物信息用人工力场驱动形变收缩力缩短路径、排斥力推开障碍物二者平衡出平滑安全的路径用重叠约束维护连通性过疏插点、过密删点保证气泡链始终连续。如果你对相关主题感兴趣可以在本仓库中继续阅读RRTStar 等全局规划器作为弹性带的初始路径来源、DistanceMap 距离场模块弹性带的环境模型基础以及 docs/modules/5_path_planning/path_planning_main.rst 中规划算法系列的其余内容理解全局规划与局部形变如何配合使用。【免费下载链接】PythonRoboticsPython sample codes and textbook for robotics algorithms.项目地址: https://gitcode.com/GitHub_Trending/py/PythonRobotics创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表