☰
ROS2巡检小车从零搭建指南:六步打通建图、导航与自动巡检
2026/10/15 1:47:59 网站建设 项目流程

做巡检小车这件事,圈子里的常态是这样的:硬件堆了一桌子,电机也会转,雷达也能出点云,可要让这辆车“自己知道自己在哪、该往哪走、遇到障碍该怎么办”,大部分人都会卡在中间那条看不见的链路上。这篇文章就是把一台基于 ROS2 的巡检小车从零连起来的过程拆成 6 步,每一步都有明确的验收标准,照着顺序走,能省下不少弯路。

先交代一下这台车的定位:两轮差速底盘,下位机用 STM32 系列单片机,上位机用树莓派或者 x86 迷你主机,装 Ubuntu 和 ROS2,配一枚单线激光雷达,外加一个可选的摄像头。最终实现的目标是:手动遥控建图,保存地图后切换自动巡检模式,小车沿预设路径巡逻,遇到障碍能自动停下或绕行,最后回到起点。这 6 步连完,你手里就不只是一台“会动的底盘”,而是一个具备感知、定位、规划能力的完整巡检系统。适合刚接触 ROS2 的机器人方向学生、想搞巡检或安防项目的工程师,以及纯粹想折腾的硬件爱好者。

1. 动手之前,先把架构和链路想明白

1.1 这 6 步到底是在连什么

很多人拿到套件的第一反应是“先让车跑起来”,这恰恰是效率最低的路径。巡检小车能不能稳定工作,靠的是下面这条链路:

  • 电机驱动板与编码器:负责执行动作、感知轮子转了多少圈。
  • 下位机(单片机):实时读取编码器、输出 PWM,同时通过串口和上位机通信。
  • 上位机(运行 ROS2 的主控板):接收雷达数据、跑定位与导航算法。
  • 传感器:激光雷达提供环境距离信息,里程计提供位移信息,两者一起喂给导航栈。
  • 应用层:巡检逻辑节点,负责“依次去几个点位”“电量低了回充”这类任务编排。

那 6 步就是沿着这条链路自下而上依次打通:第 1 步组装底盘和接线;第 2 步写底层控制程序并打通串口;第 3 步安装系统和 ROS2 框架;第 4 步用 URDF 描述这台车并接入底盘驱动;第 5 步接雷达完成建图;第 6 步配置导航并写巡检逻辑。

每步都不算难,但顺序不能乱。比如第 2 步还没验完就急着把雷达接上,出了问题你根本分不清是串口导致的还是雷达导致的。我特意把过程分成 6 步而不是一篇大杂烩,就是因为每步都有独立的验收标准,验收过了再进下一步,排错成本能低一大截。

1.2 硬件清单与选型逻辑

直接给清单,都是我实际跑通过、验证过能用的配置:

部件推荐配置说明
底盘两轮差速底盘,带编码器电机有没有编码器直接决定能不能做里程计,普通玩具底盘不建议用于巡检
电机驱动双 H 桥驱动模块,持续电流 3A 以上电流余量要留足,电机堵转时的电流比标称大很多
下位机STM32F103 系列开发板资料多、完全够跑编码器和 PWM
上位机树莓派 4B 或 x86 迷你主机建议 4GB 内存起步,跑 Nav2 才不卡
激光雷达单线激光雷达,测距半径 10 米以上室内巡检 10 米够用,室外大场地另算
摄像头(可选)USB 摄像头用于巡检图像留档、识别异常,不是导航必需
电源11.1V / 12V 锂电池组 + 降压模块电机和上位机分开供电,避免电机启动瞬间拉低主控电压

选型逻辑其实是一句话:先定功能边界,再定硬件。室内平地巡检,两轮差速加单线雷达就是性价比最高的组合,完全没必要上四轮阿克曼或者多线雷达。雷达的扫描频率和测距半径要与场地大小匹配,普通办公室和走廊 10 米足够;想跑大厂房,再考虑 20 米以上的型号。

有个经验供参考:底盘一定要买带编码器的,哪怕贵一两百块钱。没有编码器,后面做里程计、做定位全都要依赖雷达,单线雷达在长走廊里非常容易丢定位,到时候你排错会排到怀疑人生。这个坑我见过太多人踩了,所以放在清单里反复强调。

1.3 为什么用 ROS2,版本怎么选

ROS1 已经停止维护,新项目老老实实用 ROS2。ROS2 带来的变化对巡检车这种场景很关键:节点间通信基于 DDS,实时性比 ROS1 好,断线重连也更稳;多机协同和权限管理更完善,以后想加车或远程下发任务,不用推翻重来。

版本上我建议直接装 Humble,对应 Ubuntu 22.04。Humble 是 LTS 长期支持版本,维护周期长,教程和社区资料也最多。新手不要一上来追最新版,巡检车这种项目稳定压倒一切,教程多不多、坑有没有人写过,比版本新不新重要得多。

2. 第 1 步和第 2 步:底盘组装与底层控制

2.1 第 1 步:底盘组装与电机驱动接线

这步的目标很朴素:让两个轮子能独立正反转,同时编码器能输出脉冲信号。

先说接线。两轮差速底盘的电机一般各带一组电源线和一组编码器线。电源线接驱动模块的输出端,注意区分左右轮,后面软件里还要靠这个区分做差速。编码器线接单片机的外部中断引脚,两路编码器一共需要至少 4 个 IO 用于 A/B 相,如果编码器是正交输出的话。

供电顺序特别重要:先接电机电源,再接控制信号线,最后接单片机供电。原因很简单,电机启动瞬间电流冲击很大,如果单片机和驱动模块共用一个电源,电压跌落会导致单片机复位。我见过有人因为供电顺序不对,每次电机一转上位机就掉线,查了大半天才发现是电源问题。

接通之后先烧一个最简单的测试程序:定时输出 PWM,占空比从 0 慢慢加到 50%,观察两个轮子是否同时转起来、转向是否一致。这一步不要急,确认了“硬件没接错”,后面所有软件工作才有意义。

有一种情况很常见:两个轮子一个转一个不转,或者一个正转一个反转。这基本都是驱动模块的 IN 输入接线或者 PWM 引脚定义搞错了,检查一下左右轮的通道映射就能解决。还有,编码器线的颜色各家不一样,别凭印象,用万用表量一下哪根是电源哪根是信号,比自己猜要快得多。

2.2 第 2 步:下位机程序与串口通信

这一步的核心是写一个能在单片机上跑的控制程序,主要做三件事:

  1. 读取左右编码器脉冲,计算轮子转速和累计位移。
  2. 接收上位机发来的速度指令(线速度 + 角速度),转换成左右轮的目标速度。
  3. 输出 PWM 给驱动模块,并用 PID 把实际速度收敛到目标速度。

PID 参数可以先给一组保守值,比如电机速度环用 P=20、I=5、D=0,具体数值取决于电机和编码器分辨率。调 PID 的时候不要一上来追求“完美跟随”,先让速度跟得上指令、不震荡就行。等到后面真正跑导航了,你会发现速度环稳定比精准更重要。

串口通信是这一步的重头戏。上位机和单片机之间建议用固定格式的帧协议,比如:

0xAA 0x55 [指令类型] [数据长度] [数据...] [校验和]

为什么不用现成的 ROS 串口库直接读?因为单片机端资源有限,而且巡检车要保证通信不丢帧,一个简单的帧协议配合 CRC 校验,比裸读数据可靠得多。实测下来,115200 波特率下,20Hz 的控制频率完全没有压力。

下位机程序的逻辑流程一般是:初始化编码器和串口,进入主循环后读编码器、算速度、跑 PID、刷新 PWM,同时轮询串口数据,收到新指令就更新目标速度。这时候你可以在 PC 上用串口助手发一组十六进制指令验证,电机会跟着转,说明底层链路已经通了。

2.3 串口通信协议的细节约定

这一步容易踩的坑是:上位机下位机两端的字节序和数据类型约定不一致。比如上位机发了 float 类型的速度值,如果单片机和上位机的字节序不同,解析出来就是一堆乱数。

我的做法是:统一用 int16 表示速度,单位是 mm/s 和 0.01 rad/s,传输时拆分高字节低字节,这样两边都不需要浮点数转换,解析也快。实测在电机最大速度 1m/s 的情况下,int16 的量程完全够用。

另外建议加一个看门狗机制:下位机超过 500ms 没收到有效帧,就自动把目标速度清零,让小车停下来。这个在调试时尤其重要——万一上位机崩溃了,至少小车不会全速冲出去撞墙。这个细节在正规文档里不常见,但对安全来说非常关键。

3. 第 3 步和第 4 步:系统环境与机器人描述

3.1 第 3 步:安装 Ubuntu 与 ROS2 Humble

这步属于“搬砖活”,但搬不好后面全得返工。安装要点如下:

  • 上位机烧录 Ubuntu 22.04,建议用官方镜像,不要用第三方魔改版。
  • 安装 ROS2 Humble Desktop 版即可,Desktop 自带的 RViz2、demo 工具都齐全。
  • 装完后务必配置好~/.bashrc里的环境变量,source /opt/ros/humble/setup.bash是每次开终端都要做的,忘了会经常出现“找不到 ros2 命令”。

有一个我建议新手一定要花 10 分钟做的事:按下ros2 run demo_nodes_cpp talker和ros2 run demo_nodes_py listener,验证发布订阅通信是否正常。这个“hello world”如果通了,说明 DDS 配置没问题,后面所有节点通信都有底了。

DDS 默认使用多播通信,如果在小车和电脑直连的场景下发现节点发现不了,大概率是网卡选错了或防火墙拦了多播。解决办法是检查ROS_LOCALHOST_ONLY是否误设成了 1,以及确认ROS_DOMAIN_ID两边一致。这几个环境变量我会在后面的排错章节再展开。

3.2 第 4 步:URDF 模型与底盘驱动节点

上位机装好了,但 ROS2 还不认识这台车。这一步就是“告诉 ROS2 这台车长什么样”,用 URDF 文件描述车身的几何尺寸、轮子位置、雷达安装高度,同时把底盘驱动节点跑起来。

URDF 先不用写得很复杂,两轮差速底盘最小模型包含:一个车体 link、两个驱动轮 link、一个支撑轮或万向轮 link、一个雷达 link,再加若干 joint 把轮子和车体连起来。这里有个关键点:轮子的origin坐标要准确对应实际的左右间距和轮径,因为后面导航的转弯半径计算完全依赖这些参数。

底盘驱动节点建议直接用现成的diff_drive_controller,这是 ROS2 控制框架里最常用的差速驱动控制器。你只需要在上位机上写一个串口通信节点,订阅/cmd_vel(线速度和角速度指令),把速度转换成左右轮目标值,再通过串口发给下位机;同时把下位机回传的编码器数据转换成/odom里程计消息发布出去。

这一步验收标准是:在终端里发布cmd_vel话题,小车能前进、后退、原地转向;另外打开 RViz2,能看到一个跟随指令移动的小车模型。如果模型动了,说明从 URDF 到控制器再到硬件的链路已经全部打通。

3.3 坐标系的几个关键值别省事

说到坐标系,这是新手最容易忽略的。巡检车的 TF 树至少要包含:odom(里程计坐标系)、base_link(车体坐标系)、laser_frame(雷达坐标系)。这三个坐标系之间的关系必须写对,否则后面建图和导航会出现“地图上能看到墙,但车就是认为墙在另一侧”这种诡异问题。

雷达安装位置要量准。我建议用卷尺量出雷达中心相对车体中心的 x、y 偏移以及离地高度,填进 URDF。别用“目测大概差不多”,差上三五厘米在短距离建图时可能看不出来,等跑长走廊时就会明显积累误差。

4. 第 5 步和第 6 步:建图、导航与巡检联调

4.1 第 5 步:激光雷达接入与 SLAM 建图

巡检车能不能“认路”,靠的是先建一张地图。这一步要做的就是把单线激光雷达数据接进 ROS2,并跑起 SLAM 节点。

雷达驱动的安装要看具体型号。一般来说,雷达厂商都会提供官方的 ROS2 驱动包,按照说明安装后就能在/scan话题上看到 LaserScan 消息。接入后先在 RViz2 里打开,检查点云数据是否有明显畸变,比如墙是不是直的,柱子是不是圆的。如果发现数据扭曲,先检查雷达安装是否水平,再检查雷达内部转速是否稳定,这两个原因占了绝大多数。

SLAM 方案我建议用slam_toolbox,它比传统的 gmapping 更适合巡检这种“建一次图长期复用”的场景。它支持位姿图优化,建图过程中产生的漂移小,而且保存和重载地图都很方便。跑建图的核心命令就是用遥控器(或者键盘控制节点)操纵小车把整个场地扫一遍,重点覆盖墙角、门框、柱子这些特征明显的地方。

建图的操作有两个技巧。第一,速度放慢,直线段匀速走,转弯时最好停下来原地转,这样雷达数据比较干净;第二,扫描完一个区域后,让小车回到已经扫描过的地方“回看一下”,SLAM 的回环检测会把累积误差修正掉,这个动作比盲目多扫一圈有效得多。

4.2 第 6 步:Nav2 导航配置与自动巡检

地图建好了,接下来就是让小车在这张地图里自己走。

Nav2 是 ROS2 里最成熟的导航框架,核心是四个模块:定位(AMCL)、全局规划、局部规划、代价地图。配置 Nav2 看起来复杂,其实关键就几个参数:

  • 全局代价地图的膨胀半径:一般设置为车体宽度的 1/2,再加 5~10 厘米的安全余量。
  • 局部代价地图的传感器范围:设成雷达有效测距的 80% 左右。
  • 最大线速度和角速度:建议线速度 0.3~0.5 m/s,角速度 0.5~1.0 rad/s,室内巡检没必要贪快。
  • AMCL 初始位姿:每次启动导航前,用 RViz2 里的“2D Pose Estimate”手动给定初始位置和朝向,否则定位会迷失。

Nav2 跑通后,巡检逻辑就是“调用导航 API,依次到达多个目标点”。这一步的代码逻辑很贴近真实业务,大致是:

  1. 读取巡检任务清单(一组目标点的坐标和朝向)。
  2. 逐点发送导航目标并等待结果。
  3. 到达后执行动作,比如拍照、停留若干秒。
  4. 所有点位走完后,回到出发点。
  5. 如果中途导航失败,重试一次,仍失败则记录并跳到下一个点。

这一步验收标准是:给小车设置 3 个巡检点,它能在无人干预的情况下按顺序走完并回到起点。跑通以后,你基本就拥有了一台能做定点巡逻的巡检小车。

4.3 导航参数里的两个关键取舍

Nav2 调参时有两个地方容易纠结,我说下我的处理方式。

第一个是全局路径规划算法,默认的 NavFn 在室内平地上完全够用,不需要换更复杂的算法。第二个是局部规划器的 cost 参数,inflate系数设太大会导致小车离墙特别远、过门洞困难;设太小又容易蹭墙。先用默认值跑,然后在地图上挑一个窄通道反复试验,观察路径的偏移程度,再微调 5% 量级,别一次改一半。

另外,导航时/odom的话题频率建议保持在 20Hz 以上,如果频率太低,局部规划器会认为小车没有响应并不断调整指令,表现为“走路画龙”。这个症状很好认,我遇到过的绝大多数“小车走不直”的问题,本质都是里程计频率不够,不是控制参数的问题。

5. 六步全走完之前,你大概率会遇到的坑

5.1 常见问题速查表

这部分的每一条都是我实际踩过或者看别人踩过的问题。按症状、原因、解法整理成表,方便你直接对照:

症状可能原因排查与解法
电机不转,但驱动板指示灯亮PWM 引脚映射错误或使能引脚未置高检查驱动模块 ENA/ENB 引脚是否接到了高电平,确认代码里 GPIO 编号和实际接线一致
小车原地转圈或走不直左右轮编码器计数方向反了一个互换其中一侧编码器 A/B 相,或在下位机代码里取反
串口能发不能收单片机 RX 引脚被占用或电平不匹配检查是否把 USB-TTL 模块的 TX 错接到了单片机的 TX;确认共地
RViz2 里雷达点云乱转TF 树里雷达坐标系错误打印 TF 树检查laser_frame是否正确挂在base_link下,注意偏移值和方向
建图时墙是斜的雷达安装倾斜,或底盘左右轮速不匹配重新固定雷达,用水平尺校平;检查编码器分辨率是否一致
导航启动后定位崩溃AMCL 初始位姿设错在 RViz2 重设“2D Pose Estimate”,注意朝向也要对
小车在窄通道里犹豫不决代价地图膨胀半径过大把inflation_radius逐步调小,观察通过情况
导航时上位机 CPU 占用过高雷达频率过高或 Nav2 参数不合理降低雷达扫描频率到 10Hz,关闭不必要的 RViz2 显示插件

5.2 两个没人提醒但特别要命的细节

第一个是供电。巡检小车最容易被忽略的就是“电机和上位机共用一组电源”。电机启动瞬间的电流冲击会造成电压跌落,轻则造成上位机自动重启,重则导致 TF 树中断,定位瞬间失效。我的做法是:电机用 12V 直供,上位机通过独立的降压模块供电,两组电源共地但输出回路分开。多买一个降压模块的成本,远比排查一次诡异重启的时间成本低。

第二个是防掉线机制。ROS2 的 DDS 在节点异常退出后会有一个“僵尸节点”的问题,端口没释放,重启节点时提示地址被占用。遇到这种情况不要反复重启,先用ros2 daemon stop清理后台守护进程,再重新ros2 daemon start。这个知识点很偏门,但没有它你可能会在“为什么刚才还好好的,现在起不来了”这个问题上卡半天。

5.3 踩坑后的几条固定排查套路

我调试巡检车时有一套固定的排查顺序,分享出来:

  • 先看话题,再查代码:用ros2 topic echo /scan看雷达有没有数据,比直接怀疑驱动代码高效得多。
  • 先看 TF 树,再查坐标值:ros2 run tf2_tools tf2_echo base_link laser_frame可以快速确认坐标系是否有跳变。
  • 先看日志,再查硬件:ros2 launch输出的 ERROR 级别日志里,有时候已经把问题原因写得明明白白,先花 30 秒看日志,别急着拆螺丝。

这套顺序的核心思路是:信息流是逐层传递的,先确认上一层的输出没有问题,再检查下一层。顺着链路找,比跳来跳去瞎猜要快得多。

6. 车连起来之后,还能往哪个方向走

6 步走完,这台巡检车已经具备最基础的能力:建图、定位、按点巡逻、遇障避让。但这只是开始。基于这套已经打通的链路,后面可以扩展的方向其实很多。

比如加一个摄像头做图像识别,让小车在看板上检测到异常标记时自动停下来报警,这就是巡检业务里最常见的“仪表识别/安全巡检”场景。再比如把巡检点位的坐标和任务清单存成单独的任务文件,实现不同路线、不同频率的巡检计划,这就是一个简易版的调度系统。更进一步,如果你有两台或多台车,可以利用 ROS2 的多机通信特性,一台做调度,其余几台沿着各自路线巡逻,数据汇总到同一张地图上。

我个人在实际操作中体会最深的一点是:这 6 步里最花时间的从来不是安装和配置,而是排查那些“看起来像 A 问题、实际是 B 问题”的疑难杂症。所以最后再分享一个小技巧:每次改动配置或代码之前,都把当前能正常工作的状态记录一下,包括话题列表、关键参数和测试结果。这样一旦改坏了,你至少知道自己该退回到哪个状态,而不是凭记忆反推。巡检小车这东西,只要链路是通的,后面加什么功能都不难;链路上有个隐藏的断点,才最折磨人。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询