简介:本资源是一套基于ROS2开发的导航扫地机器人完整工程实现,面向高校人工智能、机器人工程方向的本科生与研究生,适用于毕业设计、课程设计及ROS2实践项目。资源聚焦机器人自主导航与清扫功能集成,覆盖感知、定位、建图、路径规划及硬件控制等核心环节,依托ROS2导航堆栈与模块化节点设计,提供可部署、可调试的端到端解决方案。压缩包共68个文件(117KB),包含29个Python节点脚本(如传感器接口、导航逻辑、清扫控制)、10个YAML配置文件(参数调优与启动配置)、4个XACRO宏定义与1个URDF模型(机器人结构描述)、3个PGM地图及RVIZ可视化配置等,目录结构清晰划分仿真(vacuum_robot_sim)与实机(vacuum_robot_real)两大分支,并含测试协议(test_protocol.py)与系统架构图(gv)。已有89人学习下载,配套PDF文档说明坐标系与帧结构,为初学者提供从环境搭建到功能验证的完整技术路径。
1. 项目缘起:从“玩具”到“工具”的扫地机器人进阶之路
几年前,我买过一个几百块的扫地机器人,它每天的工作就是随机乱撞,卡在椅子腿里是家常便饭,清扫路径毫无逻辑可言,更像一个会移动的“玩具”。后来,市面上出现了搭载激光雷达和视觉导航的“智能”机型,路径规划确实好了不少,但用久了你会发现,它的“智能”是封闭的、僵化的。你无法让它去清扫一个特定的、临时的脏污区域,也无法让它学习你家的特殊布局(比如某个角落总是需要绕个大圈),更别提为它增加新的传感器或功能了。这种“黑盒”体验,对于一个喜欢折腾的技术从业者来说,总感觉少了点什么。
于是,一个想法冒了出来:为什么不自己动手,打造一个完全开源、可深度定制、能随着技术迭代不断进化的扫地机器人呢?这个想法并非凭空而来,而是源于机器人操作系统(ROS)生态的成熟,特别是其第二代版本ROS2。ROS2解决了ROS1在实时性、跨平台和分布式通信上的诸多痛点,使得它成为构建可靠、复杂机器人系统的理想选择。而“导航”作为移动机器人的核心能力,正是ROS2社区中最为活跃和成熟的领域之一,Nav2导航框架的出现,让实现一套媲美甚至超越商用产品的导航系统,变成了一个“集成”而非“从零发明”的过程。
因此,这个“基于ROS2的导航扫地机器人”项目,本质上是一次将前沿开源机器人框架与具体家庭服务场景深度融合的实践。它不仅仅是为了造一个能扫地的机器,更是为了搭建一个可编程、可扩展、完全透明的机器人开发与验证平台。通过它,你可以深入理解现代机器人导航的每一个环节:从传感器数据融合、地图构建、定位、到全局与局部路径规划、行为树控制逻辑。最终,你得到的不仅是一个清洁工具,更是一套能够复用于其他移动机器人项目(如安防巡检、物流搬运)的软硬件方案与宝贵经验。
2. 核心架构设计:软硬件协同的蓝图
在动手写第一行代码或拧第一颗螺丝之前,清晰的架构设计是避免后期推倒重来的关键。一个完整的ROS2导航扫地机器人,可以自上而下分为硬件层、驱动层、核心功能层和应用层。
2.1 硬件选型与考量:在性能与成本间寻找平衡点
硬件是系统的骨骼与感官。对于扫地机器人,我们需要考虑移动底盘、感知系统、计算单元和清洁模块。
移动底盘:这是机器人的身体。我选择了常见的两轮差速驱动模型,因为它结构简单、控制成熟、成本低廉。两个带编码器的直流减速电机分别驱动左右轮,配合一个万向轮保持平衡。电机的选型需要计算:机器人的预估重量(含电池、结构件、主控等,假设为5kg)、轮子半径(例如0.065m)、最大期望速度(家庭环境0.5m/s足够)和爬坡能力(克服地毯和门槛,约15°)。通过计算扭矩和转速,可以选定合适的电机和减速比。编码器分辨率越高,里程计数据越精确,对后续的定位至关重要。
感知系统:这是机器人的眼睛。核心导航传感器我推荐2D激光雷达(Lidar),如思岚科技的RPLIDAR A1或A2系列。它提供360°的二维距离点云,是构建2D占据栅格地图和进行定位、避障的黄金标准。虽然单线激光无法探测低矮障碍(如电源线)或悬空物体(如椅子下方的横梁),但其稳定性和精度远超超声波和红外。为了弥补这一缺陷,可以增加一组红外或超声波接近传感器安装在机器人前部和侧裙,用于检测激光“看不见”的障碍,实现更全面的碰撞预防。对于有更高追求的项目,可以考虑加入惯性测量单元(IMU),融合角速度和加速度数据,能在机器人打滑或剧烈颠簸时,为定位系统提供重要的运动约束,减少里程计的累积误差。
计算单元:这是机器人的大脑。ROS2对算力有一定要求。树莓派4B 4GB/8GB版本是一个经典的起点,其性能足以流畅运行ROS2 Humble、Nav2以及SLAM算法。若追求更强性能或希望集成AI视觉识别(如识别宠物粪便、袜子等特定障碍物),NVIDIA Jetson Nano或Orin Nano系列是更强大的选择。它们提供了GPU加速能力,为未来扩展视觉SLAM(如RTAB-Map)或目标检测功能留出了空间。
清洁模块与电源:作为扫地机器人,清扫机构必不可少。一个带滚刷和吸尘电机的中置清扫模块是标准配置。电源方面,需要一块大容量锂电池(如12V 6000mAh以上)为整个系统供电,并通过合适的降压模块(如DC-DC降压模块)为计算单元(5V)、雷达(5V)、电机驱动(12V)等提供稳定电压。一个可靠的电池管理电路(BMS)和电量监测ADC电路是安全运行的基础。
注意:硬件连接时,务必注意电平匹配和电源隔离。例如,激光雷达通常是5V TTL串口,而树莓派的GPIO是3.3V电平,直接连接可能损坏硬件,需要使用电平转换模块。电机驱动产生的电流噪声可能干扰主控和传感器,良好的电源滤波和物理布局隔离非常重要。
2.2 软件栈规划:ROS2生态的模块化拼图
软件上,我们完全拥抱ROS2的模块化思想。整个系统将基于Ubuntu 22.04 LTS和ROS2 Humble版本构建,这是目前长期支持且稳定的组合。
- 操作系统与中间件:Ubuntu 22.04 + ROS2 Humble。ROS2采用DDS作为底层通信中间件,实现了真正的分布式、实时可靠的节点间通信。
- 驱动层:我们需要为每个硬件编写或配置对应的ROS2驱动节点(Node)。
rplidar_ros:用于驱动思岚激光雷达,发布/scan(激光扫描)话题。robot_base_controller:这是一个需要自己实现的关键节点。它订阅/cmd_vel(速度命令)话题,将线速度和角速度转换为左右电机的PWM信号;同时,它读取电机编码器数据,通过运动学模型计算并发布/odom(里程计)话题和tf(坐标变换)信息。imu_driver:如果使用了IMU,需要对应的驱动节点发布/imu话题。battery_monitor:一个简单的节点,读取ADC电压值,计算电量百分比,发布到/battery_state话题。
- 导航与感知层:这是项目的核心,主要依赖Nav2套件。
- SLAM:使用
nav2_bringup包中的slam_toolbox。这是一个优秀的2D SLAM库,能实时利用激光和里程计数据构建/map(地图)话题,并同时提供机器人在该地图中的初始定位。 - 导航(Nav2):这是一个完整的导航行为框架。它包含:
- 控制器(Controller Server):接收规划好的路径,生成具体的
/cmd_vel速度指令发给底盘。常用的是dwb_controller(动态窗口法),它能在遵循路径的同时进行动态避障。 - 规划器(Planner Server):负责全局路径规划,如从A点到B点。
nav2_navfn_planner或更先进的nav2_smac_planner都是可选方案。 - 行为服务器(Behavior Server):管理导航过程中的行为,如旋转恢复(卡住时原地旋转)、等待(遇到动态障碍物)等。
- BT导航器(BT Navigator):使用行为树(Behavior Tree)来编排上述所有服务器的调用逻辑,处理复杂的导航任务和故障恢复,这是Nav2相比传统导航栈最强大的设计之一。
- 控制器(Controller Server):接收规划好的路径,生成具体的
- SLAM:使用
- 应用层:这是我们自定义业务逻辑的地方。
cleaning_coverage_planner:一个自定义节点,实现高效的覆盖路径规划(如弓字形清扫),并将目标点序列发送给Nav2。mission_manager:任务管理器,处理如“全屋清扫”、“区域清扫”、“定点清扫”等高级指令,并协调导航与清扫机构的启停。
整个软件架构通过ROS2的话题(Topic)、服务(Service)和动作(Action)松散耦合,每个节点可以独立开发、测试和部署,这正是ROS2设计的精髓所在。
3. 从零搭建:环境配置与基础功能实现
有了蓝图,我们就可以开始动手搭建了。这个过程就像拼装一个精密的乐高模型,每一步都需要耐心和细致。
3.1 ROS2 Humble与Nav2的安装与验证
在Ubuntu 22.04上安装ROS2 Humble,官方提供了清晰的教程。但我强烈推荐使用国内开发者维护的“一键安装”脚本或镜像源,可以极大解决网络下载慢的问题。安装完成后,务必在新终端中source /opt/ros/humble/setup.bash或将其加入~/.bashrc。
接下来安装Nav2。Nav2及其依赖可以通过apt安装二进制包,这是最快捷的方式:
sudo apt update sudo apt install ros-humble-navigation2 ros-humble-nav2-bringup ros-humble-slam-toolbox安装后,我们可以先在不依赖真实硬件的情况下进行仿真测试。Gazebo是一个强大的物理仿真器,但配置稍复杂。一个更轻量级的快速验证方法是使用Nav2自带的“TurtleBot3”仿真示例。虽然我们不是TurtleBot3,但可以借鉴其启动文件来理解Nav2的配置结构。通过运行演示,你能在Rviz2中看到一个虚拟机器人在地图中导航,这能帮你快速建立对Nav2工作流程的直观认识。
3.2 机器人URDF模型与TF树构建
在ROS中,tf2库管理着所有坐标系(Frame)之间的变换关系。对于导航来说,一个正确无误的TF树是生命线。我们需要定义几个核心坐标系:
odom:里程计坐标系。这是一个非固定的坐标系,随着机器人移动而漂移,但短期内是准确的。由robot_base_controller节点根据编码器数据实时发布odom到base_link的变换。base_link:机器人本体坐标系,通常位于机器人中心。base_scan:激光雷达的坐标系。我们需要知道雷达相对于base_link的位置(X, Y, Z偏移)和朝向。
这些关系通过一个URDF文件来定义。URDF是一种XML格式的机器人描述文件。你需要在这里描述机器人的物理尺寸、视觉外观、碰撞模型,以及最重要的——关节(Joint)和连杆(Link),其中就包含了上述坐标系的固定变换(如base_link到base_scan是fixed关节)。
一个常见的错误是TF树断裂或时间不同步。务必确保:
- 所有坐标系通过父子关系连接成树。
- 每个变换都有节点持续发布(频率通常为10-50Hz)。
- 时间戳要一致。使用
ros2 run tf2_ros tf2_echo命令可以查看任意两个坐标系间的实时变换,这是调试TF问题最常用的工具。
3.3 底盘控制节点:连接ROS与硬件的桥梁
robot_base_controller节点是这个桥梁。它的实现逻辑如下:
- 订阅:它订阅
/cmd_vel话题,消息类型是geometry_msgs/msg/Twist,包含线速度linear.x(前进/后退)和角速度angular.z(旋转)。 - 转换:根据两轮差速运动学模型,将
(v, ω)转换为左右轮的目标转速ω_left, ω_right。公式为:ω_left = (v - ω * L/2) / Rω_right = (v + ω * L/2) / R其中,L是两轮间距,R是轮子半径。 - 控制:使用PID控制器。将目标转速与从编码器读取的实际转速比较,通过PID运算输出PWM占空比,控制电机驱动板(如TB6612FNG或L298N)。
- 发布里程计:同时,它持续读取编码器脉冲数,计算每个轮子走过的距离,反向推算机器人的位移和转角,从而更新
odom坐标系的位置和姿态,并发布/odom话题和odom->base_link的TF变换。
这里有一个关键细节:编码器读数与真实位移的校准。你需要通过实测来校准“每米脉冲数(ticks_per_meter)”这个参数。让机器人直线行走一段精确距离(如2米),记录编码器总脉冲数,然后进行计算和反复微调。不准确的里程计是导致定位漂移和SLAM建图失败的主要原因之一。
4. 导航核心:SLAM建图与Nav2实战配置
当机器人能够可靠地接收速度指令并反馈里程计后,我们就可以赋予它“感知环境”和“自主行动”的能力了。
4.1 使用Slam_toolbox构建高清2D地图
建图是导航的前提。我们使用slam_toolbox的异步模式。你需要编写一个启动文件(launch file),主要配置包括:
- 指定激光雷达的话题名(通常是
/scan)。 - 设置地图的分辨率(如0.05米/像素),分辨率越高地图越精细,但计算量和内存占用也越大。
- 配置里程计话题和TF坐标系。
操作流程如下:
- 启动底盘驱动、激光雷达驱动节点。
- 启动
slam_toolbox建图节点。 - 打开Rviz2,添加
LaserScan显示(订阅/scan)和Map显示(订阅/map)。 - 手动遥控机器人(可以使用
teleop_twist_keyboard节点)走遍所有需要清扫的区域,确保环境被激光充分扫描。要慢速、平稳地移动,特别是在转角处,让激光有足够时间匹配特征。 - 当地图完整后,使用
slam_toolbox提供的服务(service)保存地图。地图会保存为.pgm(图像)和.yaml(元数据)两个文件。
实操心得:建图时,室内的光线变化、阳光下反光的地板、全黑的家具都可能影响激光雷达的测距效果,导致地图出现鬼影或空洞。尽量在光线均匀的环境下建图。如果家具移动了,需要重新建图或使用
slam_toolbox的“终身定位与建图”模式进行在线更新。
4.2 Nav2导航栈的深度配置与参数调优
有了地图,就可以配置Nav2了。Nav2的配置主要是一系列YAML参数文件,这可能是整个项目中最需要耐心调试的部分。关键配置文件通常包括:
nav2_params.yaml:主参数文件,定义行为树XML路径、各服务器插件列表等。amcl_params.yaml:自适应蒙特卡洛定位参数。用于在地图中定位机器人。需要调整粒子数(max_particles,太少定位不准,太多计算慢)、激光模型参数等。bt_navigator_params.yaml:行为树导航器参数,指定行为树XML文件。controller_server_params.yaml:控制器参数,如DWB控制器的代价函数权重、速度限制、障碍物膨胀半径等。planner_server_params.yaml:规划器参数,如全局规划器的代价因子。
启动导航的典型流程:
- 启动所有硬件驱动节点。
- 启动地图服务器(
map_server)加载先前保存的地图。 - 启动
amcl定位节点。此时在Rviz2中,你需要手动给出一个初始位置估计(使用2D Pose Estimate工具点击地图对应位置并拖拽方向),AMCL的粒子云会逐渐收敛到正确位置。 - 启动Nav2的核心生命周期管理器(
lifecycle_manager),它会按顺序激活控制器、规划器、行为服务器等节点。
参数调优实战经验:
- 定位(AMCL):如果定位不稳、粒子云发散,可以尝试增加
min_particles和max_particles(例如500-3000),并调小laser_model中的z_hit(增加激光匹配的权重)。确保odom->base_link的TF和map->odom的TF正确发布。 - 全局规划:如果规划出的路径很奇怪,比如紧贴障碍物,检查全局代价地图的
inflation_layer(膨胀层)参数,增加inflation_radius可以让路径更远离障碍物。 - 局部规划与控制(DWB):这是调优的重点,直接影响机器人行走的平滑度和避障能力。
max_vel_x,min_vel_x,max_rot_vel等:设置机器人的物理速度极限。path_distance_bias,goal_distance_bias,occdist_scale:这是DWB评估轨迹的代价函数权重。增大path_distance_bias会让机器人更严格跟随全局路径;增大goal_distance_bias会让它更倾向于朝向终点;增大occdist_scale会让它更远离障碍物。需要根据机器人机动性和环境复杂度反复调整平衡。prune_plan:设置为true,可以让控制器只关注前方一段路径,提高反应速度。
- 代价地图:
obstacle_layer(障碍层)的observation_sources要包含你的激光雷达话题。inflation_layer的cost_scaling_factor和inflation_radius共同决定了障碍物对路径规划影响的“衰减梯度”,需要配合控制器参数一起调。
调试时,务必充分利用Rviz2。可视化/global_costmap和/local_costmap,观察障碍物信息是否正确融入;可视化/received_global_plan和/local_plan,看规划路径是否合理;开启DWB的轨迹评分可视化,可以直观地看到机器人为何选择了某条轨迹。
5. 赋予灵魂:实现扫地机器人的专属行为
基础导航跑通后,我们的机器人还只是一个能移动的底盘。要成为扫地机器人,需要在上层添加任务逻辑。
5.1 覆盖路径规划:从A到B到“全部覆盖”
全局规划器解决的是“从A到B”的最优路径问题,而扫地需要的是“覆盖整个区域”的路径问题。这是一个典型的**覆盖路径规划(Coverage Path Planning, CPP)**问题。我们可以在Nav2之上,实现一个cleaning_coverage_planner节点。
一种简单有效的策略是“弓字形”(Boustrophedon)规划:
- 区域划分:首先,你需要定义清扫区域。可以在Rviz2上用
PublishPoint工具点击地图,形成一个多边形区域,或直接使用整个地图的可通行区域。 - 单元格分解:将区域沿着一个主轴(如X轴)分解成若干个与机器人清扫宽度相等的条带。
- 生成路径点:按照弓字形顺序,生成每个条带中心线的起点和终点坐标。
- 调用Nav2:将这一系列路径点依次作为目标点,通过Nav2的
NavigateToPose动作(Action)接口发送给机器人。当一个目标到达后,自动发送下一个。
这个节点需要处理边界情况,如遇到动态障碍物导致导航失败时,是重试、跳过还是记录未清扫区域后续补扫。这里就可以利用Nav2行为树的可扩展性,自定义一个“清扫覆盖”行为节点,集成到更大的行为树中。
5.2 任务管理与状态机:协调清扫与导航
一个完整的扫地机器人需要多种工作模式:全屋清扫、划区清扫、定点清扫、沿边清扫、回充等。这需要一个顶层的mission_manager节点来实现一个状态机。
例如,一个简化的状态机可能包括:
IDLE:待机状态。MAPPING:建图模式。CLEANING:清扫模式。在此状态下,启动cleaning_coverage_planner和清扫电机。CHARGING:返回充电座并充电。这需要机器人具备自动回充能力(通常通过红外信标或视觉标记引导)。PAUSED:暂停状态。ERROR:错误处理状态。
mission_manager监听用户指令(可以通过手机APP、Web界面或物理按钮发送ROS服务调用),管理状态切换,并在不同状态下协调底层节点。例如,在CLEANING状态下,它要启动覆盖规划器、打开吸尘电机,并监控电池电量。当电量低于阈值时,触发CHARGING状态,调用回充逻辑。
5.3 进阶功能探索:从2D到3D感知的跨越
当2D导航玩转之后,你可以考虑引入更强大的感知能力,让机器人更智能。
- 多传感器融合定位:融合激光
/scan、IMU/imu和视觉里程计,使用robot_localization包中的ekf_localization_node进行扩展卡尔曼滤波,可以得到比单纯里程计更稳定、更准确的odom数据,尤其在打滑和旋转时。 - 视觉避障与语义导航:在机器人上添加一个USB摄像头或RGB-D相机(如Intel Realsense D435i)。利用
YOLO、MobileNet-SSD等轻量级模型在Jetson上实时运行,识别出“鞋子”、“袜子”、“电线团”等特定障碍物,并将它们作为特殊类型的障碍物动态添加到代价地图中,甚至可以设置不同的膨胀半径(比如对电线要离得更远)。 - 3D SLAM与导航:使用
RTAB-Map这类RGB-D SLAM方案,可以构建带颜色的3D点云地图。虽然Nav2核心是2D导航,但你可以将3D点云投影到2D平面上生成代价地图,同时保留3D信息用于更丰富的场景理解。这对于复式楼层或者有高度变化的环境更有意义。
6. 系统集成、调试与长期维护的思考
将所有这些模块集成在一起稳定运行,是最后的挑战,也是乐趣所在。
你需要编写一个顶层的启动文件(Launch File),用ROS2 launch语言来组织所有节点的启动顺序、参数加载和命名空间。一个良好的实践是为不同模式(如mapping.launch.py,navigation.launch.py,full_system.launch.py)编写不同的启动文件。
系统调试是一个持续的过程。除了之前提到的Rviz2可视化,ros2 topic echo、ros2 service list、ros2 node info等命令行工具是诊断通信问题的利器。rqt_graph可以查看节点与话题的连接图,一目了然。对于性能分析,ros2 run system_monitor相关的工具可以查看CPU、内存占用。
长期维护方面,考虑以下问题:
- 日志:为关键节点配置好
ros2的日志级别,将日志持久化到文件,便于后期排查偶发问题。 - 参数管理:将所有调优好的参数文件进行版本控制(如Git),记录每次修改的原因和效果。
- 安全:确保急停开关硬件回路有效;在软件层面,设置
/cmd_vel的安全超时,如果导航节点异常停止发布指令,底盘控制器应能自动停止机器人。 - 续航与回充:精确的电量监测和可靠的自动回充逻辑是实用化的关键。这涉及到回充座的识别(视觉或红外)、最后的精对准策略等。
这个项目做到这里,你已经拥有了一个完全开源、深度可控的智能扫地机器人原型。更重要的是,你获得了一套经过实战检验的ROS2移动机器人开发框架。你可以轻易地将相同的导航栈和硬件接口,移植到一个安防巡检机器人、仓库搬运AGV,甚至是户外探索小车上。这种从具体应用抽象出通用平台的能力,正是开源机器人技术带给开发者最宝贵的财富。
本文还有配套的精品资源,点击获取