超快速的路径优化IKD-SWOpt:SHIFT Planner 中增量 KD 树滑动窗口优化算法详解
IKD-SWOpt:SHIFT Planner 中增量 KD 树滑动窗口优化算法详解
今天本博主王婆卖瓜自卖自夸😄,介绍自己paper中的算法,本算法已经持续开源中(部分关键内容)Github,之前很多读者朋友一直说要详细讲讲路径优化算法,我这篇paper中的一个叫IKD-SWOpt的模块创新性的使用IKDtree改进的Astar给出比较好的初始路径,并通过滑动窗口检测需要优化的轨迹段进行无精度损失的轨迹优化算法,其内存开销及优化速度都打到了SOTA水平,在内存及计算资源极其有限的环境下也可以运行。github代码地址如下:SHIFTPlanner-Robotics SHIFT-Planner 可以点个小星星🌟支持下,今天就讲解下这部分轨迹优化内容。

图1:SHIFT Planner 系统架构
本算法使机器人能够高效且安全地在复杂环境中导航。Incremental IKD-tree Sliding Window Optimization (IKD-SWOpt) 算法,这是我们 SHIFT Planner 框架的核心部分。我们将从理论基础和实际实现两个方面,全面解析 IKD-SWOpt 在动态障碍物避让和路径优化中的作用。
在路径优化过程中,IKD-SWOpt(增量 KD 树滑动窗口优化)算法通过结合障碍物避免、路径平滑以及局部搜索来优化路径。
1. 路径优化目标
IKD-SWOpt 的核心目标是优化路径,使其更加平滑、短且避开障碍物。假设有一个由一系列路径点组成的路径,我们的优化目标可以分为以下几个部分:
- 路径长度最小化: 我们希望路径尽量短,以减少机器人行驶的距离。
- 避障性最大化: 路径应尽量避开障碍物,以确保机器人安全。
- 平滑性最大化: 路径应尽量平滑,避免过多的急转弯,减少机器人运动的能量消耗。
在数学上,路径优化可以通过一个包含多个目标的优化函数表示。该函数通常是一个带有约束条件的加权和。
2. 路径优化的数学公式
目标函数:
L ( P ) = λ 1 ⋅ L path ( P ) + λ 2 ⋅ L obstacle ( P ) + λ 3 ⋅ L smoothing ( P ) \mathcal{L}(P) = \lambda_1 \cdot \mathcal{L}_{\text{path}}(P) + \lambda_2 \cdot \mathcal{L}_{\text{obstacle}}(P) + \lambda_3 \cdot \mathcal{L}_{\text{smoothing}}(P) L(P)=λ1⋅Lpath(P)+λ2⋅Lobstacle(P)+λ3⋅Lsmoothing(P)
表示路径长度:
L path ( P ) = ∑ i = 1 n − 1 ∥ p i + 1 − p i ∥ \mathcal{L}_{\text{path}}(P) = \sum_{i=1}^{n-1} \| p_{i+1} - p_i \| Lpath(P)=i=1∑n−1∥pi+1−pi∥
是路径中相邻点之间的欧几里得距离。
表示路径与障碍物的距离。对于路径中的每一个点,计算该点到最近障碍物的距离。假设障碍物集合为 O O O,那么:
L obstacle ( P ) = ∑ i = 1 n 1 dist ( p i , O ) \mathcal{L}_{\text{obstacle}}(P) = \sum_{i=1}^n \frac{1}{\text{dist}(p_i, O)} Lobstacle(P)=i=1∑ndist(pi,O)1
其中, ( p i , O ) (p_i, O) (pi,O) 是点 p i p_i pi 到障碍物集合 O O O 中最近障碍物的距离。
- L L L是路径平滑项,用来减少路径中的急转弯。通常使用路径上相邻点之间的角度变化量来表示:
L smoothing ( P ) = ∑ i = 2 n − 1 ∥ ( p i + 1 − p i ) − ( p i − p i − 1 ) ∥ \mathcal{L}_{\text{smoothing}}(P) = \sum_{i=2}^{n-1} \| (p_{i+1} - p_i) - (p_i - p_{i-1}) \| Lsmoothing(P)=i=2∑n−1∥(pi+1−pi)−(pi−pi−1)∥
这项控制了路径在转弯处的平滑程度,确保路径不会因为局部的细节变化而出现过于急剧的变化。
加权系数:
- λ 1 , λ 2 , λ 3 \lambda_1, \lambda_2, \lambda_3 λ1,λ2,λ3是加权系数,分别对应路径长度、避障和路径平滑性。通过调整这些系数,可以在优化过程中根据具体需求,决定不同目标之间的权重。
3. 优化过程
IKD-SWOpt 使用增量 KD 树来动态更新障碍物地图,并根据当前的路径局部调整进行优化。具体步骤如下:
-
初始化: 通过 A* 或其他路径规划算法生成初步路径。这个路径可能有不平滑的转折,或者过于接近障碍物。
-
增量优化: 将路径分成若干个子路径(可以是滑动窗口中的一部分路径)。对于每个子路径,使用局部优化算法(如梯度下降、牛顿法等)来优化该路径段,目标是最小化上述目标函数。
-
局部搜索: 通过增量 KD 树实现局部搜索,快速计算路径与障碍物的距离以及路径平滑性。每次优化时,计算增量更新,并根据距离函数调整路径。
-
更新路径: 在每一步优化后,更新路径并继续搜索,直到找到全局最优路径。
-
-
停止条件: 当优化结果满足设定的精度或计算次数达到上限时,停止优化。
4. IKD-SWOpt 中的增量更新
增量更新是 IKD-SWOpt 中的一大特点,主要体现在两个方面:
-
障碍物更新: 随着机器人在环境中移动,障碍物可能会发生变化。增量 KD 树可以动态更新障碍物的空间分布,从而实时调整路径优化。
-
路径调整: 在每次增量优化时,只有路径的局部段需要被优化,而不需要重新计算整个路径。这种方法极大地提高了计算效率,适合在实时系统中应用。
5. 实验验证与可视化(先看效果)

图2:IKD-SWOpt路径可视化距离场环境优化图

图3:IKD-SWOpt路径优化算法效果图
为什么叫IKD-SWOpt
自主机器人在复杂和动态的环境中操作时,路径规划至关重要,路径优化使用ESDF地图实际很花费内存,并且有精度损失(删格化),通过IKDtree动态构建的距离场可以精确的优化出极窄通道的可通行路径。
我的论文 SHIFT Planner 中是一个全新的CCP覆盖路径算法,其中创新性的提出了通过IKDtree来实现初始路径搜索(改进的Astar)还通过IKDtree构建的避障优化项使用LBFGS-B算法来轻量级优化路径,今天就讲讲Incremental IKD-tree Sliding Window Optimization (IKD-SWOpt) 算法。IKD-SWOpt 负责实时路径优化,特别是在机器人遇到意外障碍物的情况下。通过利用增量 KD 树结构,IKD-SWOpt 高效地更新障碍物地图,并在滑动窗口内优化路径,确保路径的安全性和计算效率。
环境设置与障碍物生成
在深入探讨优化算法之前,理解机器人操作的环境至关重要。环境被表示为一个二维网格,随机生成的障碍物模拟了现实世界中机器人需要避开的物体。
代码详解
import numpy as np
import heapq
import random
import matplotlib.pyplot as plt
from matplotlib import animation
from scipy.spatial import KDTree
from scipy.optimize import minimize
from scipy.interpolate import splprep, splev# 设置随机种子以保证结果可复现(可选)
random.seed(42)
np.random.seed(42)# 定义网格大小
grid_size = (100, 100)
grid = np.zeros(grid_size)def generate_obstacle(grid, min_width, max_width, min_height, max_height):"""生成随机矩形障碍物。"""width = random.randint(min_width, max_width)height = random.randint(min_height, max_height)x = random.randint(0, grid.shape[0] - width - 1)y = random.randint(0, grid.shape[1] - height - 1)grid[x:x+width, y:y+height] = 1 # 标记障碍物# 生成多个随机障碍物
for _ in range(50):generate_obstacle(grid, min_width=5, max_width=15, min_height=5, max_height=15)
通过这种方式,创建了一个复杂的环境,包含多个障碍物,模拟了机器人在现实世界中需要导航的复杂场景。
势场计算
势场(Potential Field)表示网格中每个点到最近障碍物的距离。势场在引导机器人远离障碍物并朝目标前进中起着关键作用。
代码详解
def calculate_potential_field(grid):"""计算势场,表示每个点到最近障碍物的距离。"""grid_size = grid.shapedistance_field = np.full(grid_size, np.inf)obstacles = np.argwhere(grid == 1)free_space = np.argwhere(grid == 0)if len(obstacles) > 0:kdtree = KDTree(obstacles)distances, _ = kdtree.query(free_space)for idx, coord in enumerate(free_space):distance_field[tuple(coord)] = distances[idx]else:distance_field[free_space[:,0], free_space[:,1]] = np.infreturn distance_fielddistance_field = calculate_potential_field(grid)
解释:
- 初始化: 初始化一个与网格大小相同的距离场,所有值设为无穷大,表示初始时每个点到障碍物的距离未知。
- 识别障碍物与自由空间: 使用
np.argwhere函数分别找出障碍物和自由空间的坐标。 - KD 树构建与查询: 如果存在障碍物,构建 KD 树以加速最近邻查询。对自由空间中的每个点,查询其到最近障碍物的距离,并更新距离场。这里显示的距离场主要用来显示,实际算法中不需要将其转化成可视化的距离场地图,直接通过树访问即可。
- 返回距离场: 最终得到每个自由空间点到最近障碍物的距离场。
通过这种方式,势场为后续的路径规划提供了关键信息,帮助机器人避开障碍物并高效地接近目标。
结合IKDtree势场的 A* 搜索算法
A* 搜索算法是一种广泛使用的路径规划算法,能够在保证最优性的同时具备较高的效率。在本框架中,A* 算法结合了势场信息,以增强其在复杂环境中的导航能力。

图4:IKDtree距离场地图

图5:IKDtree改进的Astar算法结果图
代码详解
def heuristic(a, b):"""欧几里得距离启发函数。"""return np.linalg.norm(np.array(a) - np.array(b))def a_star_search_with_potential_field(start, goal, grid, distance_field, influence_strength=5.0):"""结合势场的 A* 搜索算法。"""neighbors = [(-1, 0), (1, 0), (0, -1), (0, 1),(-1, -1), (-1, 1), (1, -1), (1, 1)] # 八邻域close_set = set()came_from = {}gscore = {start: 0}fscore = {start: heuristic(start, goal)}oheap = []heapq.heappush(oheap, (fscore[start], start))while oheap:current = heapq.heappop(oheap)[1]if current == goal:# 重建路径data = []while current in came_from:data.append(current)current = came_from[current]data.append(start)data.reverse()return dataclose_set.add(current)for i, j in neighbors:neighbor = current[0] + i, current[1] + jif 0 <= neighbor[0] < grid.shape[0]:if 0 <= neighbor[1] < grid.shape[1]:if grid[neighbor[0]][neighbor[1]] == 1:continueelse:continueelse:continuetentative_gscore = gscore[current] + heuristic(current, neighbor)if neighbor in close_set and tentative_gscore >= gscore.get(neighbor, 0):continueif tentative_gscore < gscore.get(neighbor, float('inf')) or neighbor not in [i[1] for i in oheap]:came_from[neighbor] = currentgscore[neighbor] = tentative_gscorepotential = influence_strength / (distance_field[neighbor[0]][neighbor[1]] + 1e-5)fscore[neighbor] = tentative_gscore + heuristic(neighbor, goal) + potentialheapq.heappush(oheap, (fscore[neighbor], neighbor))return False
解释:
- 启发函数: 使用欧几里得距离作为启发函数,衡量当前节点到目标节点的直线距离。
- 邻域定义: 采用八邻域,允许机器人在水平、垂直和对角方向移动。
- A 算法流程:*
- 开放列表与关闭列表: 使用堆(优先队列)作为开放列表,存储待处理节点;使用集合作为关闭列表,存储已处理节点。
- 节点展开: 从开放列表中取出具有最低 f 值的节点作为当前节点。
- 路径重建: 当当前节点为目标节点时,重建并返回路径。
- 邻居处理: 遍历当前节点的所有邻居节点,计算临时 g 值(从起点到当前节点的实际代价加上从当前节点到邻居节点的代价)。
- f 值计算: f 值结合了 g 值、启发式 h 值和势场的潜在影响。势场通过
influence_strength参数调节,作用是增加靠近障碍物的节点的 f 值,促使算法选择远离障碍物的路径。 - 节点更新与入堆: 若邻居节点的 g 值被优化,则更新其 came_from、gscore 和 fscore,并将其加入开放列表。
通过将势场信息融入 A* 算法的 f 值计算,算法在路径规划时能够更有效地避开障碍物,选择更加安全且高效的路径。
路径优化:IKD-SWOpt
在路径规划的基础上,进一步优化路径以提高其平滑性和安全性是必要的。IKD-SWOpt 算法通过增量 KD 树和滑动窗口优化技术,实时调整路径,确保路径在动态环境中的适应性和效率。
识别优化段
首先,需要识别路径中靠近障碍物的段落,这些段落需要进行优化以避免碰撞并提升路径质量。
代码详解
def min_distance_to_obstacle(point, grid):"""计算点到最近障碍物的距离。"""obstacles = np.argwhere(grid == 1)if len(obstacles) == 0:return np.infkdtree = KDTree(obstacles)dist, _ = kdtree.query(point)return distdef identify_segments_close_to_obstacles(path, grid, threshold):"""识别并合并靠近障碍物的连续路径段。"""indices_to_optimize = []for i, point in enumerate(path):dist = min_distance_to_obstacle(point, grid)if dist < threshold:indices_to_optimize.append(i)# 将相邻的索引合并为连续段segments = []if not indices_to_optimize:return segmentsstart_idx = indices_to_optimize[0]end_idx = indices_to_optimize[0]for idx in indices_to_optimize[1:]:if idx == end_idx + 1:end_idx = idxelse:# 为了平滑,扩展优化段前后各 5 个点segment_start = max(start_idx - 5, 0)segment_end = min(end_idx + 5, len(path) - 1)segments.append((segment_start, path[segment_start:segment_end + 1]))start_idx = idxend_idx = idx# 添加最后一个段segment_start = max(start_idx - 5, 0)segment_end = min(end_idx + 5, len(path) - 1)segments.append((segment_start, path[segment_start:segment_end + 1]))return segments
解释:
- 最小距离计算:
min_distance_to_obstacle函数计算路径中每个点到最近障碍物的距离。若距离小于设定阈值,则认为该点需要优化。 - 识别优化段:
identify_segments_close_to_obstacles函数遍历路径,收集需要优化的点的索引。然后,将相邻的需要优化的点合并为连续的路径段,前后各扩展 5 个点以确保优化段的平滑性。
通过这种方法,确保了优化算法只对靠近障碍物的关键路径段进行处理,减少了计算负担,同时提升了路径的安全性。
IKD-SWOpt 算法
IKD-SWOpt 算法利用增量 KD 树和滑动窗口技术,对识别出的非合规路径段进行实时优化。
代码详解
def compute_total_cost(variables, num_points, start, goal, kdtree, obs_weight=1.0, smooth_weight=0.1, length_weight=0.1):"""计算优化的总成本函数。"""path_points = [np.array(start)]for i in range(num_points - 2):x = variables[2 * i]y = variables[2 * i + 1]path_points.append(np.array([x, y]))path_points.append(np.array(goal))total_cost = 0.0# 平滑性成本for i in range(1, num_points - 1):xi_prev = path_points[i - 1]xi = path_points[i]xi_next = path_points[i + 1]smoothness = np.linalg.norm(xi_prev - 2 * xi + xi_next) ** 2total_cost += smooth_weight * smoothness# 障碍物避让成本for i in range(1, num_points - 1):xi = path_points[i]dist, _ = kdtree.query(xi)obs_cost = obs_weight / (dist + 1e-5)total_cost += obs_cost# 路径长度成本for i in range(num_points - 1):xi = path_points[i]xi_next = path_points[i + 1]length = np.linalg.norm(xi_next - xi)total_cost += length_weight * lengthreturn total_costdef optimize_path_segment_with_scipy(path_segment, grid, obs_weight=1.0, smooth_weight=0.1, length_weight=0.1, max_iterations=100):"""使用 SciPy 对路径段进行优化。"""num_points = len(path_segment)if num_points < 3:return path_segment, [] # 无需优化# 构建 KD 树obstacles = np.argwhere(grid == 1)kdtree = KDTree(obstacles)initial_variables = []for i in range(1, num_points - 1):initial_variables.extend(path_segment[i])bounds = []for _ in range(num_points - 2):bounds.append((0, grid.shape[0] - 1)) # x 范围bounds.append((0, grid.shape[1] - 1)) # y 范围# 记录优化历史以便动画展示path_history = []def callback(variables):path_points = [path_segment[0]]for i in range(num_points - 2):x = variables[2 * i]y = variables[2 * i + 1]path_points.append((x, y))path_points.append(path_segment[-1])path_history.append(path_points.copy())result = minimize(compute_total_cost,initial_variables,args=(num_points, path_segment[0], path_segment[-1], kdtree, obs_weight, smooth_weight, length_weight),method='L-BFGS-B',bounds=bounds,options={'maxiter': max_iterations},callback=callback)optimized_segment = [path_segment[0]]optimized_variables = result.xfor i in range(num_points - 2):x = optimized_variables[2 * i]y = optimized_variables[2 * i + 1]optimized_segment.append((x, y))optimized_segment.append(path_segment[-1])return optimized_segment, path_history
解释:
-
成本函数计算:
compute_total_cost函数计算路径段的总成本,包括平滑性成本、障碍物避让成本和路径长度成本。- 平滑性成本: 通过计算相邻三点的二阶差分,衡量路径的平滑程度。
- 障碍物避让成本: 利用 KD 树快速查询每个点到最近障碍物的距离,并计算避让成本。
- 路径长度成本: 计算路径的总长度,鼓励路径尽可能短。
-
路径段优化:
optimize_path_segment_with_scipy函数使用 SciPy 的minimize函数对路径段进行优化。- 初始变量: 提取需要优化的路径段中间点的坐标作为优化变量。
- 边界设置: 设置每个优化变量的边界,确保优化后的路径点仍在网格范围内。
- 回调函数:
callback函数记录每次迭代后的路径点,用于后续的动画展示。 - 优化过程: 使用 L-BFGS-B 算法进行优化,逐步调整路径点以最小化总成本。
通过这种方法,IKD-SWOpt 能够高效地优化靠近障碍物的路径段,确保路径的安全性和平滑性,同时保持计算效率。
B-样条路径平滑
优化后的路径虽然避开了障碍物,但可能仍存在一定的折线性。为了使路径更加平滑和适合实际机器人运动,使用 B-样条曲线对路径进行平滑处理。
代码详解
def smooth_path_with_spline(path, smoothing_factor=0):"""使用 B-样条平滑路径。"""path = np.array(path)x = path[:, 0]y = path[:, 1]# 去除重复点_, idx = np.unique(path, axis=0, return_index=True)path = path[np.sort(idx)]x = path[:, 0]y = path[:, 1]# 需要至少 4 个点来拟合 B-样条if len(x) < 4:return path# 生成 B-样条参数和控制点tck, u = splprep([x, y], s=smoothing_factor)# 生成更高采样率的平滑曲线unew = np.linspace(0, 1, 500)smooth_x, smooth_y = splev(unew, tck)return list(zip(smooth_x, smooth_y))
解释:
- 路径转换: 将路径转换为 NumPy 数组,并提取 x 和 y 坐标。
- 去重: 去除路径中重复的点,防止 B-样条拟合时出现问题。
- B-样条拟合: 使用 SciPy 的
splprep函数生成 B-样条参数和控制点。smoothing_factor参数控制平滑程度,值越大,曲线越平滑。 - 曲线生成: 使用
splev函数在参数空间内生成更高采样率的平滑曲线点。 - 返回平滑路径: 返回平滑后的路径点列表。
通过 B-样条曲线的拟合,路径变得更加平滑,适合机器人实际运动,提高了运动的连续性和舒适性。
集成与最终路径规划
优化和平滑后的路径需要与原始路径进行整合,形成最终的导航路径。
代码详解
def integrate_path_segments(path, segments_with_indices):"""将优化后的路径段重新整合回整体路径。"""path = list(path) # 确保路径可变# 按起始索引逆序排序,以处理重叠段segments_with_indices.sort(key=lambda x: x[0], reverse=True)for start_idx, optimized_segment, _ in segments_with_indices:end_idx = start_idx + len(optimized_segment)path[start_idx:end_idx] = optimized_segmentreturn path
解释:
- 路径转换: 确保路径是可变的列表类型。
- 段排序: 按照起始索引进行逆序排序,以处理可能的路径段重叠。
- 路径替换: 将优化后的路径段替换回原始路径中相应的位置,形成整体优化后的路径。
通过这种方式,优化后的路径段被有效地整合回整体路径,确保路径的连贯性和优化效果。
可视化
为了更直观地展示路径优化的过程,使用 Matplotlib 的动画功能生成优化过程的动画。可以查看 https://github.com/fanzexuan/SHIFTPlanner-Robotics ,有更解释代码及paper。
代码详解
def animate_optimization(path_history, grid, start, goal, segment_idx):"""创建路径优化过程的动画。"""fig, ax = plt.subplots(figsize=(8, 8))# 绘制障碍物obstacles = np.argwhere(grid == 1)if len(obstacles) > 0:ax.scatter(obstacles[:, 0], obstacles[:, 1], c='lightgray', s=10)# 绘制起点和终点ax.scatter(start[0], start[1], marker='o', color='green', s=100, label='Start')ax.scatter(goal[0], goal[1], marker='*', color='red', s=100, label='Goal')line, = ax.plot([], [], 'b-', linewidth=2, label='Optimizing Segment')def init():line.set_data([], [])return line,def animate(i):path = path_history[i]x, y = zip(*path)line.set_data(x, y)ax.set_title(f'段 {segment_idx} 优化步骤: {i+1}/{len(path_history)}')return line,ani = animation.FuncAnimation(fig, animate, frames=len(path_history), init_func=init,blit=True, interval=200, repeat=False)plt.legend()plt.show()
解释:
- 图形初始化: 创建一个新的图形和轴,设置图形大小。
- 绘制障碍物、起点和终点: 使用散点图绘制障碍物,并用不同的标记和颜色标记起点和终点。
- 动画元素初始化: 初始化一条用于展示优化路径的线条。
- 初始化函数:
init函数清空线条数据,准备动画开始。 - 动画帧函数:
animate函数在每一帧中更新路径点,并在图表标题中显示当前优化步骤。 - 生成动画: 使用
FuncAnimation生成动画,逐帧展示优化过程。 - 显示图例与图形: 显示图例并展示生成的动画。
通过动画,可以直观地观察到路径优化的逐步过程,理解 IKD-SWOpt 如何逐步调整路径以避开障碍物并提升路径质量。
实验验证
为验证 IKD-SWOpt 算法的有效性,进行了多组实验,展示了该算法在不同环境中的表现。
实验设置
- 真实环境: 使用真实机器人在实际场景中进行测试,验证路径规划和优化的效果。
- 仿真环境: 在仿真环境中生成不同复杂度的网格,测试算法的鲁棒性和效率。
- 性能指标: 主要考察路径的平滑性、避障能力、优化时间和计算资源消耗。
结果分析
通过对比优化前后的路径,可以明显看到 IKD-SWOpt 对路径的改善效果。优化后的路径更加平滑,避障能力更强,计算效率也得到了显著提升。
代码详解
def main():# 随机选择起点和终点free_space = np.argwhere(grid == 0)start = tuple(free_space[np.random.choice(len(free_space))])goal = tuple(free_space[np.random.choice(len(free_space))])# 运行 A* 搜索path = a_star_search_with_potential_field(start, goal, grid, distance_field, influence_strength=5.0)if not path:print("未找到路径")return# 识别需要优化的路径段distance_threshold = 3 # 可根据需要调整segments_to_optimize = identify_segments_close_to_obstacles(path, grid, distance_threshold)# 优化每个路径段并收集优化后的段落segments_with_indices = []for idx, (start_idx, segment) in enumerate(segments_to_optimize):optimized_segment, path_history = optimize_path_segment_with_scipy(segment, grid, obs_weight=0.5, smooth_weight=1.5, length_weight=1.0, max_iterations=20)segments_with_indices.append((start_idx, optimized_segment, path_history))# 为每个优化段显示动画animate_optimization(path_history, grid, start, goal, idx+1)# 将优化后的段落整合回整体路径optimized_path = integrate_path_segments(path, segments_with_indices)# 使用 B-样条平滑整体路径smoothed_path = smooth_path_with_spline(optimized_path, smoothing_factor=1.0)# 绘制最终结果fig, ax = plt.subplots(figsize=(10, 10))obstacles = np.argwhere(grid == 1)if len(obstacles) > 0:ax.scatter(obstacles[:, 0], obstacles[:, 1], c='lightgray', s=10)# 绘制起点和终点ax.scatter(start[0], start[1], marker='o', color='green', s=100, label='Start')ax.scatter(goal[0], goal[1], marker='*', color='red', s=100, label='Goal')# 绘制初始路径x_initial, y_initial = zip(*path)ax.plot(x_initial, y_initial, 'r--', linewidth=1, label='初始路径')# 绘制优化后的路径段,使用不同颜色区分colors = ['blue', 'cyan', 'magenta', 'yellow', 'orange']for idx, (start_idx, optimized_segment, _) in enumerate(segments_with_indices):x_opt, y_opt = zip(*optimized_segment)color = colors[idx % len(colors)]ax.plot(x_opt, y_opt, color=color, linewidth=2, label=f'优化段 {idx+1}')# 绘制平滑后的路径x_smooth, y_smooth = zip(*smoothed_path)ax.plot(x_smooth, y_smooth, 'g-', linewidth=2, label='平滑路径')# 可选:绘制切线圆圈以示安全距离for point in path:dist = min_distance_to_obstacle(point, grid)if dist < distance_threshold:circle = plt.Circle((point[0], point[1]), dist, color='orange', fill=False, linestyle='--', linewidth=1)ax.add_patch(circle)ax.set_xlim(0, grid.shape[0])ax.set_ylim(0, grid.shape[1])ax.set_aspect('equal')ax.legend()ax.set_title('带有合并段的路径优化')plt.show()if __name__ == "__main__":main()
解释:
- 起点与终点选择: 从自由空间中随机选择起点和终点。
- A 搜索运行:* 使用结合势场的 A* 算法找到初始路径。
- 识别优化段: 通过设定的距离阈值识别路径中靠近障碍物的段落。
- 路径段优化与动画展示: 对每个需要优化的路径段使用 IKD-SWOpt 算法进行优化,并生成优化过程的动画。
- 路径整合与平滑: 将优化后的路径段整合回整体路径,并使用 B-样条曲线对整条路径进行平滑处理。
- 结果可视化: 绘制障碍物、起点、终点、初始路径、优化路径段和平滑后的路径,并显示安全距离圆圈(可选)。
通过这个主函数,完整地展示了从路径规划、优化到最终路径生成的整个过程,验证了 IKD-SWOpt 算法在复杂环境中的有效性。
实验验证
为了验证 IKD-SWOpt 算法的有效性,进行了多组实验,展示了该算法在不同环境中的表现。
实验设置
- 真实环境: 使用真实机器人在实际场景中进行测试,验证路径规划和优化的效果。
- 仿真环境: 在仿真环境中生成不同复杂度的网格,测试算法的鲁棒性和效率。
- 性能指标: 主要考察路径的平滑性、避障能力、优化时间和计算资源消耗。
实验结果
路径规划效率
通过比较优化前后的路径,可以明显看到 IKD-SWOpt 对路径的改善效果。优化后的路径更加平滑,避障能力更强,计算效率也得到了显著提升。
优化前后的路径对比

图:IKDtree改进的Astar算法结果图
优化性能
优化算法能够有效调整路径段,确保路径在靠近障碍物的区域更加安全和平滑。
性能指标:
- 收敛速度: 优化算法在少量迭代内即可收敛,通常在 10 次迭代内达到最佳结果。
- 安全距离: 优化后的路径能够保持与障碍物的安全距离,避免碰撞风险。
- 计算效率: IKD-SWOpt 相较于传统方法,计算时间减少了约 30%,内存使用量也有所降低。
结论
本文详细介绍了 IKD-SWOpt 算法在 SHIFT Planner 框架中的应用。通过结合增量 KD 树和滑动窗口优化技术,IKD-SWOpt 能够实时优化机器人路径,确保其在复杂和动态环境中的安全性和平滑性。
主要贡献包括:
- 识别优化段: 通过设定距离阈值,精准识别路径中需要优化的段落。
- 增量 KD 树: 利用 KD 树结构加速最近邻查询,提高障碍物避让的效率。
- 滑动窗口优化: 仅对路径中的关键段落进行优化,降低计算负担。
- 路径平滑: 使用 B-样条曲线进一步提升路径的连续性和可行性。
- 实验验证: 多组实验结果展示了 IKD-SWOpt 在不同环境中的优越性能。
后续会继续讲解下其中基于语义地图进行速度分配的RFICP算法内容,感兴趣的可以先去看看paper:SHIFTPlanner。
相关文章:
超快速的路径优化IKD-SWOpt:SHIFT Planner 中增量 KD 树滑动窗口优化算法详解
IKD-SWOpt:SHIFT Planner 中增量 KD 树滑动窗口优化算法详解 今天本博主王婆卖瓜自卖自夸😄,介绍自己paper中的算法,本算法已经持续开源中(部分关键内容)Github,之前很多读者朋友一直说要详细讲讲路径优化算法&#x…...
精读DeepSeek v3技术文档的心得感悟
最近宋大宝同学读完了DeepSeekv3的文档,心中颇多感慨,忍不住想在这里记录一下对这款“业界有望启示未来低精度训练走向”的开源大模型的观察与思考。DeepSeek v3的亮点绝不仅仅是“Float8”或“超长上下文”这么简单,而是贯穿了从数值精度、注…...
【Java数据结构】LinkedList与链表
认识LinkedList LinkedList就是一个链表,它也是实现List接口的一个类。LinkedList就是通过next引用将所有的结点链接起来,所以不需要数组。LinkedList也是以泛型的方法实现的,所以使用这个类都需要实例化对象。 链表分为很多种,比…...
uniapp——微信小程序,从客户端会话选择文件
微信小程序选择文件 文章目录 微信小程序选择文件效果图选择文件返回数据格式 API文档: chooseMessageFile 微信小程序读取文件,请查看 效果图 选择文件 /*** description 从客户端会话选择文件* returns {String} 文件路径*/ const chooseFile () &g…...
【CSS in Depth 2 精译_098】17.3:CSS 动画延迟技术与填充模式设置 + 17.4:通过 CSS 动画传递意图的秘诀
当前内容所在位置(可进入专栏查看其他译好的章节内容) 第五部分 添加动效 ✔️【第 17 章 动画】 ✔️ 17.1 关键帧17.2 3D 变换下的动画设置 17.2.1 添加动画前页面布局的构建17.2.2 为布局添加动画 17.3 动画延迟与填充模式 ✔️17.4 通过动画传递意图…...
Oracle考试多少分算通过?
OCP和OCM认证的考试及格分数并不是固定的,而是根据考试的难度和考生的整体表现来确定。对于OCP认证,考生需要全面掌握考试要求的知识和技能,并在考试中表现出色才有可能通过。而对于OCM认证,考生则需要在每个模块中都达到一定的水…...
在云服务器中编译IDF(ESP32库)
登录云服务器 使用gitee从github上导入仓库 地址GitHub - espressif/esp-idf: Espressif IoT Development Framework. Official development framework for Espressif SoCs. 然后在云服务器中创建目录~/esp 进入路径后使用git clone 下载项目 进入编程指南ESP-IDF 编程指南…...
Oracle 日常巡检
1. 检查服务器状态 1.1. CPU使用情况 1.1.1. top top 命令是 Linux 和 Unix 系统中用于显示实时系统状态的工具,特别是对于监控 CPU 和内存的使用非常有用。 在命令行中输入 top,top 会显示一个实时更新的界面,其中包含系统的关键指标&am…...
机器学习常用术语
目录 概要 机器学习常用术语 1、模型 2、数据集 3、样本与特征 4、向量 5、矩阵 6、假设函数与损失函数 7、拟合、过拟合与欠拟合 8、激活函数(Activation Function) 9、反向传播(Backpropagation) 10、基线(Baseline) 11、批量(Batch) 12、批量大小(Batch Size)…...
springboot507基于Springboot教学管理系统(论文+源码)_kaic
摘 要 传统办法管理信息首先需要花费的时间比较多,其次数据出错率比较高,而且对错误的数据进行更改也比较困难,最后,检索数据费事费力。因此,在计算机上安装教学管理系统软件来发挥其高效地信息处理的作用,…...
工具变量笔记
补充知识 简单介绍工具变量 假设 Y i α β D i ϵ i Y_i\alpha\beta D_i\epsilon_i YiαβDiϵi, where E ( ϵ i ∣ D i ) 0 E(\epsilon_i\mid D_i)0 E(ϵi∣Di)0. 但是通常这个条件不满足。于是假如有这样一个工具变量 Z i Z_i Zi存在的话,满…...
ElasticSearch 统计分析全攻略
在大数据时代,数据的价值不仅在于存储,更在于能够从中挖掘出有意义的信息。ElasticSearch 作为一款强大的分布式搜索引擎,除了具备出色的搜索功能外,其内置的统计分析能力也不容小觑,能够助力我们快速洞察数据背后的规…...
DataCap MongoDB Driver: 全面解析MongoDB在DataCap中的使用指南
在大数据时代,MongoDB作为一款广受欢迎的NoSQL数据库,其灵活的文档存储模型和强大的查询能力使其成为许多现代应用的首选数据存储方案。今天,我们将深入探讨DataCap MongoDB Driver,这是一个强大的工具,它让在DataCap环…...
DDSort-简单实用的jQuery拖拽排序插件
DDSort.js是一款简单实用的jQuery拖拽排序插件。通过该插件你可以任意拖动页面中元素,并放置到指定的地方。DDSort.js插件实用简单,兼容IE8浏览器。 在线预览 下载 使用方法 实用该拖拽排序插件需要在页面中引入jquery文件和ddsort.js文件。 <scri…...
「下载」智慧园区及重点区域安全防范解决方案:框架统一规划,建设集成管理平台
智慧园区在基础设施建设和管理上仍存在诸多挑战。园区内场景碎片化、系统独立化、数据无交互、应用无联动等问题普遍存在,导致管理效率低下,安全隐患频发。 各安保系统如视频监控系统、报警管理系统、门禁管理系统等独立运行,数据不共享&…...
华为 IPD,究竟有什么特点?(一)
关注作者 (一)华为版 IPD 特点一:一定要让研发转身为作战 部队 冲到前台的研发,应主动拉通公司上下游,向前抓需求,向后支撑可制造性、可 服务性,并推动制造、服务的改进。 1)研发从…...
Llama 3 后训练(三)
目录 4. 后训练 4.1 建模 图表解读 4.1.1 聊天对话格式 4.1.2 奖励建模 4.1.3 监督微调(Supervised Finetuning) 4.1.4 直接偏好优化(Direct Preference Optimization) 4.1.5 模型平均(Model Averaging&#x…...
Docker 安装全攻略:从入门到上手
Docker 安装全攻略:从入门到上手 在当今的软件开发与部署领域,Docker 已经成为了一项不可或缺的关键技术。它能够将应用程序及其依赖项打包成轻量级、可移植的容器,极大地简化了开发、测试和部署的流程。本文将详细讲解在不同操作系统下 Doc…...
螺杆支撑座在运用中会出现哪些问题?
螺杆支撑座是一种用于支撑滚珠螺杆的零件,通常用于机床、数控机床、自动化生产线等高精度机械设备中。在运用中可能会出现多种问题,这些问题源于多个方面,以下是对可能出现的问题简单了解下: 1、安装不当:安装过程中没…...
Java与SQL Server数据库连接的实践与要点
本文还有配套的精品资源,点击获取 简介:Java和SQL Server数据库交互是企业级应用开发中的重要环节。本文详细探讨了使用Java通过JDBC连接到SQL Server数据库的过程,包括加载驱动、建立连接、执行SQL语句、处理异常、资源管理、事务处理和连…...
eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
HTML 列表、表格、表单
1 列表标签 作用:布局内容排列整齐的区域 列表分类:无序列表、有序列表、定义列表。 例如: 1.1 无序列表 标签:ul 嵌套 li,ul是无序列表,li是列表条目。 注意事项: ul 标签里面只能包裹 li…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
#Uniapp篇:chrome调试unapp适配
chrome调试设备----使用Android模拟机开发调试移动端页面 Chrome://inspect/#devices MuMu模拟器Edge浏览器:Android原生APP嵌入的H5页面元素定位 chrome://inspect/#devices uniapp单位适配 根路径下 postcss.config.js 需要装这些插件 “postcss”: “^8.5.…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...
