
扫地机器人这几年从智商税变成了真香家电但真正让我着迷的不是买一台成品而是自己攒一台。原因很简单市面上的成品机把SLAM、导航、路径规划这些最核心的东西全封装在黑盒里你永远不知道它为什么在这个角落卡住、为什么漏扫那块地毯。自己动手做一台从底盘运动控制到激光建图再到自主导航整条链路全部打通那种它真的自己跑起来了的成就感是买十台成品都换不来的。这篇文章面向三类人一是想入门ROS2机器人开发但不知道从哪下手的学生和转行者二是玩过STM32、想往上层算法延伸的嵌入式工程师三是单纯想搞明白扫地机器人到底怎么工作的技术爱好者。我会把攒一台扫地机器人的三条技术路线讲清楚再给出一张从零到能跑的完整路线图包括底盘选型、传感器配置、ROS2环境搭建、SLAM建图、Nav2导航这些关键环节以及我在实操中踩过的那些坑。1. 先想清楚你要走哪条路线攒扫地机器人这件事最容易犯的错是一上来就买零件。我见过太多人兴冲冲下单了激光雷达和电机结果发现底盘和雷达的通信协议对不上或者算力板根本跑不动SLAM最后零件全吃灰。所以在动手之前先确定路线路线决定了你的预算、时间投入和技术栈。1.1 三条路线的本质区别我把攒机路线分成三条核心区别在于你愿意自己造多少东西。路线一成品底盘 上层开发。买一个带电机、编码器、驱动板的成品移动底盘比如两轮差速底盘你只负责在上面装雷达、装算力板、跑ROS2。这条路线把最脏最累的底层运动控制外包了你专注在SLAM和导航上。适合想快速看到机器人跑起来、主要兴趣在上层算法的人。预算大概在1500到3000元。路线二STM32自研底盘 ROS2上层。底盘完全自己搭STM32做主控驱动直流减速电机或步进电机读编码器做里程计通过串口和上位机通信。上位机跑ROS2做SLAM和导航。这条路线软硬通吃是嵌入式工程师最舒服的路线也是最能学到东西的路线。预算大概在1000到2500元但时间投入是路线一的两三倍。路线三全栈从零连雷达数据都自己处理。用STM32或树莓派直接对接激光雷达自己写建图算法不依赖ROS2的现成包。这条路线我不推荐新手走除非你的目标就是深入理解SLAM算法本身。因为你要自己实现栅格地图、扫描匹配、位姿图优化工作量巨大而且很容易在调试阶段失去信心。三条路线的对比如下维度路线一成品底盘路线二STM32自研底盘路线三全栈自研底层运动控制厂商搞定自己写自己写SLAM/导航ROS2现成包ROS2现成包自己实现技术门槛中中高极高时间投入1-2周1-2个月半年以上预算1500-30001000-25002000学习收益上层算法软硬全链路算法底层适合人群算法入门嵌入式工程师算法研究者1.2 为什么我推荐大多数人走路线二路线一看似省事但有个隐藏问题成品底盘的里程计精度和通信协议往往是黑盒当你后面想调优导航参数时会发现底盘的响应延迟、里程计漂移这些底层问题你根本改不了。而路线二虽然累但每一个环节你都清楚出了问题能定位到具体是哪一层。路线二的关键在于STM32和上位机的分工要清晰。我的做法是STM32只负责实时性要求高的活——电机PID控制、编码器读取、里程计积分、超声波避障然后以固定频率比如50Hz通过串口把里程计数据打包发给上位机同时接收上位机下发的速度指令。上位机树莓派或迷你主机负责跑ROS2、激光雷达驱动、SLAM、Nav2。这个分工的核心逻辑是实时控制放在MCU重计算放在CPU各干各擅长的。注意串口通信的波特率别低于115200否则50Hz的里程计数据加上速度指令会丢包。我一开始用9600里程计数据延迟肉眼可见机器人走起来像喝醉了。1.3 底盘机械结构的几个硬指标不管你走哪条路线底盘机械结构有几个参数直接决定后面SLAM和导航好不好用。轮距和轴距两轮差速底盘两个驱动轮的中心距叫轮距这个值要准确测量因为里程计解算要用。轮距测不准机器人转90度实际只转了80度建出来的地图就是歪的。驱动轮直径同样影响里程计。而且轮子直径要一致我见过有人用两个不同批次的轮子直径差了2mm跑直线跑着跑着就偏了。万向轮位置万向轮要放在底盘重心附近否则驱动轮抓地力不足容易打滑。打滑是里程计最大的敌人一打滑里程计就飘SLAM就崩。雷达安装高度激光雷达要装在底盘最高处且水平。雷达倾斜哪怕2度扫出来的墙面就是斜的建图会有重影。我建议用带水平泡的支架装完拿手机水平仪App校准一下。2. STM32底盘固件从电机转动到里程计输出这一章是路线二的核心也是整个项目里最容易翻车的地方。很多人STM32玩得很溜但一到把电机转动变成ROS2能用的里程计这一步就卡住了。我把它拆成几个关键环节讲。2.1 电机选型与驱动直流减速电机还是步进电机扫地机器人底盘常用两种电机直流减速电机带编码器和步进电机。直流减速电机的优势是扭矩大、转速高、驱动简单配合霍尔编码器能测速和测方向。缺点是低速时控制精度一般需要PID闭环。我推荐用带AB相霍尔编码器的直流减速电机减速比选1:30到1:50之间轮径65mm左右这样线速度大概能到0.3到0.5m/s适合室内扫地场景。步进电机的优势是开环也能精确定位低速扭矩好。缺点是高速扭矩衰减快而且容易丢步丢步了里程计就错了。如果你用步进电机建议用带闭环的驱动器或者至少加编码器做校验。驱动芯片方面直流电机常用TB6612或DRV8833步进电机常用DRV8825或TMC2209。这里有个坑TB6612的峰值电流只有3.2A如果你电机堵转电流超过这个值驱动会烧。选驱动前先看电机的堵转电流参数。2.2 编码器读取与里程计解算编码器读取有两种方式定时器编码器模式和外部中断。STM32的定时器自带编码器模式直接读CNT寄存器就能得到计数值效率最高。我建议用TIM2和TIM3分别接左右轮的AB相。里程计解算的核心公式每脉冲行驶距离 (轮子周长) / (编码器线数 × 减速比 × 4) 左轮行驶距离 左轮脉冲数 × 每脉冲行驶距离 右轮行驶距离 右轮脉冲数 × 每脉冲行驶距离 机器人前进距离 (左轮行驶距离 右轮行驶距离) / 2 机器人转角 (右轮行驶距离 - 左轮行驶距离) / 轮距这里的×4是因为AB相编码器四倍频。如果你用的是单相编码器就不乘4。这个公式看着简单但每个参数都要实测校准。轮子周长别用理论值拿卷尺量实际滚动一圈的距离。轮距也别用卡尺量轮子中心距让机器人原地转10圈看实际转了多少度反推轮距。提示里程计校准有个土办法——让机器人直线走3米看里程计报了多少如果报2.9米就把每脉冲行驶距离乘以3/2.9。反复几次就能校准到1%以内。2.3 串口通信协议设计STM32和上位机的通信协议要简单可靠。我用的帧格式是帧头(0xAA 0x55) 数据长度 数据类型 数据载荷 校验和数据类型分两种上行STM32发给上位机是里程计数据下行上位机发给STM32是速度指令。里程计数据包含x、y、theta和线速度、角速度用float或int16打包。速度指令包含目标线速度和目标角速度。校验和用简单的累加和就行别用CRC16增加计算量还容易写错。关键是帧头要选不容易出现在数据里的值0xAA 0x55这种交替的比较好。STM32这边用串口空闲中断加DMA接收这样不占用CPU。发送用DMA避免阻塞主循环。主循环里跑PID和里程计积分频率控制在50Hz到100Hz。2.4 PID调参让机器人走直线两轮差速机器人走直线靠的是两个轮子速度一致但电机特性有差异必须用PID闭环。我的做法是外环是速度环输入是目标线速度和角速度输出是左右轮目标转速内环是电流环或直接PWM。调参顺序是先调单轮速度环。给左轮一个固定目标转速看实际转速调P和I直到响应快且不震荡。然后两个轮子都调好再跑直线测试。如果走直线偏说明两个轮子的PID参数不一致或者机械阻力不同微调其中一个的I参数。这里有个经验积分项I别给太大否则启动时会积分饱和机器人会猛地冲一下。我一般给I限幅或者用积分分离——误差大的时候不积分。3. ROS2环境搭建与激光雷达接入底盘能动了接下来是让上位机跑起来。ROS2的版本选择很关键我推荐Humble因为它是LTS版本社区包最全Nav2和SLAM Toolbox都支持得好。Ubuntu 22.04配Humble是当前最稳的组合。3.1 ROS2安装与工作空间初始化安装ROS2 Humble用apt最省事但要注意源和密钥别搞错。装完之后先跑个小乌龟测试确认环境没问题。然后创建工作空间mkdir -p ~/robot_ws/src cd ~/robot_ws colcon build source install/setup.bash工作空间的目录结构要规划好我建议按功能分包robot_bringup放launch文件robot_description放URDFrobot_driver放底盘和雷达驱动robot_navigation放Nav2配置。这样后面维护清晰。注意每次打开新终端都要source一次setup.bash嫌麻烦就写进.bashrc。但别把工作空间的setup写进.bashrc否则多个工作空间会冲突。3.2 激光雷达选型与驱动激光雷达是扫地机器人的眼睛。常见的有单线雷达和固态雷达。单线雷达比如RPLIDAR系列便宜、驱动成熟但只能扫一个平面。固态雷达体积小、寿命长但价格高。对于攒机我推荐单线雷达扫描半径8到12米足够室内用。接入ROS2需要装对应的驱动包然后配置串口权限。这里有个经典坑雷达的串口设备名会变今天叫ttyUSB0明天可能叫ttyUSB1。解决办法是用udev规则绑定设备名根据雷达的USB VID/PID创建固定软链接。雷达驱动发布的话题是sensor_msgs/LaserScan在RViz2里能看到扫描点。如果点云是歪的检查雷达安装是否水平如果扫描范围不对检查雷达的angle_min和angle_max参数。3.3 URDF建模让ROS2认识你的机器人URDF是ROS2里描述机器人几何和运动关系的文件。你需要定义底盘、两个驱动轮、万向轮、雷达的link和joint。关键是joint的类型驱动轮是continuous连续旋转万向轮是fixed或continuous雷达是fixed。URDF里最容易错的是坐标系方向。ROS2约定x向前y向左z向上。雷达的坐标系要和底盘坐标系对齐否则建图会错位。我建议在URDF里给每个link加一个简单的立方体或圆柱体visual方便在RViz2里检查。写完URDF后用robot_state_publisher发布TF树用joint_state_publisher发布关节状态。在RViz2里能看到机器人模型和TF坐标系确认没问题再往下走。3.4 底盘驱动节点把串口数据变成ROS2话题底盘驱动节点是连接STM32和ROS2的桥梁。它要做两件事一是订阅/cmd_vel话题把速度指令通过串口发给STM32二是从串口读里程计数据发布/odom话题和TF变换。/odom话题的类型是nav_msgs/Odometry包含位姿和速度。TF变换是odom到base_link的变换这个变换由里程计提供。注意里程计会漂移所以odom坐标系是局部的后面SLAM会提供map到odom的修正。写这个节点用Python或C都行。Python开发快C性能好。我建议先用Python跑通后面如果需要高频再换C。节点里要注意串口读取的线程安全别在主线程里阻塞读。4. SLAM建图让机器人认识环境SLAM是扫地机器人的灵魂。简单说就是机器人一边走一边画地图同时知道自己在地图的哪个位置。ROS2里最常用的SLAM包是slam_toolbox支持在线建图和保存地图。4.1 slam_toolbox配置与启动slam_toolbox的配置参数很多但新手只需要关注几个max_laser_range设成雷达实际量程resolution设成0.05米5cm一个栅格map_update_interval设成1秒。模式选mapping。启动顺序很重要先启动底盘驱动和雷达驱动确认/odom和/scan话题都有数据再启动slam_toolbox。启动后在RViz2里添加Map显示应该能看到地图逐渐长出来。建图时用手动遥控机器人走一圈速度别太快0.2m/s左右。走太快雷达数据匹配不上地图会糊。转弯时慢一点让雷达多扫几帧。我一般让机器人沿着墙走一圈再走几个房间地图就基本完整了。4.2 建图质量差的几个原因建图糊、重影、墙壁歪是新手最常遇到的问题。我总结了几条排查链路第一里程计不准。这是最常见的原因。如果里程计报的转角和实际转角差得多SLAM的扫描匹配就会失败。回去校准里程计走直线和原地转圈测试。第二雷达安装不水平。雷达倾斜会导致扫描平面不是水平面扫到的墙是斜线。用水平仪校准。第三雷达数据时间戳不对。如果雷达驱动的时间戳用的是系统时间而不是雷达内部时间会导致TF变换错位。检查雷达驱动的参数。第四环境特征太少。如果房间全是白墙雷达扫不到特征SLAM会迷失。这种情况可以贴一些标记物或者用带反光板的雷达。第五机器人速度太快。雷达扫描频率是固定的走太快两帧之间位移太大匹配不上。降速。4.3 地图保存与加载建好图后用nav2_map_server的map_saver保存地图会生成.pgm和.yaml两个文件。.pgm是栅格图.yaml是元数据分辨率、原点、阈值。保存的地图后面导航时要用。加载地图用map_server节点发布/map话题。注意地图的origin参数要和建图时的起点一致否则导航时机器人初始位置会偏。提示建图时机器人起点最好选一个特征明显的位置比如门口或墙角。这样后面导航时用AMCL定位能快速收敛。5. Nav2导航从能建图到能自己跑建图只是第一步让机器人自己规划路径、避开障碍、到达目标点才是扫地机器人的完整形态。Nav2是ROS2的导航框架功能强大但配置复杂。5.1 Nav2的核心组件与数据流Nav2由多个节点组成核心的有bt_navigator行为树导航、planner_server全局规划、controller_server局部控制、recoveries_server恢复行为、amcl定位、map_server地图。数据流是这样的你给一个目标点bt_navigator启动行为树调用planner_server算全局路径然后controller_server跟踪路径并发布/cmd_vel同时amcl根据雷达和地图修正机器人位置。如果卡住了recoveries_server会执行恢复行为比如后退、旋转。5.2 代价地图配置让机器人知道哪里能走代价地图是Nav2的核心概念分全局代价地图和局部代价地图。全局代价地图基于静态地图局部代价地图基于实时雷达数据。配置的关键参数inflation_radius是膨胀半径决定机器人离障碍物多远。设太小会撞设太大会卡在窄道。我一般设成机器人半径加5cm。cost_scaling_factor是代价衰减系数影响路径贴墙的程度。局部代价地图的obstacle_range和raytrace_range要根据雷达量程设。obstacle_range是标记障碍的距离raytrace_range是清除障碍的距离。设反了会导致障碍物标记不消失。5.3 行为树与恢复行为Nav2用行为树组织导航逻辑。默认的行为树是规划路径→跟踪路径→如果失败→清除代价地图→重新规划→如果还失败→旋转→如果还失败→后退。行为树可以自定义但新手先用默认的。恢复行为里spin和backup最常用。spin是原地旋转找路backup是后退。这两个行为能解决大部分卡死情况。如果机器人经常卡在同一个地方说明代价地图配置有问题或者雷达有盲区。检查雷达安装位置确保没有遮挡。5.4 定位AMCL与里程计的配合AMCL是自适应蒙特卡洛定位用粒子滤波根据雷达和地图估计机器人位置。它发布map到odom的TF变换修正里程计漂移。AMCL的参数里min_particles和max_particles控制粒子数laser_model_type选likelihood_field。初始位置要手动给在RViz2里用2D Pose Estimate点一下。定位不准的常见原因地图和实际环境不一致比如家具挪了位置、雷达数据噪声大、粒子数太少。我建议建图后别挪大件家具否则要重新建图。6. 攒机路上那些没人告诉你的坑前面讲的都是应该怎么做这一章讲实际做的时候会怎么翻车。这些是我和身边朋友踩过的坑文档里不会写。6.1 电源系统的隐形杀手扫地机器人是移动的电源系统比想象中复杂。STM32要5V或3.3V电机要12V雷达要5V上位机要5V。如果用一个电池加多个降压模块要注意共地。我见过有人忘了共地串口通信时好时坏查了一周才发现。电池选锂电还是铅酸锂电轻、能量密度高但需要保护板。铅酸重但便宜。我推荐3S锂电11.1V配一个12V转5V的降压模块给雷达和上位机。电机直接接12V。注意电机启动瞬间电流很大会把电压拉低导致STM32复位。解决办法是电机电源和逻辑电源分开或者加一个大电容缓冲。6.2 串口通信突然连不上STM32的CAN通信突然连不上、串口突然没数据这类问题我遇到过好几次。排查顺序先看硬件连接再看波特率再看终端电阻最后看软件。CAN通信需要120欧姆终端电阻少了通信不稳定。串口通信要注意TX和RX交叉接很多人接成TX对TX当然没数据。还有STM32的串口引脚要配置成复用推挽输出别配成普通IO。如果用的是USB转串口模块注意模块的芯片。CH340便宜但驱动偶尔抽风CP2102稳定但贵一点。我建议用CP2102。6.3 雷达数据在RViz2里不显示雷达驱动跑起来了但RViz2里看不到点云。排查先看话题有没有数据ros2 topic hz /scan再看frame_id对不对最后看RViz2的Fixed Frame设对没有。最常见的原因是frame_id和URDF里的雷达link名字不一致。比如雷达驱动发布的是laser_frameURDF里叫laser_linkTF树就断了。改成一致就行。还有一个坑雷达的扫描角度范围。有些雷达默认只扫180度你以为它坏了其实是配置问题。看驱动的angle_min和angle_max参数。6.4 Nav2规划失败机器人原地转圈Nav2启动后给目标点机器人原地转圈不走路。这通常是定位没收敛或代价地图有问题。先看AMCL的粒子云如果粒子散得到处都是说明定位没收敛。检查初始位置给对没有地图和实际环境是否一致。如果粒子收敛了但机器人还是不动看全局路径有没有规划出来。如果路径是空的说明目标点在障碍物里或者代价地图把目标点标记成障碍了。局部规划失败的话看controller_server的日志通常是局部代价地图里没有可行路径。调小inflation_radius试试。6.5 建图时机器人跟随焦点随意移动这个现象我遇到过建图时机器人明明没动地图却在漂移。原因是雷达数据里有动态障碍物比如走动的人SLAM把这些动态点当成了环境特征。解决办法建图时清场别让人在雷达范围内走动。如果无法避免可以在slam_toolbox里调大minimum_travel_distance和minimum_travel_heading让SLAM不那么敏感。还有一个原因是里程计漂移。如果机器人静止时里程计还在累积说明编码器有噪声或者PID在震荡。检查电机是否真的停了编码器读数是否稳定。7. 从能跑到好用进阶优化方向机器人能自己导航了但离好用还有距离。这一章讲几个进阶优化方向让你的扫地机器人从能跑变成跑得好。7.1 覆盖路径规划让扫地不漏扫Nav2默认是点到点导航但扫地需要覆盖整个区域。覆盖路径规划Coverage Path Planning是专门解决这个问题的。常见算法有牛耕式Boustrophedon和螺旋式。牛耕式就是来回扫像耕地一样。实现思路是把地图分成若干单元格规划一条经过所有单元格的路径。ROS2里有nav2_coverage相关的包但成熟度一般可能需要自己写。我的做法是简化版把房间分成几个矩形区域每个区域用牛耕式路径区域之间用Nav2导航连接。这样实现简单效果也够用。7.2 多传感器融合超声波和IMU单靠雷达机器人对低矮障碍物比如拖鞋、电线检测不到。加超声波传感器能补盲。STM32上接几个超声波模块检测到障碍就通过串口上报ROS2这边转成/ultrasonic话题在代价地图里标记。IMU能提供角速度和加速度和里程计融合能提高定位精度。ROS2里有robot_localization包做EKF融合。IMU选MPU6050或ICM20602通过I2C接STM32数据打包进里程计帧里。7.3 回充与自主充电扫地机器人没电了要自己回去充电。这需要充电桩有红外或视觉标记机器人能识别并对接。实现上充电桩发红外信号机器人上装红外接收器靠近时根据信号强度调整方向。ROS2这边可以设一个充电桩位置为特殊目标点电量低时自动导航过去。对接阶段用红外引导精度要求高需要单独写控制逻辑。7.4 远程监控与数据记录想在外面看机器人状态可以用ROS2的ros2 bag记录数据或者用WebSocket把话题转发到网页。rosbridge能把ROS2话题转成WebSocket前端用roslibjs订阅就能在浏览器里看地图和机器人位置。数据记录方面ros2 bag record能录所有话题后面回放分析。我建议建图和导航时都录bag出问题了能复现。8. 一张攒机路线图从零到能跑的完整清单最后给一张实操路线图按顺序做每步都有验收标准。第一阶段底盘能动1-2周采购STM32开发板、直流减速电机带编码器、电机驱动、电池、轮子、万向轮、底盘板完成STM32能通过PID控制电机转速编码器能读数验收给固定PWM轮子转速稳定给目标转速PID能闭环第二阶段里程计输出3-5天完成STM32解算里程计通过串口按协议发送验收上位机串口助手能收到正确格式的里程计数据手动转轮子数据变化正确第三阶段ROS2接入1周采购树莓派或迷你主机、激光雷达完成ROS2环境搭好底盘驱动节点跑通雷达驱动跑通验收RViz2里能看到/odom和/scanTF树完整第四阶段SLAM建图3-5天完成slam_toolbox配置好能建图验收遥控机器人走一圈地图完整墙壁直无重影第五阶段Nav2导航1-2周完成Nav2配置好能点到点导航验收给目标点机器人能规划路径、避障、到达第六阶段优化持续覆盖路径规划、多传感器融合、回充、远程监控这张路线图的关键是每阶段都有验收标准别急着往下走。我见过太多人底盘还没调稳就去搞SLAM结果建图一塌糊涂回头返工更费时间。提示每个阶段都录bag出问题了回放分析。这是排查问题最有效的手段比盯着屏幕猜强一百倍。整个项目做下来我最大的体会是扫地机器人是一个典型的木桶系统底盘、里程计、雷达、SLAM、导航任何一环短板都会让整体体验崩掉。但反过来说每修好一个环节你都能明显感觉到机器人变聪明了一点。这种即时反馈是纯软件项目给不了的。如果你也想攒一台别想太多先从让轮子转起来开始。