一架无人机要沿通道前进 4 米,从静止出发,在终点停下。速度上限为 2 米/秒,加速度大小上限为 1 米/秒²。
这次让搜索算法决定运动安排:下一秒加速、匀速还是减速?经过什么状态,才能尽快到达终点并停止?
Kinodynamic A* 将运动状态作为节点,用运动模型生成连接,再按照 A* 的规则比较候选方案。
下面构造一个以到达时间为代价的入门算例,完整算出搜索过程,再把一次扩展放到二维障碍环境中。
一、一个节点,同时记录位置和速度
1. 把任务写清楚
用沿通道的坐标 p 表示位置,用 v 表示向前速度,把它们组成一个状态:
X=(p,v).
例如,X=(2,1) 表示位于 2 米处,正以 1 米/秒向前运动。
本例采用双积分器模型:
p˙=v,v˙=u.
u 是规划器选择的加速度。它先改变速度,再通过速度改变位置。
| 项目 |
本例设置 |
| 起始状态 |
S=(0,0):位于 0 米处,速度为 0 |
| 目标状态 |
G=(4,0):位于 4 米处,速度为 0 |
| 允许位置 |
0≤p≤4,整段直线通道已经通过几何检查 |
| 允许速度 |
0≤v≤2m/s,始终向前或静止 |
| 可选加速度 |
u∈{+1,0,−1}m/s2 |
| 每次动作持续时间 |
Δt=1 秒 |
| 比较目标 |
从 S 到 G 的总时间最小 |
这里的允许位置是计入机体尺寸后的中心点范围。环境静止,运动限制在搜索期间保持不变。
三个加速度分别表示加速、保持当前速度和减速。每选一次加速度,就产生一段持续 1 秒的候选运动。
2. 同一个位置,为什么要保留不同节点?
在 2 米处,考虑两个状态:
| 状态 |
运动情况 |
接下来可能怎样运动 |
| (2,0) |
静止 |
可以保持静止,或者重新加速 |
| (2,2) |
以 2 米/秒向前运动 |
即使立即以最大减速度制动,也需要继续前进 |
对于第二个状态,保持加速度 −1m/s2,需要 2 秒才能停下。这两秒的平均速度为 1 米/秒,因此还要前进 2 米。
两个状态的后续运动不同,搜索时就为它们分别保存记录。
本例用完整的 (p,v) 区分节点。到达位置相同、速度不同的两个候选,都有各自的到达代价与前驱。
二、一条边,是一段计算出来的运动
1. 从当前状态计算下一秒
设当前状态为 (p0,v0),选择加速度 u,在这 1 秒内保持不变。
用 τ 表示本段开始后经过的时间,0≤τ≤1。这段运动满足:
p(τ)v(τ)=p0+v0τ+21uτ2,=v0+uτ.
到第 1 秒结束时,得到下一个节点:
Xnew=(p0+v0+21u, v0+u).
最后这个数值式采用秒、米为单位,已经代入了 Δt=1 秒。
节点记录一段运动的终点状态,边保存整个时间区间内的位置与速度变化。 这样的短时运动称为运动基元。
2. 从同一个状态生成三个候选
假设当前位于:
X=(0.5,1).
选择加速度 u=+1,计算:
pnew=0.5+1×1+21×1×12=2,
vnew=1+1×1=2.
得到状态 (2,2)。
对另外两个加速度执行同样计算:
| 加速度 u(米/秒²) |
1 秒后的位置(米) |
1 秒后的速度(米/秒) |
新状态 |
| +1 |
0.5+1+0.5=2 |
1+1=2 |
(2,2) |
| 0 |
0.5+1=1.5 |
1+0=1 |
(1.5,1) |
| -1 |
0.5+1−0.5=1 |
1−1=0 |
(1,0) |

图的横轴是本段时间,纵轴是位置。三条曲线从同一状态出发,经过 1 秒后落到不同状态。
生成候选时还要检查运动限制。本例每段速度随时间线性变化;首尾速度都在 [0,2] 内,整段速度就保持在这个区间内。速度始终非负,因此位置单调增加,可以同时用首尾位置核验通道范围。
后面加入障碍物时,还需要检查整条运动曲线与障碍的关系。
三、用时间给候选状态排序
1. 已经用了多久:g(X)
沿用 A* 的记号,用 g(X) 记录目前找到的、从 S 到状态 X 的最小累计时间。
每条运动基元持续 1 秒,因此沿一条新边到达下一状态的候选时间为:
gnew=g(X)+1.
例如,2 秒到达某个状态,再接一段运动,就得到一条耗时 3 秒的到达方案。
找到更快到达同一状态的方案时,同时更新它的累计时间、前驱和连接所用的加速度。
2. 至少还要多久:h(X)
先分别估计两项需求。
第一项是完成剩余位移。 当前位置为 p,距离终点还有 4−p 米。速度上限为 2 米/秒,因此至少需要:
hp=24−p.
例如,位于 0.5 米处时,还剩 3.5 米,至少需要 3.5/2=1.75 秒。
第二项是把速度降到零。 当前速度为 v,最大减速度大小为 1 米/秒²,因此至少需要:
hv=1v.
例如,当前速度为 2 米/秒,减速到静止至少需要 2 秒。
减速的同时还会向前移动,这两项需求可以在同一段时间内完成。任何可行的剩余运动,都至少要满足其中较长的时间要求。因此本例取:
h(X)=max(24−p,1v).
max 表示取两个数中较大的那个。两个比值的单位都是秒,式中的分母分别来自速度上限与加速度上限。
这只是一个剩余时间下界,具体运动仍由后续搜索确定。
3. 合起来比较:f=g+h
A* 按照:
f(X)=g(X)+h(X)
安排候选的处理顺序。这里的 g、h、f 全部以秒计。
例如,前面从 (0.5,1) 产生的三个状态,都能在总计 2 秒时到达:
| 候选状态 |
已用时间 g |
剩余时间下界 h |
f=g+h |
| (2,2) |
2 |
max(1,2)=2 |
4 |
| (1.5,1) |
2 |
max(1.25,1)=1.25 |
3.25 |
| (1,0) |
2 |
max(1.5,0)=1.5 |
3.5 |
这次先处理 (1.5,1),因为它的 f=3.25 最小。 到达更靠前的位置与保留怎样的速度,都会影响候选的评价。
为使手算过程确定,本例规定:先选 f 较小的;f 相同时选 h 较小的;两者都相同时,按进入候选清单的先后顺序处理。每次按 +1、0、−1 的顺序尝试加速度。
四、跟着搜索,算到终点
1. 第一轮:从静止起点出发
候选清单中最初只有起点 S=(0,0),g=0、h=2、f=2。检查三个加速度:
| 加速度 |
1 秒后的状态 |
处理结果 |
| +1 |
(0.5,1) |
合格,记录到达时间 1 秒 |
| 0 |
(0,0) |
回到同一状态,已有的 0 秒记录更好 |
| -1 |
(−0.5,−1) |
超出本例的位置与速度范围 |
候选清单中只留下 (0.5,1)。在静态问题中,多用 1 秒等待再到达同一状态,后续可选运动保持相同,所以保留原来的较早记录。
2. 第二轮:保留三种后续安排
取出 (0.5,1),它的到达时间为 1 秒。
按上一节的计算,加入 (2,2)、(1.5,1)、(1,0) 三个候选,f 分别为 4、3.25、3.5。它们的前驱都是 (0.5,1),对应加速度分别为 +1、0、−1。
下一轮取出 (1.5,1)。另两个候选继续留在清单中。
3. 第三轮:从匀速候选继续扩展
到达 (1.5,1) 已经用了 2 秒。分别尝试:
| 加速度 |
新状态 |
新的累计时间 |
新的 f |
| +1 |
(3,2) |
3 秒 |
3+2=5 |
| 0 |
(2.5,1) |
3 秒 |
3+1=4 |
| -1 |
(2,0) |
3 秒 |
3+1=4 |
例如,加速度为 −1 时,位置为 1.5+1−0.5=2,速度降到 0,得到 (2,0)。
此时完整的候选清单按优先级排好为:
| 顺序 |
状态 |
g |
h |
f |
| 1 |
(1,0) |
2 |
1.5 |
3.5 |
| 2 |
(2.5,1) |
3 |
1 |
4 |
| 3 |
(2,0) |
3 |
1 |
4 |
| 4 |
(2,2) |
2 |
2 |
4 |
| 5 |
(3,2) |
3 |
2 |
5 |
其中,(2,0) 和 (2,2) 同时保留。它们都位于 2 米处,后续运动能力各不相同。
4. 第四至六轮:比较分支,记录更远的候选
先处理 (1,0)。选择 +1 后,用总计 3 秒到达 (1.5,1),而这个状态已有 2 秒的记录,因此保留原记录。选择 0 会增加等待时间,选择 −1 则产生负速度。本轮没有新增候选。
随后取出 (2.5,1),此时 g=3。三个动作产生:
| 加速度 |
新状态 |
到达时间 |
处理 |
| +1 |
(4,2) |
4 秒 |
加入候选,位置达到终点坐标,速度仍为 2 |
| 0 |
(3.5,1) |
4 秒 |
加入候选 |
| -1 |
(3,0) |
4 秒 |
加入候选 |
任务的目标是 (4,0)。状态 (4,2) 表示到达 4 米处时仍在向前运动,因此搜索继续。
第六轮取出 (2,0)。重新加速会用总计 4 秒到达 (2.5,1),已有记录为 3 秒,其余两个动作也没有带来更优候选。
这三轮比较后,清单中轮到 (2,2)。它一直保留着总计 2 秒的到达方案。
5. 第七轮:另一条分支带来更早到达的方案
现在从 (2,2) 出发,已经用了 2 秒。
选择加速度 +1,下一秒速度会达到 3,超过上限,排除。
选择 0:
pnew=2+2=4,vnew=2.
到达 (4,2) 的时间为 3 秒,优于原来的 4 秒,因此更新它的记录。
选择 −1:
pnew=2+2−0.5=3.5,vnew=1.
到达 (3.5,1) 的时间也为 3 秒,比原来的记录更早:
| 方案 |
经过的状态 |
用时 |
| 旧 |
(0,0)→(0.5,1)→(1.5,1)→(2.5,1)→(3.5,1) |
4 秒 |
| 新 |
(0,0)→(0.5,1)→(2,2)→(3.5,1) |
3 秒 |
于是把 (3.5,1) 的累计时间从 4 秒改为 3 秒,前驱从 (2.5,1) 改为 (2,2),最后一段加速度从 0 改为 −1m/s2,优先级变为 f=3+1=4。
更新的对象是到达同一位置、同一速度的方案。前驱改变后,最后一段运动的输入也随之改变。
6. 第八轮:用减速段接到静止终点
取出 (3.5,1),现在只用了 3 秒。
选择 +1 或 0,会分别到达 5 米或 4.5 米,超出本例的位置范围。
选择 −1:
pnew=3.5+1−0.5=4,vnew=1−1=0.
这次得到完整目标状态:
G=(4,0),g(G)=4,h(G)=0,f(G)=4.
它成为优先级最高的候选。第九轮取出 G,结束搜索。
完整的取出顺序如下:
| 轮次 |
取出状态 (p,v) |
g(秒) |
h(秒) |
f(秒) |
| 1 |
(0,0) |
0 |
2 |
2 |
| 2 |
(0.5,1) |
1 |
1.75 |
2.75 |
| 3 |
(1.5,1) |
2 |
1.25 |
3.25 |
| 4 |
(1,0) |
2 |
1.5 |
3.5 |
| 5 |
(2.5,1) |
3 |
1 |
4 |
| 6 |
(2,0) |
3 |
1 |
4 |
| 7 |
(2,2) |
2 |
2 |
4 |
| 8 |
(3.5,1) |
3 |
1 |
4 |
| 9 |
(4,0) |
4 |
0 |
4 |
表中的轮次是搜索处理候选的顺序,g 是相应运动方案的累计时间。处理不同分支时,累计时间可以从 3 回到 2;实际执行的运动顺序随后由前驱回溯确定。
五、沿前驱,取出一条带时间的运动
1. 回溯节点,也回溯每条边的输入
从 G 逐个查前驱,反向整理后得到 (0,0)→(0.5,1)→(2,2)→(3.5,1)→(4,0),对应的运动安排为:
| 时间区间(秒) |
加速度(米/秒²) |
起始状态 |
结束状态 |
| 0~1 |
+1 |
(0,0) |
(0.5,1) |
| 1~2 |
+1 |
(0.5,1) |
(2,2) |
| 2~3 |
-1 |
(2,2) |
(3.5,1) |
| 3~4 |
-1 |
(3.5,1) |
(4,0) |
合并相同输入的相邻段,就是先加速 2 秒,再减速 2 秒。

图中的一对坐标表示位置和速度。最终运动沿曲线先到达 (2,2),再接到 (4,0)。时间标记表示执行时经过各状态的先后。
2. 还原任意时刻的位置与速度
前两秒从静止加速:
p(t)=21t2,v(t)=t,0≤t≤2.
后两秒从位置 2、速度 2 开始减速。令 τ=t−2:
p(t)=2+2τ−21τ2,v(t)=2−τ,2≤t≤4.
例如,第 2.5 秒时,本段经过 τ=0.5 秒:
p(2.5)=2+2×0.5−21×0.52=2.875 米,
v(2.5)=2−0.5=1.5m/s.

速度曲线下的两个三角形面积分别为 2 米,合计 4 米。整段速度在 0~2 米/秒之间,加速度大小为 1 米/秒²,起终状态也符合要求。
3. 这里的“最短时间”对应什么?
本例的节点由指定输入和 1 秒时长生成。可到达位置落在半米刻度上,速度取 0、1、2;结合通道边界,构成一个有限的离散运动图。
前面构造的 h 是剩余时间下界,而且满足一致性。沿任意合格的 1 秒运动,最多前进 2 米,所以距离下界最多下降 1 秒;速度最多减少 1 米/秒,所以减速下界也最多下降 1 秒。取两者的较大值后,仍有:
h(X)≤1+h(Xnew).
再结合 h(G)=0、正的边代价和正确的记录更新,目标以最小有效 f 被取出时,得到这个离散运动图中的最短时间。
改变可选加速度、动作时长或状态保留规则,就改变了搜索能够比较的运动集合。
六、扩展到二维:连接可能是一条弯曲的运动
1. 水平面内,同时传播两个方向
在固定高度的水平面内,用:
X=(x,y,vx,vy)
记录状态,输入为加速度 (ux,uy)。本段运动满足:
x(τ)y(τ)=x0+vx0τ+21uxτ2,=y0+vy0τ+21uyτ2.
例如,当前位于 (2,2),速度为 (1,0):正在沿 +x 方向以 1 米/秒运动。
这一秒选择输入 (ux,uy)=(0,1),得到:
x(τ)=2+τ,y(τ)=2+21τ2.
横向保持匀速,侧向逐渐加速。计算几个时刻:
| 本段时间 τ(秒) |
位置 (x,y)(米) |
速度 (vx,vy)(米/秒) |
| 0 |
(2,2) |
(1,0) |
| 0.5 |
(2.5,2.125) |
(1,0.5) |
| 1 |
(3,2.5) |
(1,1) |
速度大小为 1+τ2,全段不超过 2 米/秒;加速度大小为 1 米/秒²。因此,这段候选满足速度上限 2、加速度上限 1 的要求。
2. 用实际运动曲线检查障碍
假设地图上有一小块禁行区域,已经计入机体尺寸:
2.4≤x≤2.6,2.05≤y≤2.18.
这段候选的两个端点都位于区域外,但在半秒时:
(x,y)=(2.5,2.125),
正好落在区域内部。因此整段候选被碰撞检查拒绝。

图中的端点连线是另一条几何曲线。它满足:
y=2+21(x−2).
经过障碍的横向范围 x∈[2.4,2.6] 时,这条直线的 y 在 2.2~2.3 之间,位于障碍上方;实际运动则在同一区域内更低,发生碰撞。
动力学搜索检查的是输入与初始状态共同产生的运动曲线。 候选边被接受后,保存的也是这段运动。
本例一个中间时刻就足以证明碰撞。判断整段无碰撞时,需要验证整个区间,例如计算曲线与几何障碍的相交关系,或者采用带保守界的曲线细分。
七、把计算整理成搜索流程
本篇的一维算例可以整理成:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| 检查起终状态与运动参数
g[S] = 0 其他状态的 g = ∞ 将 S 放入 OPEN,优先级为 g[S] + h(S)
只要 OPEN 非空: 取出 f 最小的记录,得到状态 X 如果记录中的 g 已经过期: 跳过这条记录
如果 X 满足目标位置和目标速度: 沿前驱回溯,同时取出每段输入与持续时间 返回完整运动
依次尝试 u = +1、0、-1: 从 X 出发,生成持续 1 秒的运动基元 计算末端状态 Y
检查整段运动的速度、位置范围和碰撞关系 如果不合格: 跳过这个候选
new_g = g[X] + 1 如果 new_g < g[Y]: 更新 g[Y] = new_g 更新 Y 的前驱为 X 保存本段输入 u 和持续时间 1 秒 将 Y 加入或更新到 OPEN 优先级为 g[Y] + h(Y)
返回:当前离散运动图中没有找到符合要求的目标
|
每个状态的记录需要包含位置、速度、累计时间、前驱,以及接入它的运动参数。这里的前驱连接还携带加速度与时间,因此回溯时能够恢复连续运动。
本例用精确的半米位置和整数速度区分状态。更一般的搜索可以对位置、速度设置分辨率;把多个不同状态归入同一格并只保留一个代表时,代表状态的选择会影响后续可搜索的运动。
当前终点 (4,0) 正好可以由这些运动基元到达。对于其他目标,还可以从接近终点的状态构造一段满足起终位置、速度的多项式连接,再验证整段约束。这个末端连接把多项式轨迹生成与状态空间搜索联系起来。
配套文件 kinodynamic_astar_example.py 使用 Python 标准库复算本篇的九轮搜索。运行:
1
| python kinodynamic_astar_example.py
|
程序输出各轮状态、候选处理结果、前驱回溯和四段加速度,还会用 Dijkstra 核对最终时间。
八、搜索结果怎样交给后续轨迹规划?
本篇得到的是双积分器模型下的分段恒加速度运动。它已经包含时间、位置、速度和输入,各段的位置与速度连续。
在第 2 秒,加速度从 +1 切换到 −1m/s2。把它代入等高、忽略阻力的多旋翼模型,令重力加速度大小为 g0=9.8m/s2,所需倾角为:
θ=arctan(g0u).
这个切换对应参考倾角从约 +5.83∘ 跳到 −5.83∘。真实机体完成转动需要时间,因此后续轨迹设计还要安排姿态的连续变化,并检查角速度、推力和执行器要求。
可以把搜索结果作为初始运动,用分段多项式或样条重新安排加速度与更高阶导数。调整形状与时间后,再核验运动上限、起终条件和整段碰撞关系。
这样,搜索提供一条满足所用简化模型的运动候选,轨迹优化继续改善平滑性与障碍间距,动力学计算则检查相应的飞行需求。
小结
在这个 4 米算例中,搜索自动选出了 +1、+1、−1、−1 四段加速度,用 4 秒从静止出发并在终点停下。
状态决定当前能怎样运动,输入与时长生成候选连接,A* 比较到达这些状态的代价,前驱记录还原整段运动。
把位置扩展到二维、三维后,同一套过程可以用于绕障:生成运动曲线,检查约束,保留可行连接,再继续搜索。后续可以学习 Bézier 曲线与 B 样条,用控制点调整轨迹形状,并利用曲线的几何性质组织避障约束。