反应式导航:教会机器人避开障碍物
你能让机器人自己感知障碍并决定往哪里去——不需要地图,只需要干净的感知和一个行为循环。
反应式导航是大多数机器人学会四处移动的第一种方式:机器人并不持有地图、 也不规划路线,而只是对传感器当下报告的内容作出反应。感知前方空间、做决定、 移动,然后重复,每秒钟重复很多次。它便宜、稳健,而且足以让一台机器人在 一个杂乱的房间里游荡而不撞到任何东西——每一个初学者做的避障机器人 背后都是这套行为。
这条路线一层一层地建立这项技能。你先把一次原始的超声波脉冲变成一个 你可以信赖的距离,然后弄清传感器读数为什么会跳以及怎么滤波。 你把超声波和激光飞行时间放在一起比较,好知道哪种传感器会在什么时候骗你; 再加上一个舵机扫描,让机器人能看清哪个方向是通的;把整套东西包进一个 行为状态机;最后在模拟器里把完整的闭环整定好。
按顺序走完这些节点——每完成一个就会解锁下一个,你的进度会保存在这台设备上。 当你准备动手做真家伙时,这条路线会直接接进避障机器人项目。
开始之前
你需要能读传感器,也能驱动两个电机——电机控制路线 涵盖驱动那一半。这里不涉及地图、定位,也没有任何规划算法;这是刻意的, 也正是反应式导航适合作为第一种做法的原因。
你将会做到什么
- 把一次超声波脉冲变成一个可以据以行动的距离,并配一个超时,使缺失的回波 不会卡住回路;再配一个中值滤波,使一个坏读数不会让机器人突然转向。
- 针对给定的表面说出该信赖哪种传感器,并解释为什么激光飞行时间传感器 和超声波传感器会在完全不同的材料上失效。
- 让传感器扫过一段圆弧,并从读数中挑出最开阔的方位。
- 把行为表达成显式的状态而不是嵌套的条件分支,让“机器人现在在干什么” 永远有一个明确的答案。
大家卡在哪里
**在舵机还没停下来之前就读传感器。**测量结果对应的是扫描途中传感器 正指向的东西,于是机器人会自信地转向一堵墙。在指令完角度之后、发波之前, 加一个稳定延迟。
**回波没有超时。**如果什么都没有回来——而在柔软或倾斜的表面上,
这种情况经常发生——一个天真的 pulseIn 会阻塞整个回路。
机器人看起来会随机地卡死。
**相信单次读数。**超声波传感器偶尔会给出反常的数值。在空旷环境里 一个虚假的 20 cm 读数就足以触发一次紧急转向。取三次,用中间那个。
**倾斜和柔软的表面。**声音会从一堵以陡峭角度背离传感器的墙上反射走, 所以一堵 45° 的墙可能读成空旷。靠垫和窗帘会把这道脉冲完全吸收。 这是一个物理限制,不是 bug——要把行为设计成能在它面前存活下来。
**在阈值上振荡。**只有一个停车距离时,在它附近徘徊的机器人每秒会在 行驶和转向之间翻转很多次。用两个阈值——近了停、远了才恢复—— 这样行为就有了迟滞,并会坚决地做出一个决定。
你需要什么
| 什么 | 这条路线为什么需要它 | 说明 |
|---|---|---|
| 一块 HC-SR04 或 VL53L0X | 整条路线所建立的距离感知 | 分别约 $2 和约 $5 |
| 一个业余级舵机 | 好让传感器能看往正前方以外的地方 | 传感器头用 SG90 就够 |
| 一两个杠杆式微动开关 | 唯一一个从不在碰撞上撒谎的传感器 | 对下面每一种测距失效来说都是便宜的保险 |
| 一台能开的机器人底盘 | 两个你已经会指令的电机和驱动器 | 电机控制路线能带你走到这一步 |
| 一片杂乱的地面 | 测试环境,而且必须同时包含一个柔软表面和一个倾斜表面 | 一个靠垫和一扇开着的门是最好的两个测试障碍 |
为什么按这个顺序
**先感知,后决策,永远如此。**几乎每一个行为异常的避障逻辑,都是在 一个坏读数上正确地动作。在一次距离测量变得可信之前——缺失回波要超时、 取三个值的中位数来杀尖峰——再多的行为逻辑也做不出一台表现良好的机器人。 反过来调试,则意味着要为传感器里的一个故障去怀疑你的状态机。
**先比较传感器,再选定一种。**设置这个比较节点,是因为声呐和激光 会在完全不同的材料上失效,而哪一个才对,完全取决于你正在行驶的那个房间。 有意识地做一次这个决定,比在底盘围绕错误的传感器造好之后才发现要便宜得多。
**先滤波,再扫描。**一次舵机扫掠会把你传感器的错误率乘以采样角度数。 如果单次读数就不可靠,那么九点扫掠给了你九次选错方向的机会, 而机器人会自信地转进一堵墙。
**先扫描,后决策。**只能看见前方的机器人只有两个选择——停下, 或者盲目转向。能够测量多个方位,就把避障从一种反射变成了一种选择, 而这正是行为开始看起来像是有智能的地方。
**先状态机,后算法。**避障算法就是一台状态机;单独把结构先学一遍, 意味着最后那个节点讲的是机器人学,而不是在理清控制流。
**接触感知贯穿全程。**碰撞开关是刻意不放在最后的。这条路线上的每一种 测距传感器都有它看不见的表面,所以一台没有接触感知的机器人, 离一路推到东西被弄坏只差一层帘子。它是整台机器人上最便宜的可靠性。
检查点:如何判断一个阶段已经落地
| 阶段 | 检查内容 | 通过是什么样 |
|---|---|---|
| 距离读数 | 把传感器对准 30 cm 外的墙,打印一分钟 | 稳定在一两厘米以内,没有零值,对准天花板时也不卡顿 |
| 超时 | 把传感器对准空旷处,观察回路速率 | 回路保持它的间隔——没有回波绝不能意味着机器人卡死 |
| 中值滤波 | 反复挥手穿过光束 | 输出里反常的数值消失了;真实的靠近仍然看得出来 |
| 传感器对比 | 测量一个靠垫、一堵 45° 的墙和一块深色哑光表面 | 在测量之前你就能预测哪种传感器会在哪种材料上失效 |
| 舵机扫描 | 扫过一道开着的门,打印每个角度的距离 | 门口明显是最大值,而且读数每次扫掠都重复得上 |
| 稳定延迟 | 刻意去掉你的稳定延迟 | 读数会在各个角度上糊成一片——现在你知道那种失败长什么样了 |
| 状态机 | 每次循环都打印当前状态 | 你永远能说出机器人在干什么,而且每次状态转移都有一个可见的成因 |
| 碰撞开关 | 慢慢按下并数事件 | 按一次恰好产生一个事件,而不是原始开关会产生的那九个 |
| 完整行为 | 在一个杂乱的房间里跑五分钟 | 它存活下来了,而且卡住时你能说出它当时处在哪个状态 |
这条路线到哪里为止
反应式导航有一个硬上限,而且值得直说:一台反应式机器人无法被派往任何地方。 它没有记忆,所以它去不了厨房,无法保证自己已经走遍整个地板, 也无法避开上一次困住它的那个角落。这些不是实现上的空缺—— 它们就是“没有地图”这件事本身的含义。
这条路线同样在你接下来会想要的两件事之前停下。沿墙行走是自然的延伸, 也是第一个开始看起来像规划的行为,因为一台保持与单侧墙面固定距离的 机器人会以确定的方式走遍整个房间。而覆盖——真正扫荡一片区域 而不是在里面游荡——是记忆的缺失最终变得无法忍受的地方。
到那时候,路径规划与建图就是答案, 而这条路线先做是对的:每一台建图机器人仍然需要这里建立的这些反射动作, 以备它的地图被发现是错的时候。
学习路线
路线
按顺序完成各个节点——完成一个就会解锁下一个。你的进度会保存在这台设备上。
已完成 0 / 11
常见问题
常见问题解答
机器人学中的反应式导航是什么?
没有地图、也没有计划的导航。机器人感知此刻前方有什么,决定该怎么应对,移动,然后重复——往往每秒五十次。它从不问自己在哪里,因为它从来不需要知道。这使它便宜、稳健,而且不受那些会让基于地图的导航崩溃的定位误差影响,代价是它做不了任何需要记忆的事:它去不了一个指定的地点,无法保证已经走遍一个房间,还可能被无限期地困在一个凹角里。
为什么我的避障机器人会径直撞上墙?
几乎总是传感器的问题而不是逻辑的问题,而且通常是三个原因之一。超声波传感器以很陡的角度遇到墙时,会把声脉冲反射到别处而不是反射回来,所以一堵 45° 的墙读起来就是空旷——这是物理,不是故障。窗帘、靠垫之类的柔软表面会把声脉冲完全吸收。而如果你在扫描舵机还没转完时就读传感器,得到的距离属于它扫到半路时正指着的东西。在指令角度之后加一段稳定延迟,再加一个碰撞开关,这样即使测距失效,也总能检测到接触。
为什么我的机器人在障碍物前来回抖动?
因为只有一个停车阈值。当机器人在阈值附近徘徊时,微小的测量变化会让决策每秒翻转很多次,于是它结结巴巴,而不是果断地做出决定。用两个中间有间隔的阈值——20 cm 时停下,到 30 cm 才恢复。这个间隔就是迟滞,它会迫使行为做出决定。同样的模式能解决机器人代码里几乎所有由阈值引起的振荡,而不只是这一个。
避障该用超声波还是激光飞行时间传感器?
它们在截然相反的东西上失效,所以一旦你了解自己的环境,选择就很容易。超声波的锥角很宽——半角大约 15°——所以它能检测到一条桌腿,却定位不出它在哪里,而且对柔软和陡斜的表面视而不见。VL53L0X 激光传感器的波束很窄,所以定位很精确,但可能完全漏掉一个细长的障碍物,而且在强烈环境光下,面对深色、哑光和镜面表面会很吃力。要在杂乱的房间里漫游,宽阔的声呐锥角确实是一个优势。要测量到某个特定物体的距离,激光更胜一筹。
避障需要状态机吗?
只要行为超过两个状态就需要,而避障几乎马上就会达到这个数:行驶、停车、扫描、转向、倒车、恢复。用嵌套条件分支来写,一个下午之内就会变得不可读;更糟的是,你会失去回答“机器人此刻在做什么”的能力——而每一次调试都是从这个问题开始的。显式的状态机让这个答案变成一个可以直接打印出来的变量。
反应式机器人会卡住吗?
会,而这是这种方法本身的性质,不是一个你能修掉的缺陷。一台没有记忆的机器人,在凹角或 U 形死胡同里,会朝最开阔的方向转去、往前开,然后回到出发的地方,永远如此。常见的缓解办法是在转向选择里加入随机成分,以及一个卡住检测器,在几次尝试失败之后触发一次更大幅度的脱困动作。真正的解决办法是记忆,也就是一张地图——而那是另一条路线。