ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

从零复刻开源扫地机器人:嵌入式、SLAM与全栈机器人工程实战

从零复刻开源扫地机器人:嵌入式、SLAM与全栈机器人工程实战 前段时间我把一台开源扫地机器人从底盘拆到了App端一路折腾下来最大的感受是这玩意儿看起来就是个会跑的吸尘器实际上里面藏着一整套机器人工程课程。从STM32上的中断、定时器到Linux端的SLAM、路径规划再到手机App和云端服务几乎把全栈这两个字占全了。如果你正打算找嵌入式项目练手或者想补一补机器人相关的算法和工程知识这台机器是很合适的切入点。不需要你真的去买一台昂贵的整机很多开源方案从硬件到固件再到上位机都能在社区直接拿到你完全可以从零开始复刻、改造甚至在原版基础上接入自己的控制逻辑。下面这篇拆解我按“一台扫地机器人真正涉及的技术栈”来分章节讲尽量把一个开源扫地机器人项目的来龙去脉讲透也把我在实际折腾中遇到的坑和解决方案一并列出来。1. 扫地机器人到底“全栈”在哪里很多人一听“扫地机器人开源项目”以为是某个做硬件的团队把PCB图纸和固件代码放出事实也确实差不多但如果只盯着“能转起来”就太可惜了。一台扫地机器人完整跑起来至少要横跨硬件、嵌入式驱动、感知算法、上层业务逻辑和前端交互这几层每一层又能细分成许多独立的子模块。1.1 一台会扫地的机器涉及的技术栈全景我习惯把扫地机器人拆成五个层面看机械与结构层底盘、驱动轮、万向轮、边刷、滚刷、尘盒、传感器支架。这层决定机器人能不能稳定行走、清扫效果如何。嵌入式传感器层激光雷达LDS、惯性测量单元IMU、沿墙/碰撞传感器、悬崖红外传感器、充电座信号接收模块。机器人的“感觉”全部来自这里。底层控制与驱动层带编码器的直流减速电机、电机驱动芯片或FOC驱动、STM32/ESP32主控、电源管理模块。干掉PID调不好机器走路都是歪的。算法与决策层SLAM建图、定位、路径规划、弓字形覆盖规划、脱困逻辑一般跑在ARM Linux板或树莓派上用ROS/ROS2去组织这些节点。交互与业务层手机App、局域网通信、OTA升级、语音控制、云端地图管理这层就是很标准的全栈开发业务了。这几层堆在一起就是一门机器人工程导论课的目录。单独抽任意一层出来都足够一个新人学一两个月。1.2 开源生态给了我们什么现在的开源扫地机项目其实分几类一种是有完整硬件设计资料的开源整机方案比如很多基于Roomba协议二次开发的板子另一种是针对核心零件做开源比如基于STM32的电机控制板、激光雷达驱动、底盘运动控制固件还有一类是纯软件栈比如基于ROS的导航、建图、避障框架。也有人在开源鸿蒙生态里尝试做家用设备的控制层方案虽然目前主要用在智能家居方向但思路是相通的底层设备通过标准接口上报状态上层应用统一调度。这些公开项目价值在于你不必从零发明轮子可以把每个模块的成熟方案读一遍再自己重新实现一遍这是最好的学习路径。我在实际复刻时最喜欢做的事情就是先把开源项目的代码下载下来不看原作者怎么写的自己先按需求写一遍然后打开源码对比差异。这个过程比看十篇教程都有用。2. 机械与感知扫地机器人怎么“看”周围一台机器要先能把“周围长什么样”感知出来才有可能做到不乱撞、不漏扫、能回家充电。这一部分往往被低估但它恰恰是整套系统里最多坑的地方。2.1 底盘、清扫结构的设计逻辑市售扫地机底盘的常见布局是左右两个带编码器的驱动轮居中偏后前面一个万向轮起支撑作用边刷在右前方通常只有一侧另一侧靠边刷反转把垃圾扫进来滚刷在底部中间尘盒在滚刷后方。开源项目里你常看到的底盘方案是3D打印件加铝板或者直接用市面上成熟的机器人底盘。设计时要注意几个点驱动轮要选带弹簧悬挂的不然过门槛或压线时打滑后果比你想的严重得多滚刷要预留防缠绕结构否则头发缠上去电机就容易堵转发热边刷转速不能太高否则垃圾会被甩出去。如果你是自己做机械部分建议第一版别追求外观光轴加联轴器、亚克力板加铜柱就能撑过整个调试阶段。重要的是给激光雷达留出一个稳定、水平的安装平面雷达抖动会直接导致建图重影。2.2 各类传感器的工作原理与选型建议扫地机器人身上传感器特别多每个传感器负责一种“感觉”下面是我整理的常用配置。传感器类型作用常见型号原理要点激光雷达LDS360度测距、建图定位思岚A1/A2、乐视R1拆机雷达三角测距靠激光发射点与接收点视差计算距离惯性测量单元IMU加速度、角速度感知MPU6050、BMI160融合陀螺仪加速度计提供航向角和姿态参考里程计编码器轮子转了多少圈霍尔编码器、光电编码器根据轮径和编码器计数推算位移和航向增量红外悬崖传感器检测台阶、架空边缘红外对管下方红外反射信号变弱时触发悬崖保护碰撞传感器检测撞到障碍物微动开关、压感条前面撞到东西时触发减速回退充电座感应自动回充对准红外发射管接收管阵列接收充电座发出的方向性红外信号辅助对准这里我给新手的建议是第一版别追求全部传感器一步到位。先用激光雷达编码器IMU把“走不歪、地图不花”调好再往上面加碰撞和悬崖保护的逻辑逐个模块去验证。2.3 感知数据融合的入门理解光有传感器还远远不够难点在于数据融合。拿最简单的直线行驶举例你给两个驱动轮发了相同的PWM但轮子打滑或地面阻力不同车头就偏了编码器读到的里程和真实路径还不一样这就是里程计漂移。所以你要用陀螺仪角速度来修正航向让车尽量走直线这叫航向融合在建图定位里IMU、里程计、激光雷达点云三者又要融合才能得到全局一致位姿估计。开源方案通常直接用ROS里的robot_pose_ekf或更成熟的Cartographer来做这事。我的体会是不要一上来就啃数学推导先把“数据流”搞清楚。比如先看IMU的角速度积分值和轮式里程计给出的航向差了多远再去看融合节点输出的位姿是否更稳定。数据流跑通了以后再回去补滤波公式理解起来快很多。3. 嵌入式底层让机器人“走起来”的核心到了这一层很多做上层应用的朋友会开始觉得吃力但这一层恰恰是“扫地机器人全栈项目”里含金量最高的部分。因为你会在一个很小的MCU里同时面对多任务协调、实时响应、资源受限这三个问题。3.1 主控与电机驱动的方案对比扫地机器人主控常见有两种路线单片机直驱方案用STM32F407或类似主频较高的MCU直接读取传感器、控制电机、跑简单避障逻辑。适合入门代码量小坑少。Linux板MCU前后端方案树莓派/瑞芯微板子跑ROS、激光雷达驱动和算法STM32只做电机控制和传感器采集两者通过串口或CAN通信。这是产品级的典型架构也是“全栈”最完整的形态。电机驱动这块最入门的是L298N或DRV8833这类H桥驱动配带编码器的直流减速电机PWM调速加DIR换向足够用。想再进阶一些可以用RTT或VESC这类开源FOC固件搭配无刷电机BLDC效率更高、噪音更小但调试难度会陡增既要调电流环、速度环还要处理换相逻辑。我踩过的坑是新手不要一上来就玩FOC无刷。有刷直流减速电机调PID调不好最多是走不直无刷调不对直接就是炸管或电机啸叫对信心的打击是毁灭性的。先把有刷调明白再学FOC不迟。3.2 差速轮运动学与PID调速扫地机器人几乎都是差速轮结构两个轮子独立驱动通过左右轮速度差实现前进、转向。底盘运动学就两个公式线速度 v (v_left v_right) / 2角速度 ω (v_right - v_left) / wheel_base控制上PID是绕不开的一环。机器人要按指令线速度和角速度运动就要让左右轮实际转速稳定在目标值附近一个典型的PID调速循环大概是error target_speed - current_speed; integral error * dt; derivative (error - last_error) / dt; output Kp * error Ki * integral Kd * derivative;调PID的实操心得先把Kp和Kd调好让速度从0启动没有明显过冲再慢慢加Ki消除稳态误差。不要五个参数一起调否则你会陷入怎么弄都振动的死循环。我测试时用的方法是给轮子空转悬空观察编码器实时反馈曲线把响应调到又快又不啸叫再加上负载测试。3.3 RTOS、中断与任务划分底层代码并不是一个死循环怼到底。等传感器一多你会发现每个传感器都要“时不时采样”电机要“每20ms更新一次速度”与上位机的串口通信要“一直收”、还要“快速回发”一个循环里全部轮询会顾此失彼。所以开源项目一般会用实时操作系统RTOS来划分任务低优先级处理传感器慢速采样、任务调度中等优先级跑里程计积分和电机PID高优先级处理无线遥控、急停、悬崖触发这类实时性要求高的中断事件。我最初的代码是裸机大循环串口偶尔收包慢了就把PID周期拖垮机器走起来一顿一顿的。换成FreeRTOS后把PID放在固定频率任务里通信只做队列收发问题瞬间消失。嵌入式里的“实时”不是绝对快而是“在该发生的时间点一定发生”理解了这句话你的架构能力会上一个台阶。3.4 电源管理与低电量逻辑扫地机器人是电池供电的这一块容易被新手忽略。移动平台最怕的就是电压不稳导致的电机堵转、主控复位用了降压模块也要注意电池从4.2V掉到3.7V时DC-DC的输入范围。我做的这个开源项目的电源方案也比较直白18650电池组或单节锂聚合物电池经过升压或降压给主控和电机供电。电压检测脚接在电池正极通过电阻分压进ADC。当电压低于阈值时代码里最优先的任务是停止清扫把地图保存然后低速回充电座这个“低电量回充”在整机里算一个比较完整的业务闭环值得自己手写一遍。4. SLAM与路径规划机器人怎样“知道”自己在哪到了算法层这台扫地机的“科技感”才真正爆发。前面说的走起来只是腿脚到了这一层才算有大脑。4.1 激光SLAM的两条主流路线开源扫地机器人最常见的建图定位方案是激光SLAM。我见过的两类主流算法是Gmapping基于粒子滤波适合小场景、计算量低地图效果稳定是入门首选。Cartographer基于图优化能在大场景下保持一致性但代码复杂学习和调参成本高。我建议新人先把Gmapping跑起来用传感器消息播放或者真机数据都行。当你能看到地图一点点构建出来那种成就感是很强的。之后再切换到Cartographer对比两种算法的体感和建图质量差异。ROS里跑SLAM的大致流程是这样激光雷达驱动节点发布/scan话题里程计发布/odomTF树做好base_link到laser的坐标变换然后slam_gmapping订阅这些话题输出occupancy grid地图。4.2 全局规划与局部避障有了地图和实时定位之后机器人要决定“怎么走”。这里分两层全局规划基于已知地图规划出一条从当前位置到目标点的无碰撞路径。扫地机器人用得多的有Dijkstra和A*算法在ROS里就是navfn或global_planner插件。局部规划机器人按全局路径走的时候遇到临时障碍物比如拖鞋、电线要靠局部规划器实时避障。扫地机上最常见的开源方案是DWA动态窗口法它会从速度和角速度组成的选择空间里找一条能避开障碍又最接近目标的轨迹。我遇到过一种很典型的问题地图建得挺好的但导航时机器人就是会卡在一些窄缝里反复摇头。排查后发现是膨胀半径和机器人半径设得偏大CRITICAL路径把门缝判成不可通行。把膨胀半径改小以后立刻顺畅了。4.3 弓字形清扫与分区覆盖扫地机的“干活能力”取决于覆盖策略单纯从A点到B点导航是不够的。产品级扫地机一般是把地图栅格化划分成多个房间分区然后在每个分区里跑弓字形Boustrophedon路径让清扫轨迹密铺整个区域。开源项目里这一块有时候做得比较简陋很多是“随机游走碰壁再转向”但这种覆盖率确实很不稳定。我自己写清扫覆盖模块时是把地图转成二维栅格数组用“沿墙弓字扫描”的思路边条区域用mark标记遇到已清扫区域就转向。这个实现思路并不特别难但非常锻炼空间数据处理和状态机设计能力。5. 上层软件与交互ROS、服务端与App到了这一层“扫地机器人”已经完全变成一个软件工程问题了。很多做嵌入式或机械的朋友会在这里看到另一个世界原来设备是被这么多层的软件托起来的。5.1 ROS与机器人通信的基础概念在Linux板子上跑机器人算法几乎绕不开ROS机器人操作系统。ROS不是一个操作系统它是一个分布式通信框架把程序组织成多个节点节点之间通过话题topic、服务service和动作action通信。比如你有一个激光雷达驱动节点发布/scan话题一个SLAM节点订阅/scan并发布/map和/odom一个导航节点订阅/map和/odom发布/cmd_vel控制指令底层STM32通过串口桥接节点订阅/cmd_vel解析出左右轮速度再发串口给MCU执行。这种架构的精髓是解耦每个功能模块都是独立程序可以单独重启、替换、调试。你在终端里跑几个rosrun就能像搭积木一样把一台扫地机的软件系统拼出来。5.2 从嵌入式到上位机的数据链路如果你想直接从自己写的单片机代码控制整个机器人不需要ROS也能做但数据链路的复杂性一样不少。最朴素的方案是STM32通过串口不断向上位机发送状态帧比如速度、里程、IMU角速度、电压、传感器状态用固定帧头加校验的方式打包。上位机可以是Linux板或PC接收后一边解析成机器人状态一边向下发PWM速度指令或路径指令。我在这个项目里用了一个非常简单但实用的自定义协议帧头(0xAA) 指令码(1字节) 数据长度(1字节) 数据体(N字节) CRC8校验(1字节)注意串口通信一定要加校验和超时重传机制否则电磁干扰或拔插线缆时出现一帧脏数据机器人就可能乱跑甚至撞墙。我因为这个吃过亏后来所有发给电机控制的指令都加了CRC校验和指令有效性窗口一帧错误就立即急停。5.3 手机App、MQTT与全栈工程化到了App这一层很多嵌入式工程师会望而却步但其实只要把上一层的通信协议设计清楚App这部分就是纯粹的业务开发了。常见的架构是扫地机器人连上局域网Wi-Fi通过MQTT或者自研TCP协议和手机App通信。App负责下发清扫指令、显示机器人状态远程回传现场视频。如果你希望支持手机随时随地控制就需要加一个云端服务器机器人端上报状态云端做状态同步和指令缓存App再从云端拉数据。这一下就变成了标准的“端-云”全栈项目。做得好的开源扫地机器人项目会把地图数据以图片或栅格协议传回AppApp端画布渲染出地图然后用手指点击设置清扫点或禁区。这一块需要你掌握前端画布、栅格坐标转换、多端协议一致性非常涨经验。6. 实操复盘从零复刻一台开源扫地机器人的建议路线纸上谈兵差不多了说说我怎么复刻的。给想动手的同好们一个可参考的路线和预算。6.1 硬件入门清单与预算参考我用的入门方案是“Linux板 STM32底盘 激光雷达”总预算控制在1500元以内。部件作用参考预算STM32F407开发板底盘控制主控60元左右带编码器的直流减速电机2个动力与里程计输入70元左右电机驱动模块DRV8833或双H桥电机调速30元左右MPU6050模块IMU姿态感知15元左右思岚A1激光雷达激光SLAM核心300元左右闲鱼更便宜树莓派4B或香橙派上位机跑ROS300元左右亚克力底盘/3D打印件机器本体100元左右电池、降压模块、稳压板供电系统100元左右如果你手里已经有现成的遥控车底盘可以先只加雷达和主控省下一大笔。别一上来就买全套高配先让机器能走直线、能建一张像样的图再谈后面的事。6.2 分阶段学习与开发路径我的建议是按照下面几个阶段推进别跳步控制级2~3周先把STM32和电机驱动跑通用串口发速度指令控制车轮正反转读编码器算实际转速。闭环级1~2周写PID调速函数让轮子转速稳定跟随目标值保存里程计数据。感知级2~3周接上激光雷达和IMU在ROS里发布/scan和/imu验证数据质量。建图级2周跑通SLAM手动遥控让机器人把客厅扫一圈生成一张房间地图。导航级2周在生成的map上设置目标点让机器人自己走过去避障观察位姿和路径。全覆盖级2周以上实现或接入扫地业务逻辑分区-弓字形覆盖-低电量回充这时候它就真的像一台扫地机器了。这套流程走下来哪怕你以前只是写过单体应用的背景也能对机器人工程有一个很立体、很具体的认识。6.3 开源项目里的经典参考想深入学习有几个开源项目值得反复读各大厂商开源的底盘控制方案学习如何把PID、里程计、速度控制封装成可复用的固件模块。ROS生态里的navigation导航栈它是扫地机路径规划的标准参考实现。各类开源电机控制固件比如VESC、Moteus它们把电机控制做到极致是进阶参考。开源鸿蒙生态里的分布式设备管理思路对打通手机-设备这条链路很有启发。我的建议是不要只是下载下来跑每个开源项目都问自己三个问题这个模块为什么放在这一层换成别的方案行不行我能不能自己写一个简化版7. 常见问题与排查技巧实录折腾机器人必然会遇到各种奇葩问题。我把自己踩过的典型坑整理成一个速查表给正在复刻的朋友扫雷。7.1 问题速查与解决方案现象大概率原因排查与解决机器人走不直频繁偏航左右轮PID参数或机械负载不一致让两轮空转比较速度曲线分别整定PID检查轮胎磨损和悬挂地图扭曲、重影里程计漂移较大或激光雷达晃动检查轮子打滑固定雷达支架正确配置TF坐标提高雷达扫描频率建图时机器人在原地转圈但地图不建立TF树缺变换或/odom话题没有数据用rqt_tf_tree查TF树确保base_link、odom、laser坐标链完整导航卡在窄门或不走路径膨胀半径设置过大调低膨胀半径确认机器人半径参数真实悬崖传感器频繁误触发深色地毯或强光干扰红外传感器调低触发阈值增加延迟滤波必要时增加距离阈值判断充电回充时对不准只用了红外居中信号增加红外两侧信号差分对准再加电流检测确认已成功接触串口偶发乱码导致乱动未加校验或波特率附近干扰给协议加CRC校验指令失效窗口异常数据立即急停电池电压低时主控重启降压模块余量不足或线序压降大换宽压模块用粗硅胶线单独给主控供电视频流不流畅App端直接拿原始数据流渲染降低分辨率/帧率或换低延迟流媒体方案7.2 排查思路与防坑心得我踩过最深的一个坑是地图看起来蛮正常但机器人一到某个角落就“迷路”般乱撞。折腾了一周才发现是那个位置的激光雷达被一个凸起的支架挡了一小段视野导致那个方向永远有“墙”。解决方式非常简单把雷达装到整机最高处保证360度无遮挡。另一个心得和打滑有关。扫地机器人是在家里跑的越是干净的地板越容易“脚滑”。轮子一打滑里程计瞬间漂移一大截地图就会拉伸变形。我后来在一个开源方案里学到了应对方法当IMU检测到的加速度变化和轮式里程计推算的速度不一致时降低里程计的置信度让定位更多依赖激光匹配。这个思路简单有效推荐给大家。最后提醒一句调试扫地机器人一定要在物理上留出急停开关或者把“5秒无有效指令自动停止”写死在固件里。我见过不止一次机器人开去撞墙的场面有了安全兜底你才敢大胆试参数学算法。7.3 从复刻走向“自己的项目”如果你跑通了一台开源扫地机器人下一步怎么进阶我也顺便聊几句。一个方向是改造机械结构换更大的尘盒、加拖地模组、改悬挂。另一个方向是升级算法把简单走迷宫式清扫改成真正的分区覆盖和断点续扫也可以研究视觉识别在前端加摄像头做物品识别。还有一个方向是纯软件把 App 从局域网改造成云平台远程控制上地图渲染和语音指令。我个人在实际操作中最大的体会是完成复刻只是第一步真正有价值的是把某一条链路换成“自己的实现”。不管是自己写一遍覆盖路径规划还是自己设计一套通信协议每一次“不照搬原版”的改动都会逼你把原理吃得更透。最终你会发现这台会扫地的机器其实是一套可以反复拆装重组的机器人工程实践平台永远有下一个可以折腾的模块等着你。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进