交互式模拟器中级

路径跟踪模拟器:纯跟踪与 Stanley

用纯跟踪或 Stanley 跑完一条赛道,并带上真实的转向延迟。拖动前视距离,整趟轨迹立即重画——包括 1 Hz GPS 定位让你付出的代价。

类别
自主机器人
时长
20–40 分钟
平台
浏览器 · Arduino · Raspberry Pi
路径跟踪模拟器:纯跟踪与 Stanley 技术示意图LOOKAHEADGOAL POINTCOMMANDED PATH

01 / 从这里开始

简介

规划器交给你一条路径,但路径里没有任何东西告诉轮子该怎么做。这个实验台补上的正是这缺失的一环。纯跟踪和 Stanley 在同一条航点路线上转向,并带有一阶转向响应和感知延迟,因为一个没有滞后的模型会让错误的整定看起来像是最优的。拖动一个航点或前视距离,整趟运行都会重新计算。

Live lab / Path following

Path following simulator

Pure pursuit and Stanley steering the same course, with the lag a real robot has. Drag the lookahead and the whole run replots — too short oscillates, too long cuts corners, and the best value moves with speed.

Browser native
A top-down path-following lab. A robot follows a course of waypoints using the selected controller, and the route it actually drove is drawn against the route it was asked to drive. Use the controls below to run it and the keyboard hint to move the waypoints.
A plot of how far the robot was from the path, against distance along the path. Corners appear as spikes; a lookahead that is too short appears as jitter everywhere.

The dashed line with dots is the course you asked for; the solid line is where the robot went. The faint line is the whole run at the current settings, computed the moment you change one. Below, cross-track error along the path — dotted verticals are corners. Drag a waypoint to rebuild the course.

  • Commanded path
  • Driven
  • Full run preview
  • GPS fix
Simulation

Ready. The faint line is the whole run at these settings — press Start to drive it.

RMS error
—
Worst error
—
Corner cut
—
Steering effort
—
Progress
0%
Lap time
—

Keyboard: focus the course, then Space to run/pause, N to step, R to reset, C for a new course, F for full screen. Press 1–8 to pick a waypoint and the arrow keys to move it.

控件

控制器用来在纯跟踪和 Stanley 之间切换。前视距离是纯跟踪唯一的旋钮, 对 Stanley 则是禁用的,因为它并不使用前视距离——这本身就是重点。

速度与前视距离会相互影响,这是最值得动手玩的部分: 先设成 1 m/s 找到最好的前视距离,再设成 3 m/s 重新找一次。

位置来源可以把完美的里程计换成一个 1 Hz、带米级噪声的定位结果, 并在两次更新之间保持不变。误差始终对照真值评分,所以这个惩罚是真实的, 而不是被藏起来的。

拖动任意航点,或者按 1–8 选中一个再用方向键移动。 拖动时整趟运行都会重新计算。

原理

两个控制器回答的是同一个问题——已知我在哪里、路径在哪里,转向角应该是多少?—— 而它们的回答方式完全不同。

纯跟踪是几何。找出路径上在前视距离 L 之前那个点,然后开过它的圆弧:

κ = 2y / L_d²          δ = atan(2 b sin α / L_d)

其中 y 是目标点在机器人坐标系下的横向偏移,b 是轴距。它只有一个参数, 而且是一个距离而不是一个增益——所以它可以在机器人之间迁移。

Stanley是控制。以前轴为参考,加上两项:

δ = θ_e + atan(k · e / v)

航向误差加上横向误差的反正切。除以速度,就是让一个增益能跨越一段 速度范围的原因。k 是一个真正的控制增益,不迁移。

实验台补上了教科书推导里略去的东西:总共 0.4 s 的滞后, 由 0.25 s 的一阶转向响应加上 0.15 s 的感知与计算延迟构成。 没有它,纯跟踪会随着前视距离缩小而单调变好,整个整定问题就消失了。

算法

每一步,对两个控制器都适用:

  1. 投影到路径上,在“上次到达的弧长”附近的一个窗口内搜索,而不是整条路径。 全局搜索会匹配到最近的那一段,所以一条折返的赛道会把机器人的进度 瞬移到它一分钟前刚经过的某个拐角。
  2. **在顶点处把平局解决到出边那一段。**过了拐角之后,两条相邻线段会投影到 同一个点、且距离相同;保留入边那一段,会递给控制器一个航向误差和 一个横向偏移——两者都接近零——于是它悄无声息地径直开出路径。
  3. 计算转向角,按控制器自己的规则来,并把它限制在机械极限内。
  4. 施加滞后,然后积分自行车模型。
  5. 对照真值评分,永远不要对照估计值。

第 2 步不是一个优化项。它就是 Stanley 能用和 Stanley 每次都恰好 在 78% 的地方自信地开出赛道之间的区别。

源代码

完整的纯跟踪,以它在真实机器人上呈现的形式:

float lastS = 0;   // arc length last reached — state, and it only moves forward

float pursue(float x, float y, float heading, float speed) {
  // The lookahead is scheduled on speed, with a hard floor: at a standstill a
  // proportional schedule asks for zero, which is a division by zero in disguise.
  float lookahead = constrain(0.7f * speed + 0.4f, 0.4f, 3.0f);

  float s = projectOntoPath(x, y, lastS);      // windowed around lastS
  lastS = max(lastS, s);
  Point goal = pointAtArcLength(lastS + lookahead);

  float dx = goal.x - x, dy = goal.y - y;
  float lateral = -sinf(heading) * dx + cosf(heading) * dy;
  float ld = max(0.3f, hypotf(dx, dy));        // clamp, or curvature blows up

  float curvature = 2.0f * lateral / (ld * ld);
  return curvature;                            // omega = v * curvature
}

真正要紧的是三行:调度下限、lastS 的单调性,以及 ld 的钳位。 其余的就是公式。

假设与硬件差异

实验台给了机器人一张完美的路径地图、一个完全已知的轴距、没有轮子打滑, 以及一个干净的一阶滞后模型。真实机器人一样都没有。

轮子打滑会让位置估计以一种 任何控制器都无法察觉的方式出错。减速箱背隙 在每次转向换向时都会加上空行程,它表现得像额外的滞后,会把最优前视距离 往上推。而差速驱动根本没有转向角——它有一个被指令的转速, 所以 ω = v κ 取代了 atan,而轴距只影响它能转得多紧。

在这一切之后仍然存活下来的是那个形状:一个内部最优解、随速度向右移动, 以及在该最优解处的误差无论如何都随速度增长。

电路图

控制器是便宜的部分。它从机器人其余部分需要的东西,才是贵的部分。

**位置。**两个轮子上的正交编码器, 以及在回路速率上对它们做积分的差速里程计。 在室内,这足以应付几十米的距离。

**航向。**短期用陀螺仪,绝对参考用磁力计,或者两者都要。航向误差是两个 控制器都赋予最高权重的项,也正是里程计最先丢失的那一项。

户外加一个绝对修正。GPS 模块要融合进估计里, 而不是直接跟随它——差别是 0.09 m 的均方根误差对 1.25。

完整理论见纯跟踪和 横向误差; 要动手做,GPS 航点车先在室内用编码器起步, 只等跟踪器工作之后才到户外去。

硬件清单

元器件

  • 一个能直接指令转向或轮速的底盘
  • 一个位置估计——最少要有编码器,在户外还要与 GPS 融合
  • 一个在整个任务期间都不会漂移的航向参考
  • 一个足够快的回路,使它自身的滞后小于你的前视距离

探索关联图谱

哪里用到这个模拟器

以这个实验台为基础的项目、学习路线和教程。

继续搭建

下载资源

完成项目时可以参考本页上的这些资料。可下载的项目包只会在其源文件和版本发布之后才会添加。

常见问题

常见问题解答

为什么前视距离更短,并不总能跟得更好?

在没有滞后的模型里确实如此,这正是许多教科书推导具有误导性的原因。真实机器人需要时间才能达到被指令的转向角,而且它据以行动的位姿已经是几十毫秒之前的了。这个实验台模拟了 0.25 秒的转向时间常数和 0.15 秒的感知延迟。有了这些滞后,误差曲线就变成了 U 形:短前视距离发出的修正,要等机器人已经越过误差之后才生效,于是下一次指令就会过度修正。一个比自身执行器还快的控制器会产生振荡。

如何为我的机器人选择前视距离?

测出你的总控制滞后,乘以你的速度,然后从这个距离的一到两倍开始。在这个实验台里,滞后是 0.4 秒,实测的最优值在 1 m/s 时为 0.9 米,到 3 m/s 时升至 1.4 米——是滞后期间所走距离的 1.2 到 2.3 倍。注意,最优值随速度增长,但增长得比正比例慢,所以按固定的行驶秒数来取值很接近,却并不准确。实际使用时,把它做成一个随速度变化的简单线性调度,并设一个硬性下限,因为在静止时这个调度会要求零。

纯跟踪和 Stanley,哪个更好?

它们失效的方式不同,这才是有用的答案。在这条路线上以 2 m/s 行驶时,纯跟踪会切弯,走完的路程比指令路径短 0.8%;Stanley 则不肯离开线路,转弯时甩得更宽,多走了 2.2%。Stanley 在关键之处能守住更紧的线路,但花掉的转向量是 18.5 弧度,而纯跟踪只有 4.3——执行器的动作、电流和轮胎磨损都是四倍。当路径只是一个建议时用纯跟踪,当路径是一个约束时用 Stanley。

为什么误差是对照真实位置、而不是估计值来测量的?

因为一台以为自己在路径上的机器人,按其构造就会报告零误差。把位置来源切换成 GPS,控制器就开始依据一个带噪声、滞后一秒的定位结果来转向,而实验台依然对照模型实际积分出的位姿来评分。这是 GPS 的惩罚能以一个数字显现出来的唯一原因:0.09 米的均方根误差变成了 1.25 米,转向量也增加到四倍以上。

那条淡色的线表示什么?

它是在当前设置下的完整运行,在你改动任何一个设置的那一刻就计算出来。每拖动一次滑块,整条路线都会在后台用大约二十毫秒重新跑一遍,所以拖动前视距离时,你看到的是它实际产生的轨迹,而不是对轨迹的某种承诺。那条粗线则是你按下开始后,机器人沿同一趟运行播放的动画。

为什么机器人在那个非常急的拐角处总是转个不停?

两个控制器都有一个由轴距和最大转向角决定的最小转弯半径,比这更急的拐角,无论怎么整定都跟不上。真正的解决办法在上游:用倒圆角或圆弧把路径变得平缓,或者在拐角前减速,而这正是运动曲线的用途。任何转向控制器都无法开出车辆本身不具备的几何形状。

延伸阅读

参考资料

权威资料,帮助你越过本模拟器有限的教学模型,进一步深入学习。