
1. 从“会扫”到“好用”自研扫地机器人的核心挑战与破局思路很多人以为扫地机器人就是“轮子加吸尘器加一块电池”买几个现成模块拼起来就能跑。我一开始也这么想直到自己从零搭了一台基于ROS2的扫地机器人才发现“会扫”和“好用”之间隔着一整套系统工程。会扫指的是机器能通电、能转、能吸尘好用指的是它能在你家客厅里不撞墙、不卡死、不漏扫、不重复扫还能在你上班时自己规划路线把全屋走一遍。这中间的差距就是SLAM建图、Nav2导航、传感器融合、行为决策、异常恢复这一整套软件栈的差距。我做的这台机器硬件上用的是常见的差速轮底盘、2D激光雷达、IMU、编码器和吸尘模组软件上跑的是Ubuntu 22.04加ROS2 Humble建图和定位用SLAM Toolbox导航用Nav2最后通过Home Assistant做统一接入和远程控制。整个项目从立项到“好用”状态前后迭代了四个大版本踩过的坑比扫过的地还多。这篇文章就把我从“会扫”到“好用”的完整路径拆开讲清楚包括方案选型、核心参数、实操步骤、问题排查以及那些只有真正跑过才知道的细节。如果你正在做类似的自研项目或者想从零学习SLAM和Nav2在真实机器人上的落地这篇内容应该能帮你省下不少试错时间。我不会只讲概念而是把每个环节的“为什么”和“怎么做”都摊开说让你能直接抄作业。2. 整体方案设计与核心思路拆解2.1 为什么选ROS2而不是ROS1这个项目启动的时候ROS1 Noetic还在维护期内但我还是选了ROS2 Humble。原因有三个第一ROS2的实时性和多机通信能力更适合机器人产品化DDS中间件让话题、服务、动作的通信更稳定不会像ROS1那样依赖中心化的roscore第二Nav2是ROS2原生的导航栈功能比ROS1的move_base更完整行为树架构让导航逻辑更容易扩展第三Home Assistant对ROS2的支持越来越成熟通过MQTT桥接可以很方便地把机器人状态接入智能家居系统。当然ROS2的学习曲线确实比ROS1陡一些尤其是DDS配置和生命周期节点这些概念。但如果你要做的是“好用”的机器人而不是实验室里跑一次的demoROS2是更值得投入的选择。我实测下来ROS2 Humble在树莓派4B和Jetson Orin Nano上都能稳定运行内存占用比ROS1略高但换来的通信可靠性和多机协同能力完全值得。2.2 传感器选型2D雷达还是3D雷达热词里有人提到“nav2导航使用3d雷达”我一开始也考虑过3D雷达方案。但实际用下来对于扫地机器人这种低矮、室内、结构化环境2D单线激光雷达的性价比和稳定性明显更高。3D雷达的优势在于能感知高度信息比如识别桌腿和悬空障碍物但代价是数据量大、算力要求高、成本翻倍。我最终用的是2D雷达加一个朝前的红外防撞和悬崖传感器配合IMU做姿态估计整体成本控制在可接受范围内。如果你确实需要3D感知比如家里有低矮沙发或者复杂地形可以考虑在2D雷达基础上加一个深度相机做视觉SLAM辅助。但要注意视觉SLAM对光照变化很敏感晚上关灯后基本失效所以不能完全替代激光雷达。我的建议是2D雷达做主力建图和定位深度相机做障碍物识别补充两者通过ROS2的topic做数据融合。2.3 建图方案SLAM Toolbox的实战配置SLAM Toolbox是ROS2生态里最成熟的2D建图方案之一支持在线建图和离线建图两种模式。我用的在线异步建图模式机器人一边走一边更新地图适合第一次全屋探索。配置上主要调这几个参数resolution设成0.05米max_laser_range设成雷达实际量程minimum_travel_distance和minimum_travel_heading控制地图更新频率。实测下来minimum_travel_distance设成0.3米比较合适太小会导致地图频繁更新占用CPU太大则地图细节丢失。建图过程中有个关键技巧尽量让机器人匀速走完全屋避免急转弯和原地打转。因为SLAM依赖里程计和激光匹配急转弯时里程计误差会累积导致地图出现重影或错位。我第一版地图就是因为机器人转弯太猛客厅和走廊的墙壁出现了明显的双层结构后来重新建图才解决。2.4 导航方案Nav2的行为树架构Nav2的核心是行为树它把导航任务拆成一系列可配置的节点比如计算路径、跟随路径、恢复行为等。默认的navigate_to_pose行为树已经覆盖了大部分场景但如果你要做全覆盖清扫就需要自定义行为树或者用nav2_coverage这类插件。我一开始用的是默认行为树发现机器人在遇到障碍物时只会原地旋转不会绕行后来在行为树里加了Spin和BackUp恢复节点情况好了很多。Nav2的另一个重点是代价地图配置。全局代价地图用静态地图加膨胀层局部代价地图用激光雷达实时数据加障碍物层。膨胀半径设成机器人半径加安全余量我设的是0.25米实测能避免大部分轻微碰撞。如果家里家具腿比较细可以适当减小膨胀半径但要注意留出足够的避障空间。3. 核心细节解析与实操要点3.1 ROS2环境搭建与版本选择Ubuntu 22.04加ROS2 Humble是目前最稳的组合。安装步骤网上教程很多但有几个细节容易踩坑第一rosdep初始化时如果网络环境不好可以换用国内镜像源但要注意镜像源的同步延迟第二colcon build编译时如果内存不足可以加--parallel-workers 2限制并行编译数第三环境变量source要写进.bashrc否则每次新开终端都要手动source。我实测下来ROS2 Humble在Jetson Orin Nano上编译Nav2需要大约15分钟在树莓派4B上需要40分钟以上。如果你用树莓派建议直接装二进制包不要从源码编译。另外ROS2的版本要和Ubuntu版本严格对应Humble对应22.04Iron对应23.04不要混用。3.2 SLAM建图实操从启动到保存地图建图流程分三步启动雷达和底盘驱动、启动SLAM Toolbox、遥控机器人走完全屋。启动文件里要配置好base_link到laser的TF变换这个变换的精度直接影响建图质量。我一开始用卷尺量了雷达安装位置后来发现还是用tf2_ros的静态变换发布器更准因为卷尺测量有毫米级误差累积到地图上就是厘米级偏移。建图时用teleop_twist_keyboard遥控速度不要超过0.2米每秒角速度不要超过0.5弧度每秒。走完后用map_saver保存地图生成.pgm和.yaml两个文件。.yaml里的origin参数是地图原点在全局坐标系中的位置如果建图时机器人起点不是原点这个参数需要手动调整。注意建图过程中不要移动雷达或底盘上的任何传感器否则TF变换会失效地图直接废掉。3.3 Nav2导航配置参数调优与行为树定制Nav2的配置文件主要分三块nav2_params.yaml、行为树XML和启动文件。nav2_params.yaml里最关键的是代价地图参数和控制器参数。控制器我用的是RegulatedPurePursuitController它比默认的DWB更平滑适合扫地机器人的低速场景。desired_linear_vel设成0.15米每秒lookahead_dist设成0.3米实测下来转弯时不会过度摆动。行为树方面默认的navigate_to_pose_w_replanning_and_recovery.xml已经够用但如果你要做全覆盖清扫需要加一个ComputeCoveragePath节点。这个节点不是Nav2自带的需要自己写或者用第三方包。我用的方案是先用nav2_coverage生成覆盖路径再用FollowPath动作执行效果比随机碰撞式清扫好很多。3.4 八叉树地图与3D导航的取舍热词里提到“八叉树地图导航”这其实是3D建图的方案。八叉树地图OctoMap能把3D空间划分成体素适合无人机或者机械臂避障。但对于扫地机器人2D栅格地图已经足够因为机器人本身就在地面上跑不需要感知高度信息。我试过用OctoMap做3D建图结果发现数据量太大树莓派跑不动最后还是回到2D方案。如果你确实需要3D感知比如家里有台阶或者悬空障碍物可以用深度相机加OctoMap做局部避障但全局导航还是用2D代价地图。这样既能感知高度又不会拖垮算力。3.5 Home Assistant接入MQTT桥接与状态同步Home Assistant接入ROS2机器人最稳的方式是通过MQTT桥接。ROS2这边用mqtt_client包把机器人状态发布到MQTT brokerHome Assistant那边用MQTT集成订阅这些话题。我发布的状态包括电池电量、当前地图、机器人位置、清扫模式、错误码。Home Assistant里可以做一个卡片实时显示机器人位置和清扫进度。有个细节要注意MQTT的QoS等级设成1保证消息至少送达一次。如果设成0机器人状态可能会丢设成2开销又太大。另外ROS2和Home Assistant的坐标系要统一我用的都是map坐标系这样位置显示不会错位。4. 实操过程与核心环节实现4.1 底盘驱动与里程计标定底盘驱动是整台机器人的基础。我用的是两个带编码器的直流减速电机通过ros2_control做速度控制。里程计标定分两步先标定轮距再标定轮径。轮距标定方法是让机器人原地旋转360度看IMU的偏航角变化如果实际旋转角度和IMU读数不一致就调整轮距参数。轮径标定方法是让机器人直线走1米看编码器读数如果偏差超过2%就调整轮径参数。我第一版里程计误差很大走1米实际只走了0.85米后来发现是轮径参数设错了。标定后误差控制在1%以内SLAM建图质量明显提升。4.2 激光雷达数据过滤与TF配置激光雷达原始数据里有很多噪声比如玻璃反射、地面反光、动态障碍物。我用laser_filters包做了三层过滤第一层是距离过滤去掉太近和太远的点第二层是角度过滤去掉机器人自身结构遮挡的角度第三层是动态过滤用ScanShadowsFilter去掉移动物体产生的噪点。过滤后数据量减少约30%SLAM匹配速度提升明显。TF配置方面base_link到laser的变换要精确到毫米级。我用的是static_transform_publisher参数里x y z yaw pitch roll要反复测量确认。如果雷达安装有倾斜pitch和roll也要设对否则建图时地面会变成斜面。4.3 SLAM建图完整流程与参数记录建图那天我记录了完整流程先启动ros2 launch slam_toolbox online_async_launch.py然后启动雷达和底盘用ros2 run teleop_twist_keyboard teleop_twist_keyboard遥控。速度控制在0.15米每秒每走2米停一下让SLAM完成一次优化。全屋80平米走了大约25分钟地图保存后检查了一遍墙壁直线度很好没有明显重影。关键参数记录resolution: 0.05、max_laser_range: 12.0、minimum_travel_distance: 0.3、minimum_travel_heading: 0.3、map_update_interval: 2.0。这些参数在80平米户型里实测稳定更大的户型可以适当调大minimum_travel_distance。4.4 Nav2导航启动与路径规划实测导航启动文件里要加载地图、启动AMCL定位、启动Nav2导航栈。AMCL的参数里laser_model_type设成likelihood_fieldmax_beams设成60min_particles设成500max_particles设成2000。实测下来AMCL在激光雷达数据稳定时定位精度在5厘米以内。路径规划我用的是SmacPlannerHybrid它比默认的NavFn更平滑适合差速轮底盘。规划出的路径曲率连续机器人跟踪时不会频繁启停。实测从客厅到卧室的路径规划时间约50毫秒完全满足实时性要求。4.5 全覆盖清扫路径生成与执行全覆盖清扫是扫地机器人的核心功能。我用的方案是nav2_coverage加自定义行为树。nav2_coverage用boustrophedon算法生成弓字形路径然后通过FollowPath动作执行。路径间距设成机器人宽度的80%保证不漏扫。实测80平米户型清扫时间约35分钟覆盖率95%以上。有个细节要注意清扫过程中如果遇到动态障碍物比如人走动Nav2会重新规划路径但nav2_coverage生成的路径不会自动更新。我的做法是在行为树里加一个ClearEntireCostmap节点遇到障碍物时先清代价地图再重新规划。5. 常见问题与排查技巧实录5.1 SLAM建图常见问题速查表问题现象可能原因排查方法解决方案地图重影里程计误差大检查轮径和轮距参数重新标定里程计地图错位TF变换不准检查base_link到laser的变换重新测量安装位置地图缺失雷达数据被过滤检查laser_filters配置调整过滤参数建图卡顿CPU占用过高检查minimum_travel_distance调大更新距离5.2 Nav2导航常见问题与解决导航中最常见的问题是机器人原地打转或者卡在角落。原地打转通常是代价地图膨胀半径太大导致机器人认为周围都是障碍物。解决方法是减小膨胀半径或者调整inflation_radius和cost_scaling_factor。卡在角落通常是恢复行为不够可以在行为树里加BackUp和Spin节点让机器人先退出来再重新规划。另一个常见问题是定位丢失机器人突然不知道自己在哪。这通常是AMCL粒子数不够或者激光雷达数据匹配失败。解决方法是增大max_particles或者检查雷达是否被遮挡。我实测下来AMCL在激光雷达被遮挡超过30%时就会定位丢失所以雷达安装位置要尽量高视野要开阔。5.3 ROS2通信与DDS配置避坑ROS2的DDS配置是个大坑。默认的FastDDS在树莓派上跑久了会内存泄漏后来换成CycloneDDS就稳定了。配置方法是在~/.bashrc里加export RMW_IMPLEMENTATIONrmw_cyclonedds_cpp。另外多机通信时要注意ROS_DOMAIN_ID要一致否则话题发现不了。还有个细节ROS2的话题、服务、动作在跨机器通信时如果网络环境复杂可能会丢包。我的做法是用ros2 topic hz检查频率如果频率不稳定就改用ros2 topic echo看数据内容确认是网络问题还是节点问题。5.4 Home Assistant接入常见故障Home Assistant接入ROS2机器人时最常见的问题是MQTT连接断开。排查方法是先检查MQTT broker是否正常运行再检查ROS2这边的mqtt_client是否发布成功。我遇到过MQTT broker重启后ROS2节点没有自动重连后来在mqtt_client配置里加了reconnect_interval参数才解决。另一个问题是状态更新延迟。Home Assistant的MQTT集成默认是异步更新如果机器人状态变化频繁可能会丢消息。解决方法是把QoS设成1并且在Home Assistant里用automation做状态缓存避免频繁刷新UI。5.5 独家避坑经验分享第一个坑雷达安装高度。我一开始把雷达装在离地10厘米的位置结果建图时扫到了地毯边缘地图上出现一圈噪点。后来把雷达升到15厘米噪点消失。第二个坑底盘轮子打滑。地毯上轮子打滑会导致里程计误差暴增SLAM直接崩。后来换了带花纹的橡胶轮情况好转。第三个坑电池电压下降导致电机转速变化。锂电池从满电到没电电压从12.6伏降到10伏电机转速会下降约15%里程计如果不做电压补偿建图误差会累积。我的做法是在ros2_control里加电压反馈动态调整速度指令。6. 从“会扫”到“好用”的最后一公里6.1 异常恢复与自诊断机制“好用”的机器人必须能自己处理异常。我加了三个自诊断机制第一雷达数据超时检测如果超过1秒没有新数据就触发急停并报警第二里程计异常检测如果编码器读数突变超过阈值就判定为打滑并重新定位第三电池低压保护电压低于10.5伏时自动回充。这些机制通过ROS2的生命周期节点管理启动时按顺序初始化异常时按优先级处理。6.2 清扫策略优化从随机到规划第一版清扫用的是随机碰撞式效率极低80平米要扫1个多小时。第二版改成弓字形规划时间降到35分钟。第三版加了分区清扫把全屋分成客厅、卧室、厨房三个区域每个区域单独规划路径避免重复扫。第四版加了动态避障遇到人走动时暂停清扫等人走了再继续。实测下来第四版的清扫效率比第一版提升了3倍。6.3 远程控制与自动化联动通过Home Assistant我做了几个自动化场景第一离家模式机器人自动开始清扫第二回家模式机器人自动回充第三夜间模式机器人只扫客厅不扫卧室避免噪音。这些场景通过MQTT消息触发ROS2这边用mqtt_client订阅对应话题收到消息后调用Nav2的NavigateToPose动作。6.4 后续扩展方向这台机器目前已经能稳定完成全屋清扫但还有几个方向可以继续优化第一加视觉识别区分地面垃圾类型调整吸力第二加语音控制通过Home Assistant的语音助手直接下指令第三加多机协同两台机器人分工清扫不同区域。这些扩展都需要在现有ROS2架构上做增量开发不会推翻重来。我个人在实际操作中的体会是自研扫地机器人最难的不是某个单点技术而是把SLAM、Nav2、传感器、行为决策、异常恢复这些模块整合成一个稳定系统。每个模块单独跑都没问题但一起跑就会互相干扰。解决方法是模块化设计加充分测试每个模块先单独验证再逐步集成。最后再分享一个小技巧建图时用手机录屏记录机器人走位后期对照地图排查问题比看日志直观得多。