想象你是一名刚上岗的外卖骑手,被派到一个大雾弥漫的陌生城市。没有地图、没有导航,只有一栋栋大楼和禁止驶入的小区。你怎么把餐送到顾客手里?你不会先画完整张城市地图,而是随手往几个路口扔一把“探针”:能走的路记下来,不能走的绕开。跑得越久,路网越密,最终找到一条可行的送餐路线。这就是基于采样的运动规划——不追求把地图背下来,而是用随机采样一点一点“摸”出可行路径。 机器人也有自己的“陌生城市”:机械臂的关节角、无人车的坐标、避障姿态组合成的高维空间。PRM、RRT、RRT* 是三种“摸路”的典型打法:PRM 先撒点建路网,RRT 像牵着绳子乱跑探路,RRT* 在探路时不断改绳子,把路线越改越短。这篇文章就用这个“外卖骑手摸路”的故事,带你系统理解这三种算法。

岗位关联

采样规划是机器人、自动驾驶和工业机械臂在复杂高维空间里找路的“必修课”。学会 PRM/RRT/RRT*,你就掌握了从算法原型到工程调试的关键一步,是运动规划相关岗位的核心竞争力。

目录
  1. 可视化演示
  2. 采样思想起源
  3. 概率路图PRM
  4. 快速扩展RRT
  5. 渐近最优RRT*
  6. 参数调优经验
  7. 高维应用边界
  8. 工程实践落地
  9. AI 应用场景
  10. Python 演示
  11. 常见误区
  12. 面试题

可视化演示

展示PRM路线图构建、RRT快速探索随机树生长与RRT*渐近最优重连过程,可视化三种采样规划算法在高维空间中的路径搜索策略。

本节配有交互动效(进入视口后自动加载,约 3KB)。

RRT快速探索随机树 从起点出发,随机采样并朝最近节点延伸,快速覆盖空间 x_new←x_rand 概率完备但非渐近最优

采样思想起源

小李的第一课是不求满分地图。雾城太大,如果把每条巷子都点亮再送餐,等天亮了也送不完。于是他在城市里随机撒一把“探针”,这些探针是一组随机坐标;落在楼里的答案作废,落在路上的保留。这一小步就是采样。机器人也一样,它关心的不是所有可能姿势,而是“哪个姿势不撞墙、哪个动作能走通”。

在机器人学里,这个“城市”叫配置空间(C-space),机器人的每一个可能状态都对应空间里的一个点。障碍物占据的集合叫障碍空间,剩下的叫自由空间。随机采样的精髓,就是不去显式画出自由空间的边界,而是用一个个随机点去试探。每抛出一个点,就做一次碰撞检测;能落脚的,就认为是自由空间的一部分。这样避开了“把整个高维地图都建模出来”的难题,这也是采样思想在高维空间里能突围的原因。

为什么这一招管用?因为基于采样的规划具有概率完备性:只要采样点足够多,找到一条可行路径的概率会趋于 1。

回到小李:摸几个路口不能保证每次送成,但摸得越多,送成的把握越大。采样规划也一样,它用“更多的脚印”换“更稳的路径”。

lim⁡n→∞P(找到一条可行路径)=1\displaystyle \lim_{n\to\infty} P(\text{找到一条可行路径}) = 1
公式说明:随着采样次数 \(n\) 无限增加,规划器找到可行路径的“命中率”会无限接近 100%。这是一个统计意义上的保证,而不是确定性保证。
  1. 极限 \(n\to\infty\)采样点的数量 \(n\) 无限增加,表示“摸路摸得越来越密”。
    n→∞n \to \infty
  2. 概率 \(P\)表示随机采样过程能找到一条可行路径的机会。
    P(⋅)P(\cdot)
  3. 等式右边等于 1概率收敛到 1,说明只要肯撒足够多的点,几乎必然能找到路。
    lim⁡n→∞P(⋅)=1\lim_{n\to\infty} P(\cdot) = 1

概率路图PRM

PRM 很像小李白天先做“路书”:随机撒几百个路标,把相邻且能直线到达的路标连起来,形成一张城市路网。这份路书一旦做好,晚上接单时就不用再满城乱跑,只要查一下路网就能快速给出候选路线。PRM 的核心思路,就是把“找路”拆成两个阶段:先建网,再查网。

建图阶段会做大量工作:在自由空间里随机采样,把距离较近且连线不碰障碍的采样点连成边。查询阶段则是给定起点和终点,把起点终点接入已有路网,再在图上来一次最短路径搜索。因为路网可以反复使用,所以 PRM 特别适合静态场景里“同一张地图要回答多个起点终点问题”的情况,比如仓储机器人的固定货架区。

PRM 的连边条件可以写成:

对小李来说,PRM 就是白天把路书做扎实,晚上送餐时“按图索骥”。路书做得越密,后续查路就越省事;但如果路书覆盖不到顾客小区,那晚上照样会送迷路。

∥qi−qj∥<r且L(qi,qj)∩Cobs=∅\displaystyle \|q_i - q_j\| < r \quad\text{且}\quad L(q_i,q_j)\cap \mathcal{C}_{\text{obs}}=\varnothing
公式说明:两个采样点之间的距离要小于半径 \(r\),并且两点之间的直线段不能碰到任何障碍物,才允许连成一条“路”。
  1. 两点距离 \(\|q_i - q_j\|\)计算两个采样点在配置空间里的欧氏距离,用来判断它们是否“足够近”。
    ∥qi−qj∥\|q_i - q_j\|
  2. 邻域半径 \(r\)只有距离小于 \(r\) 的点才考虑连边,避免所有点两两相连造成边爆炸。
    <r< r
  3. 线段与障碍空间交集 \(L \cap \mathcal{C}_{\text{obs}}\)检查从 \(q_i\) 到 \(q_j\) 的整条线段是否都落在自由空间里。
    L(qi,qj)∩Cobs=∅L(q_i,q_j)\cap \mathcal{C}_{\text{obs}}=\varnothing
  4. 两者同时满足距离近且无碰撞,这条路才能加入路网。

快速扩展RRT

如果说 PRM 是先修路后开车,那 RRT 就是“边开车边修路”。小李从站点牵出一根弹性绳索,随机向某个方向跑一小段,绳索留在地上形成树根;下一次又从某个新位置再随机跑一段,慢慢长成一棵探索树。RRT 不需要预先知道全局地图,它只需要知道“哪个方向撞墙、哪个方向能走”,就能不断把树往未知区域推进。

实现时,每次迭代从自由空间里采一个随机目标点,在现有树上找最近节点,然后沿着最近节点指向随机目标点的方向,走一个固定步长。如果走到的位置没有碰撞,就把这个新点挂到树上。这样反复生长,树会越来越接近目标点。RRT 往往会加一点“目标偏置”:以较小概率直接把目标点当作随机点,让树别只顾着乱逛。

新节点生成公式:

对小李来说,RRT 就像“不认路的骑手,绳子一头拴在站点,另一头到处试探”。它最大的优点是快速、内存友好,特别适合单次查询、动态环境;缺点是找到的路往往比较绕,未必是最优。

qnew=qnear+min⁡ ⁣(δ, ∥qrand−qnear∥)⋅qrand−qnear∥qrand−qnear∥\displaystyle q_{\text{new}} = q_{\text{near}} + \min\!\left(\delta,\ \|q_{\text{rand}} - q_{\text{near}}\|\right)\cdot \frac{q_{\text{rand}} - q_{\text{near}}}{\|q_{\text{rand}} - q_{\text{near}}\|}
公式说明:从最近节点 \(q_{\text{near}}\) 出发,朝着随机点 \(q_{\text{rand}}\) 走一步;走的距离不超过步长 \(\delta\),也不超过两者原本的距离。
  1. 最近节点 \(q_{\text{near}}\)在现有树上找一个离随机点最近的节点,作为本次生长的起点。
    qnearq_{\text{near}}
  2. 步长上限 \(\delta\)每次生长最多走这么远,防止树一步跨过障碍或飞得太远。
    δ\delta
  3. 方向向量 \(\frac{q_{\text{rand}} - q_{\text{near}}}{\|q_{\text{rand}} - q_{\text{near}}\|}\)表示从最近节点指向随机点的单位方向。
    qrand−qnear∥qrand−qnear∥\frac{q_{\text{rand}} - q_{\text{near}}}{\|q_{\text{rand}} - q_{\text{near}}\|}
  4. 最小值 \(\min(\delta,\ \text{距离})\)如果随机点很近就直接走到那里;如果很远就只走一个步长。
    min⁡ ⁣(δ, ∥qrand−qnear∥)\min\!\left(\delta,\ \|q_{\text{rand}} - q_{\text{near}}\|\right)

渐近最优RRT*

小李跑了几单后发现:绳子虽然能到顾客家,但路线经常绕远路。于是他想了个改进办法:每次走到一个新路口,别急着把绳子钉死,先看看附近还有没有更近的路口;如果有,就把绳子的挂点从原来的地方“改挂”到更近的地方。这样随着探索不断继续,整棵探索树的路径会逐步变短。这就是 RRT* 的核心直觉。

RRT* 在 RRT 的基础上增加两步:一是“邻域选父”,新节点生成后,看它周围有哪些老节点,选择一个能让“从起点到新节点总代价最小”的老节点作为父节点;二是“重布线”,新节点加入后,如果老节点通过新节点走到起点的代价更小,就把老节点的父节点改成新节点,让整棵树不断被优化。

选父节点的目标是最小化累积代价:

RRT* 之所以叫“渐近最优”,就是因为它不承诺一次找到最短路径,但会随着迭代增加不断向最优路径逼近。小李也因此越跑越精:先求送到,再求送得近。

c(qnew)=min⁡qp∈Xnear[c(qp)+d(qp,qnew)]\displaystyle c(q_{\text{new}}) = \min_{q_p \in \mathcal{X}_{\text{near}}} \left[ c(q_p) + d(q_p, q_{\text{new}}) \right]
公式说明:新节点的代价,等于从附近某个候选父节点走到它的距离,加上那个父节点原本的代价,然后取最小值。
  1. 累积代价 \(c(q_p)\)从起点按当前树走到节点 \(q_p\) 的总路程。
    c(qp)c(q_p)
  2. 邻域集合 \(\mathcal{X}_{\text{near}}\)新节点周围半径范围内的所有老节点,它们都有机会当新父节点。
    Xnear\mathcal{X}_{\text{near}}
  3. 距离增量 \(d(q_p, q_{\text{new}})\)从候选父节点到新节点的连线长度。
    d(qp,qnew)d(q_p, q_{\text{new}})
  4. 取最小值 \(\min\)在所有候选里挑一个总代价最小的作为父节点,让新节点从“最划算”的地方接入树。
    min⁡qp∈Xnear[⋅]\min_{q_p \in \mathcal{X}_{\text{near}}}[\cdot]

参数调优经验

参数调优就像小李调整自己的跑腿习惯:撒多少点、迈多大步、看多远的邻居、算多远的距离,都会直接影响找到路的速度和质量。没有一组万能参数,真正工作里要靠场景反复调试。

首先是采样规模。采样点太少,自由空间覆盖不完整,很可能漏掉可行通道;采样点太多,建图、碰撞检测、连边的计算量会急剧上升。其次是步长 \(\delta\)。步长太小,树前进缓慢,需要更多迭代;步长太大,容易跳过窄通道或直接穿过障碍物边界。再次是邻域半径 \(r\)。半径过小,候选父节点太少,难找到好路径;半径过大,连边和重布线开销会爆炸。最后是距离度量。在机械臂关节空间里,欧氏距离不一定能反映真实代价,有时要给不同关节分配不同权重。

RRT* 的理论邻域半径常按下面公式取:

小李的经验是:先跑一次默认参数看树长什么样,再观察失败原因是“覆盖不够”还是“计算太慢”,对症下药调参数。盲目堆采样量,常常只是让程序更慢,而不是让路径更好。

r(n)=γ(log⁡nn)1/d\displaystyle r(n) = \gamma \left(\frac{\log n}{n}\right)^{1/d}
公式说明:邻域半径随采样点数量 \(n\) 和空间维度 \(d\) 变化,目的是在“连接机会”和“计算开销”之间取平衡。
  1. 采样数量 \(n\)当前树上已经生成的节点数,采样越多,邻域半径理应越小。
    nn
  2. 对数项 \(\log n\)让半径不会随节点数线性增长,避免高密度时连边过多。
    log⁡n\log n
  3. 维度 \(d\)配置空间的自由度数;维度越高,几何覆盖越稀疏,半径调整越敏感。
    dd
  4. 系数 \(\gamma\)与地图尺度、碰撞检测代价相关的经验常数。
    γ\gamma

高维应用边界

当雾城不断升级:不仅有狭窄小巷,还有多层立交、限行时段、电动车电量约束,地图维度陡然上升。小李很快发现,随机撒点开始失灵了——并非方法错了,而是“城市太大,随机脚印太稀疏”。

窄通道是采样规划最典型的痛点。如果自由空间里只有一条细细的通道,随机采样点绝大多数都会落在通道两侧的障碍区,只有极少数能准确落进通道。维度越高,这种“碰运气”的难度越大。高维空间看似每个维度都有自由度,但自由空间往往只占很小一块区域,随机点像沙粒撒进大海,很难精准命中可通行区域。这就是“维数灾难”。

更复杂的是非完整约束,比如汽车不能原地掉头、机械臂关节有速度上限。这些约束让随机采样点之间不能随便直线连接,新节点必须满足运动学可行性。采样规划不能只回答“能不能到”,还要回答“怎么用符合物理规律的方式到”。

生成随机点落入窄通道的概率可以近似理解为:

对小李来说,解决方式不是不撒点,而是“聪明地撒点”:在窄道附近增加密度、使用桥采样、结合局部规划器处理动力学。理解采样规划的适用边界,比记住算法代码更能决定工程天花板。

P窄道≈(ϵL)d\displaystyle P_{\text{窄道}} \approx \left(\frac{\epsilon}{L}\right)^d
公式说明:当特征长度 \(L\) 远大于窄道宽度 \(\epsilon\) 时,维度 \(d\) 越高,随机点落入窄道的概率越小,而且是指数级衰减。
  1. 窄道宽度 \(\epsilon\)可通行区域的典型宽度,越窄越难命中。
    ϵ\epsilon
  2. 地图尺度 \(L\)整个配置空间的特征边长,通常远大于 \(\epsilon\)。
    LL
  3. 比率 \(\frac{\epsilon}{L}\)表示窄道在单一维度上所占的比例。
    ϵL\frac{\epsilon}{L}
  4. 维度指数 \(d\)自由度的个数,相乘时这个比例不断被“稀释”,维度越高衰减越剧烈。
    (ϵL)d\left(\frac{\epsilon}{L}\right)^d

工程实践落地

采样规划早已不只是论文里的算法,它已经像外卖平台调度系统一样嵌进现实世界的机器人产品中。小李的故事,正在无数仓库、工厂和街道上真实发生。

在无人仓储场景中,AGV(自动导引车)要在货架间快速穿行。PRM 适合提前把静态货架区的路网建好,工作过程中反复查路;一旦遇到临时障碍,RRT* 再局部重规划一段新路,兼顾效率和实时性。在工业机械臂场景中,六轴机械臂要在狭小空间里做抓取,关节空间往往有 6 个甚至更多维度。工程师通常用 RRT* 在关节空间搜索,并配合逆运动学把关节路径映射成末端轨迹。在自动驾驶场景中,车辆换道、绕障需要毫秒级响应。RRT 系列算法能利用车辆运动学模型生成符合转向约束的局部路径,再由后端优化器做平滑。

这些场景的共同点都是:地图不能被完整预知、维度高、障碍复杂。基于采样的规划用一个非常朴素的哲学解决问题——不追求全知,只追求在有限时间内找到一条“足够好”的路。这恰恰是机器人从实验室走进真实世界所需要的工程智慧。

AI 应用场景

无人仓储AMR路径规划

阶段:运动规划与决策控制层

解决的问题:传统导航依赖预先建立的精确栅格地图,货架一旦变动就要重新建图,维护成本高。基于采样的规划只需随机采样探测可行空间,结合 RRT* 的重布线机制,能在动态变化的仓库中快速生成绕障路径。

具体案例:某电商仓库里,AGV 需要在密集货架之间搬运包裹。工程师先用 PRM 离线建好静态路网,运行中遇到临时堆放的纸箱,则触发 RRT* 局部重规划,让 AGV 在 100 毫秒内生成新路径,绕开障碍后重新汇入主干道。

工业机械臂高维避障

阶段:运动规划与轨迹生成层

解决的问题:六轴机械臂的关节空间维度高,直接画三维栅格地图会引发“维数灾难”。采样规划在关节空间随机采样,能天然避开末端执行器的几何复杂度,只需要做关节角度的碰撞检测。

具体案例:汽车工厂里,机械臂要在车体内侧完成焊接。工程师使用 RRT* 在 6 维关节空间搜索无碰撞路径,再用 B 样条平滑,最终让机械臂从车门缝隙伸入并完成焊接,整个规划耗时不到 0.5 秒。

自动驾驶局部避障

阶段:感知融合后的局部规划层

解决的问题:自动驾驶车辆需要满足转弯半径、加速度等运动学约束,普通最短路径算法生成的折线根本开不出来。RRT 系列采样时结合车辆运动学模型,随机产出的每段路径都符合“车能开”约束。

具体案例:城市道路中遇到施工围挡,自动驾驶系统在感知模块输出障碍物边界后,使用带转向约束的 RRT* 快速生成一条局部绕行轨迹,再由二次规划平滑成连续可执行的期望路径。

Python 演示

python135 行
import mathimport random class Node:    def __init__(self, x, y):        self.x = x        self.y = y        self.parent = None        self.cost = 0.0 class RRTStar:    def __init__(self, start, goal, obstacles, area,                 extend_len=0.2, neighbor_radius=0.3, max_iter=600):        self.start = start        self.goal = goal        self.obstacles = obstacles        self.area = area        self.extend_len = extend_len        self.neighbor_radius = neighbor_radius        self.max_iter = max_iter        self.node_list = [Node(*start)]        self.goal_node = Node(*goal)     def sample_point(self):        if random.random() < 0.1:            return self.goal        x = random.uniform(self.area[0], self.area[2])        y = random.uniform(self.area[1], self.area[3])        return (x, y)     def nearest_index(self, x, y):        best = 0        best_d = float('inf')        for i, node in enumerate(self.node_list):            d = (node.x - x) ** 2 + (node.y - y) ** 2            if d < best_d:                best_d = d                best = i        return best     def steer(self, x_near, y_near, x_rand, y_rand):        dx = x_rand - x_near        dy = y_rand - y_near        dist = math.hypot(dx, dy)        if dist < self.extend_len:            return x_rand, y_rand        ratio = self.extend_len / dist        return x_near + dx * ratio, y_near + dy * ratio     def collision_free(self, x1, y1, x2, y2):        steps = 12        for i in range(1, steps):            t = i / steps            px = x1 + (x2 - x1) * t            py = y1 + (y2 - y1) * t            for ox, oy, ow, oh in self.obstacles:                if ox <= px <= ox + ow and oy <= py <= oy + oh:                    return False        return True     def near_indices(self, x, y, r):        res = []        for i, node in enumerate(self.node_list):            if (node.x - x) ** 2 + (node.y - y) ** 2 <= r * r:                res.append(i)        return res     def plan(self):        for _ in range(self.max_iter):            rx, ry = self.sample_point()            ni = self.nearest_index(rx, ry)            near = self.node_list[ni]            nx, ny = self.steer(near.x, near.y, rx, ry)            if not self.collision_free(near.x, near.y, nx, ny):                continue            new_node = Node(nx, ny)            new_node.parent = near            new_node.cost = near.cost + math.hypot(nx - near.x, ny - near.y)             indices = self.near_indices(nx, ny, self.neighbor_radius)            for idx in indices:                cand = self.node_list[idx]                d = math.hypot(nx - cand.x, ny - cand.y)                if self.collision_free(cand.x, cand.y, nx, ny) and \                   cand.cost + d < new_node.cost:                    new_node.parent = cand                    new_node.cost = cand.cost + d             self.node_list.append(new_node)             for idx in indices:                other = self.node_list[idx]                d = math.hypot(other.x - nx, other.y - ny)                if self.collision_free(nx, ny, other.x, other.y) and \                   new_node.cost + d < other.cost:                    other.parent = new_node                    other.cost = new_node.cost + d             if math.hypot(nx - self.goal[0], ny - self.goal[1]) < 0.15:                if self.collision_free(nx, ny, self.goal[0], self.goal[1]):                    self.goal_node.parent = new_node                    self.goal_node.cost = new_node.cost + \                        math.hypot(self.goal[0] - nx, self.goal[1] - ny)                    break         if self.goal_node.parent is None:            return []         path = []        node = self.goal_node        while node is not None:            path.append((node.x, node.y))            node = node.parent        path.reverse()        return path def main():    start = (0.2, 0.2)    goal = (1.2, 1.0)    obstacles = [(0.3, 0.0, 0.18, 0.55), (0.65, 0.45, 0.2, 0.55),                 (0.5, 0.25, 0.25, 0.15)]    planner = RRTStar(start, goal, obstacles, [0, 0, 1.5, 1.2],                      extend_len=0.15, neighbor_radius=0.25, max_iter=800)    path = planner.plan()    print("path nodes:", len(path))    print("path start:", path[:1])    print("path end:", path[-1:])    if path:        total = sum(math.hypot(path[i + 1][0] - path[i][0],                               path[i + 1][1] - path[i][1])                    for i in range(len(path) - 1))        print("total length:", round(total, 4)) if __name__ == "__main__":    main()
目的:用 100 多行 Python 实现一个可运行的 RRT* 路径规划器,模拟外卖骑手在二维障碍地图里从起点摸到目标点的全过程。
  1. self.node_list = [Node(*start)]初始化探索树,把起点当作树根。
  2. def sample_point(self):随机在自由空间采样,偶尔直接返回目标点,模拟“目标偏置”。
  3. new_node.cost = near.cost + math.hypot(nx - near.x, ny - near.y)先按 RRT 方式接上父节点,计算出起点到新节点的累积代价。
  4. if self.collision_free(cand.x, cand.y, nx, ny) and \检查候选父节点到新节点是否无碰撞,这是 RRT* 邻域选父的前提。
  5. other.parent = new_node重布线:如果老节点通过新节点更划算,就“改挂”到新节点上。
  6. path.reverse()从目标沿父指针回溯到起点,再反转成从起点到目标的完整路径。

常见误区

误区既然采样规划靠随机点找路,那就疯狂增加采样数量,采样越多、覆盖越密,结果肯定越好。

正解采样数量增加确实会提高找到路径的概率,但也会让边数、碰撞检测和重布线开销快速增长。工程上更看重“有效覆盖”,而不是“盲目堆点”。就像小李不可能把全城每块砖都踩一遍才去送餐,而是在关键路口多踩几脚。参数调优的目标是用尽量少的点覆盖尽量关键的自由区域。

为何常见:人容易把“数量”和“质量”划等号,而且采样量增加带来的概率完备性直觉非常强,却忽略了计算代价和边界效应。

误区算法有概率完备性,所以只要跑得够久,最后一定既能找到路径,又能找到最短路径。

正解概率完备只保证“存在可行路径时,采样无限多能找到一条可行路径的概率趋于 1”,并不保证路径最优。RRT 只能找到可行路径,RRT* 才有渐近最优性。就像小李随手扔飞镖,扔得够多总能扎中靶子,但不保证每支飞镖都是十环。

为何常见:很多人把“完备性”和“最优性”混为一谈,因为日常语言里“搞定”常被理解成“搞定得最好”。

误区只要两个采样点本身不在障碍物里,它们之间的连线就是安全的。

正解两点连线可能穿过障碍物。正确做法是在线段中间均匀采样多个中间状态做碰撞检测,确认整条线段都落在自由空间里。小李也不会因为两个朋友站在楼两侧招手,就认为他们之间有一条直路。

为何常见:人脑处理二维直线时容易默认“两点之间直线最短且畅通”,但在复杂配置空间里,障碍可能横在两点中间。

误区距离度量就用普通欧氏距离,反正代码里也是这么写的。

正解机械臂关节空间、车辆运动学约束等场景下,欧氏距离并不能真实反映“走起来有多费劲”。关节角具有周期性,方向变化需要特殊处理;不同关节的最大速度不同,要给距离加权重。小李也不会用地图上的直线距离代替实际骑行距离,因为还要考虑红绿灯和单行道。

为何常见:欧氏距离直观、容易实现,初学者容易忽略配置空间的多维几何结构,尤其是非欧氏和带约束的情形。

面试题

Q1. 下列哪一项最符合基于采样规划的核心思想?

单选题 · easy

  • A.对配置空间做像素级规划
  • B.随机采样探测可行空间← 正确答案
  • C.用解析方法穷举所有路径
  • D.对地图做颜色聚类分析

答案:B。基于采样规划通过随机撒点、碰撞检测、逐步连接来探索配置空间,而不是对整个空间做像素级或解析式建模。B 最准确地描述了这个核心思想。

Q2. PRM 算法通常分为哪两个阶段?

单选题 · mid

  • A.建图阶段与查询阶段← 正确答案
  • B.训练阶段与推理阶段
  • C.编码阶段与解码阶段
  • D.采样阶段与死循环阶段

答案:A。PRM 先离线建路图,再在线查询路径。训练/推理是机器学习术语,编码/解码与采样规划无关。

Q3. 关于 RRT 中新节点 \(q_{\text{new}}\) 的描述,正确的是?

单选题 · hard

  • A.新节点一定落在随机采样点上
  • B.新节点离最近节点不超过步长← 正确答案
  • C.新节点一定穿过障碍物的中心
  • D.新节点只受目标点姿态影响

答案:B。RRT 从最近节点向随机点方向走一个步长 \(\delta\),如果随机点距离小于步长就直接到达随机点,否则不会越过步长。因此新节点不会无限远离最近节点,也不会一定落在随机采样点上。

Q4. RRT* 相对于 RRT 最关键的改进是什么?

单选题 · mid

  • A.使用更长的步长并合并路径
  • B.扩展后对邻域节点重新布线← 正确答案
  • C.每次采样后删除全部旧节点
  • D.用深度优先搜索替代随机采样

答案:B。RRT* 新增邻域选父和重布线,在扩展后不断优化树上已有节点的父节点关系。这正是它能从“可行解”走向“渐近最优解”的原因。

Q5. “概率完备”的含义是?

单选题 · hard

  • A.样本无限时找到可行解概率趋一← 正确答案
  • B.机器人必然在有限步内最优收敛
  • C.规划器能处理任意高维动态障碍
  • D.输出路径与随机种子完全无关

答案:A。概率完备指当采样点数量趋于无穷时,找到一条可行路径的概率趋于 1。它不保证有限步内最优,也不保证对任意动态障碍都有效。

Q6. 对六自由度机械臂做运动规划时,更合适的距离度量是?

单选题 · mid

  • A.末端笛卡尔空间直线距离
  • B.关节角加权后的欧式距离← 正确答案
  • C.彩色图像像素灰度差之和
  • D.机械臂表面涂料的颜色差

答案:B。机械臂规划通常发生在关节空间,关节角之差比末端直线距离更能反映机械臂真实运动代价。加权欧式距离还能表达不同关节速度或惯量的差异。

Q7. 在窄通道场景中,下列哪些说法正确?

多选题 · extreme

  • A.窄通道内随机采样命中率低← 正确答案
  • B.窄通道是采样规划主要难点← 正确答案
  • C.增加采样密度可缓解该问题← 正确答案
  • D.窄通道会阻塞所有可行路径

答案:ABC。窄通道体积占比小,随机点很难命中;它确实是采样规划在复杂场景中的典型瓶颈;增加采样密度可以提高命中概率。但窄通道不会阻塞所有可行路径,只是让路径搜索更难。

Q8. 下列哪些是采样规划中常见的可调参数?

多选题 · mid

  • A.采样点的总数量← 正确答案
  • B.扩展步长的尺度← 正确答案
  • C.邻域半径的大小← 正确答案
  • D.摄像头曝光的时间

答案:ABC。采样数量、步长、邻域半径分别控制覆盖密度、探索粒度和连边范围,是 PRM/RRT/RRT* 的核心调试项。摄像头曝光时间属于感知模块,跟运动规划无关。

Q9. 关于 PRM 与 RRT 的场景选择,正确的是?

单选题 · mid

  • A.PRM适合静态场景多查询← 正确答案
  • B.RRT* 一定比PRM更慢且无法使用
  • C.PRM只能处理二维平面地图
  • D.RRT完全不需要碰撞检测

答案:A。PRM 强调先建路网再查询,适合地图固定、需要多次回答路径问题的场景。RRT 更适合单次动态规划;PRM 不限于二维;RRT 仍然需要碰撞检测。

Q10. 关于 RRT* 的邻域优化策略,正确的是?

多选题 · hard

  • A.扩展后选择代价最小的近邻作父节点← 正确答案
  • B.对邻域节点进行重新布线← 正确答案
  • C.状态转移方程必须使用五次多项式
  • D.每次采样前必须清空整棵树

答案:AB。RRT* 通过“邻域选父”让新节点接入总代价最小的路径,再通过“重布线”优化老节点路径。它不强制使用五次多项式,也不会清空整棵树,树是持续累积探索结果的。