做一台避障机器人:感知、扫描与转向
一台自己漫游的机器人——感知障碍、扫描寻找开口、朝空旷处转向——它的每个部分你都先弄懂,并在仿真里调好。
避障机器人是循迹车之后最自然的下一步。循迹车在跟随——沿着别人替它画好的一条线走。而这台机器人在决策:没有赛道,也没有地图,它感知周围的空间并选择往哪里去。这一个差别——对世界作出反应,而不是跟随世界——就是自主能力的第一次真实滋味,而且它仍然简单到可以被完全理解。
核心是一个简短的重复循环:感知—扫描—决策—转向。HC-SR04 超声波传感器向前发出脉冲并计时回声来估算距离;当有东西比安全阈值更近时,机器人停下,用一只 SG90 舵机把传感器左右扫动,然后朝最空旷的方位转去。这个阈值不是随意定的——它是由当前速度、感知决策执行延迟、刹车距离(随速度的平方增长)、机器人的半径以及一份余量共同构成的安全距离,而在模拟器里,这些都能在停车距离曲线上直接看到。
移动车要的零件逐个加上学透:容错 5 V 逻辑 Arduino Uno,超声波和盲区(近到报不出的最小距离),给波束第二个视角的舵机,逻辑脚供不起的电机电流 L298N H 桥开关,两 TT 减速电机减速箱拿转速换可用扭矩,万向轮差速转向两轮底盘,电机逻辑分轨的电池包。技术树还带过两条学习路线——电机控制和反应式导航——循迹见过的 PWM、里程计、滤波导航语境再来。
在花钱或者冒着接错线的风险之前,先在浏览器模拟器里把避障行为调好,直到它能在杂乱的空间里干净地导航。那里的工作空间是俯视的二维空间,射线是瞬时的、没有噪声;而真实的超声波束会扩散约 15°,会被机器人自己的车身挡住,也会被柔软或倾斜的表面扰乱,所以在硬件上你还要对读数做滤波、加一个中值滤波,并且在舵机动作之后加一段短暂的稳定延迟,才敢相信一个距离。在模拟器里找到一个安全的停车距离和一条“空旷方向”的规则,可以在机器人动起来之前消掉大部分猜测。
只有到这一步才去接真实的机器人——触发和回波接到电压正确的引脚上,舵机信号接到支持 PWM 的引脚,电机 PWM 和方向接到驱动器,电机电池只接驱动器的 VM 引脚,所有地连在一起——然后让它在摆着纸箱或椅子的地面上自由活动。同样那些关于感知和滤波的经验,会直接通向Micromouse 墙式迷宫(如果你之后想要建图),或者在你加上一块树莓派之后通向 ROS 2 导航。
技术树从上往下跟。每节点前置做完解锁,进度存这台设备,周末做完不丢位置。
物料单
| 零件 | 数量 | 约价 | 说明 |
|---|---|---|---|
| Arduino Uno | 1 | $5–8 | 5 V 逻辑这里真帮忙——HC-SR04 回波 5 V |
| HC-SR04 | 1 | $2 | VL53L0X 当第二传感器好,不替代 |
| SG90 舵机 | 1 | $2 | 扫描头。长跑 MG90S |
| L298N | 1 | $2–4 | 或 TB6612FNG,电池浪费少得多 |
| TT 减速电机 | 2 | $4 | |
| 两轮底盘 | 1 | $6–10 | |
| 电池包 | 1 | $6 | 6×AA 镍氢或 2×18650 |
| 碰撞开关 | 2 | $1 | **加上。**见下 |
合计约 $30–40。
这两个碰撞开关是整台机器人上最值的四毛钱,也是大多数作品会漏掉的部分。每一个测距传感器都有它看不见的表面——声呐看不见窗帘,也看不见以很陡的角度遇到的墙——而一台没有接触传感的机器人会把窗帘一直推到某个东西让步为止。在包络式保险杠后面装两个开关,就把“通常躲得开东西”变成了“就算有东西看不见也不会卡住”。
怎么连
| 从 | 到 | 说明 |
|---|---|---|
HC-SR04 VCC、GND |
5 V、GND | 约 15 mA,打脉冲尖峰 |
HC-SR04 Trig |
D9 | 任一数字脚 |
HC-SR04 Echo |
D10 | 5 V 输出——在 Uno 上没问题,在 3.3 V 板子上要加分压 |
| 舵机信号 | D6 | Servo 库占 Timer 1,也驱动 D9/D10 PWM |
| 舵机电源 | 独立 5 V,共地 | 堵转 650 mA——不走 Arduino 5 V 脚 |
驱动 ENA、ENB |
D5、D3 | PWM 脚。L298N 使能跳帽拔掉 |
驱动 IN1–IN4 |
D8、D7、D4、D2 | |
| 碰撞开关 | D11、D12,INPUT_PULLUP |
COM 接地,NO 接脚 |
电池 + |
驱动 VM / +12V |
绝不 Arduino |
| 所有地 | 同一点 | Arduino、驱动器、舵机电源、电池负极 |
留意定时器冲突:Servo 库会接管 Timer 1,而在 Uno 上它同时驱动 9、10 脚上的 PWM。把电机 PWM 放在 3、5、6 或 11 上,舵机放在任意引脚上,这个问题就根本不会出现。而如果你把电机使能放在 9 脚上,那么一旦接上舵机,速度控制就会悄悄失效。
停车距离,算不猜
停车阈值是这个项目里最重要的一个数字,而它不是随意定的。它是四段距离之和:
stop_distance = (v x t_latency) + (v^2 / (2 x a_brake)) + robot_radius + margin
| 项 | 来自 | 典型 |
|---|---|---|
| 感知与决策延迟 | 打脉冲(最长 25 ms)、舵机稳定时间、主循环周期 | 60–100 ms |
| 刹车距离 | 速度平方除两倍减速度 | 涨得快 |
| 车半径 | 底盘前沿到旋转中心 | 80–100 mm |
| 余量 | 因为传感器锥角有 15° 宽,而且它对柔软的东西会撒谎 | 50 mm |
算一遍,0.3 m/s、延迟 80 ms、刹车 1.0 m/s² 的车:
= (0.3 x 0.08) + (0.09 / 2.0) + 0.09 + 0.05
= 0.024 + 0.045 + 0.09 + 0.05 = 0.21 m
约 21 cm。速度翻倍 0.6 m/s:
= 0.048 + 0.18 + 0.09 + 0.05 = 0.37 m
阈值没翻倍——涨 76%,刹车项随速度平方。慢走躲得好、加速撞的原因,解是随速阈值不是一刀大切得车到处胆小。
里程碑制作
| # | 里程碑 | 测试 | 通过长这样 |
|---|---|---|---|
| 1 | 电机能驱动 | 架空状态下前进、后退、两个方向原地转 | 六个状态全部正常;你知道了每个轮子的死区 |
| 2 | 距离读数 | 30 cm 墙打印一分钟 | 厘米内稳,无零 |
| 3 | 超时正常 | 对着空旷处和天花板 | 主循环保持它的频率——没有回波绝不能让机器人卡死 |
| 4 | 中值滤波 | 反复把手挥过光束 | 单独的离谱读数消失了;真正靠近时仍然能检测到 |
| 5 | 舵机扫描 | 指令 −60°、0°、+60° 并在每个角度打印距离 | 每次扫描都能重复,且每次打脉冲前都有稳定延迟 |
| 6 | 稳定延迟得到验证 | 故意把延迟去掉 | 读数在不同角度间糊成一片——现在你知道这种失败了 |
| 7 | 停车阈值 | 朝墙开过去并让它自己停 | 它是靠着你算出来的余量停下的,而不是靠运气 |
| 8 | 转向决策 | 把它摆成面对一个拐角、其中一侧是开口的姿势 | 它会朝开口那一侧转,而不是随机乱转 |
| 9 | 迟滞 | 让它停在阈值附近悬着 | 它会明确地做出一个决策,而不是犹犹豫豫 |
| 10 | 碰撞恢复 | 朝一个靠垫开过去 | 声呐漏掉了它,开关抓住了它,机器人倒车并转向 |
| 11 | 自由漫游 | 在杂乱的房间里跑五分钟 | 撑住了;真的卡住时你能说出是哪个状态 |
里程碑 10 正是把演示和机器人区分开的那一步。靠垫会把超声波脉冲完全吸收,于是传感器报告前方是空旷的,机器人就全速撞了上去。没有碰撞开关的话,它会一直往前推,直到电机堵转。
故障排查
| 现象 | 可能原因 | 解决 |
|---|---|---|
| 机器人随机卡死 | pulseIn 没有超时 |
传入 25000 µs 超时;显式处理“没有回波”这种情况 |
| 在空房间里急停 | 把超时当成了 0 cm | 超时意味着远,不是近。返回一个哨兵值 |
| 撞上窗帘和靠垫 | 声音被吸收——这是物理,不是缺陷 | 加碰撞开关 |
| 斜墙撞上 | 打偏接收器收不到 | 同解;多扫角度 |
| 自信地转进墙里 | 舵机还没稳定就读数 | 指令角度之后等 100–200 ms 再打脉冲 |
| 在障碍前犹犹豫豫 | 只有一个阈值,没有迟滞 | 20 cm 停下,要到 30 cm 才继续 |
| 舵机抖板子复位 | 舵机电流过 Arduino | 舵机独立 5 V 供电,共地 |
| 电机调速罢工 | Servo 库占 Timer 1(9、10 脚) |
电机 PWM 挪 3、5、6、11 |
| 永远在拐角里打转 | 没有记忆——这是反应式导航固有的 | 加一个随机分量,再加一个卡住检测与脱困 |
| 躲得慢却撞得快 | 固定阈值,没有考虑刹车平方项 | 让阈值随速度变化 |
| 两台车一起跑时出现离谱读数 | 它们听到了彼此的脉冲 | 把打脉冲的时序错开 |
下一步去哪
**加入沿墙行走。**一台在一侧与墙保持固定距离的机器人,会确定性地走遍房间而不是四处乱撞,而这是第一个开始看起来像“计划”的行为。代码上只是小改动,概念上却是大改动。
加入第二种类型的传感器。VL53L0X 失效的表面几乎和声呐正好相反——前者怕深色哑光和镜面,后者怕柔软和倾斜。两者合起来覆盖的房间,比任何单独一个都多得多。
**接受这个天花板,然后继续往前走。**反应式机器人没法被派往某处,无法保证自己覆盖了地面,还可能在马蹄形的房间里无限循环。这些都是“没有地图”带来的性质,而不是缺陷。等到它们开始变得要紧时,微型迷宫鼠会加上建图与规划,而覆盖机器人则直接处理“我到底有没有到过所有地方”这个问题。
项目路线图
搭建路径
沿着技术树,从零件一路走到一台能正常工作的机器人。每个节点在其前置条件完成后解锁,你的进度会保存在这台设备上。
已完成 0 / 18
元器件
- 控制器Arduino Uno对新手失误很宽容的 8 位开发板,大多数人正是通过它认识机器人的。
- 传感器HC-SR04 超声波传感器装在两美元小板上的声呐探测——机器人就是靠它摸索前方障碍的。
- 执行器SG90 舵机九克重的小舵机,大多数机械臂、夹爪和转向机构背后都是它。
- 驱动器L298N 电机驱动板双 H 桥驱动,把单片机微弱的逻辑引脚信号变成带动电机的动力。
- 执行器直流减速电机(TT 电机)黄色减速箱电机,能把一个光秃秃的底盘变成会跑的机器人小车。
- 底盘两轮驱动机器人底盘一块甲板:两个电机、一个自由万向轮和你的全部电子元件都固定在它上面。
- 电源机器人电池与电源包能正常运行的机器人和不停复位的机器人,差别就在它身上。
本路径中的教程
- 入门 · 22 分钟机器人避障算法:感知、扫描、决策、转向让机器人自主避开障碍物的“感知—扫描—决策—转向”循环。
- 入门 · 20 分钟读取 HC-SR04 超声波传感器:用代码测出可靠距离借助超时和中值滤波,把发射与回波变成稳定的厘米级距离读数。
- 入门 · 18 分钟用舵机带动超声波传感器扫描,寻找开阔空间用舵机带着 HC-SR04 扫一圈,在转弯前找出最通畅的方向。
- 入门 · 阅读约 18 分钟用 PWM 与 H 桥电路控制直流电机用 PWM、H 桥和符合实际的电流限制,安全地接线并控制一台有刷直流电机。
- 中级 · 阅读约 20 分钟用车轮编码器实现差速驱动里程计把左右轮的运动积分成移动机器人的位姿,再识别并标定漂移。
接线之前先练习
用在线模拟器把它调好
搭建路径会经过一个浏览器实验台。先在这里把行为调对,再把参数迁移到真实的机器人上。
常见问题解答
避障机器人是怎么工作的?
它一边往前开,一边用超声波传感器盯着前方的距离。当有东西比设定的阈值更近时,机器人停下,用舵机带着传感器左右扫动,测量每个方向上的距离,然后朝最空旷的方向转过去——再继续往前开。整个过程就是一个每秒运行很多次的简短“感知—扫描—决策—转向”循环。
避障机器人用哪种传感器最好?
默认选择是 HC-SR04 超声波传感器:便宜、容易接线,在几米范围内都很可靠。如果你需要,飞行时间传感器能给出波束更窄、速度更快、精度更高的读数,但对第一台避障车来说,超声波传感器在成本和简单性之间取得了恰当的平衡。
开始这个项目之前需要先买零件吗?
不需要。感知和避障逻辑都在浏览器模拟器里运行,所以你可以在买任何东西之前先理解并调好它的行为。只有最后的制作步骤——接线和装配——才需要实体的 Arduino、HC-SR04、舵机、驱动器、电机、底盘和电池。
为什么我的避障机器人不能正常工作?
三个常见元凶是:超声波读数有噪声或被遮挡(加一个中值滤波,并保持传感器前方无遮挡);舵机还没转到位就去读传感器(加一段短暂的稳定延迟);以及直接从 Arduino 给电机供电而不是经过驱动器(这会导致欠压,让主板复位)。
它和循迹车有什么不同?
循迹车沿着替它铺好的赛道走;避障机器人没有赛道,必须自己决定去哪里。它多了一个扫描传感器和一个真正的决策循环,这使它自然成为继循迹车之后的第二台机器人。