
很多刚接触ROS的朋友第一次拿到的雷达基本都是思岚A1虽然现在市面上也有EAI、乐视、镭神这些选择但A1确实凭借性价比和官方驱动完善程度成了新手入门的事实标准。这个雷达本身支持到12米的测距半径采样率在5.5Hz到10Hz之间可调测距精度在0.5米到8米范围内大概是实际距离的1%对于室内建图和导航来说完全够用。这篇文章我就把从零开始用思岚A1在ROS里跑通SLAM建图的全过程拆开讲清楚主要是给那些刚装好ROS、手里有一台A1、然后不知道该从哪里下手的读者。简单说下我的测试环境Ubuntu 20.04 ROS Noetic这是目前A1驱动支持最成熟的组合。如果你用的是Ubuntu 18.04加ROS Melodic或者Ubuntu 22.04加ROS2 Humble后面的步骤需要做少量调整我会在涉及的地方单独说明。整个流程走下来你会实现三个目标第一让A1在Rviz里正常显示雷达点云第二通过键盘遥控或手动推动小车完成一张室内栅格地图的构建第三把构建好的地图保存下来为后续做自主导航做准备。先给个底整个流程并不复杂但牵涉到环境配置、串口权限、驱动编译、SLAM算法选型、tf树检查、地图保存这几个环节任何一个环节出问题都会导致建图失败或者地图质量很差。我见过的绝大多数新手卡住的地方其实就那么几个串口权限没给导致雷达不转、缺少serial包导致编译失败、没有正确source工作空间导致找不到launch文件、棋盘格地图发布错位导致点云漂移。这篇文章会把每个环节的坑都提前标记出来。1. 整体思路拆解为什么是A1加上gmapping这个组合1.1 建图方案选型背后的逻辑SLAM建图说白了就是让机器人一边移动一边回答两个问题我在哪里周围长什么样激光雷达负责提供周围长什么样的信息而里程计odom负责提供我怎么移动的的估计SLAM算法则把这两部分数据融合起来最终输出一张占用栅格地图occupancy grid map。ROS生态里最常用的2D建图算法有gmapping、hector_slam、cartographer、karto_slam这几个。A1作为单线激光雷达最稳妥、最容易上手的就是gmapping因为它对计算资源要求低调参简单依赖少而且在室内小场景下精度足够。hector_slam不需要里程计但要求雷达帧率很高A1的10Hz上限只能说勉强跑起来地图容易飘。cartographer是谷歌的方案精度最高但配置复杂新手很容易被它的lua配置文件劝退。所以这里选择的是gmapping加A1的组合这也是很多入门教程采用的方案原因是gmapping对里程计和雷达的外参标定要求不高只要tf树正确发布哪怕里程计精度一般也能构建出不错的地图。1.2 你需要提前准备的东西硬件方面一台思岚A1激光雷达、一台运行Ubuntu的电脑虚拟机也可以但建议把虚拟机设置里USB兼容性调到USB 3.0否则可能出现设备识别不稳定或者数据丢帧的情况、一根自带的USB数据线。如果你想边建图边控制机器人的运动还需要一个差速底盘或者至少一个能控制电机转动的开发板能把里程计数据发布出来。没有底盘也没关系可以手持雷达在房间里走动但这样建出来的地图精度会差一些因为你没有一个精确的里程计来估计你的移动。软件方面搭载ROS Noetic的Ubuntu 20.04是首选。ROS安装方式现在很多新手都在用鱼香ROS的一键安装脚本这个工具确实省了不少事一条命令装好ROS、自动配置环境变量但装完之后建议手动验证一下环境是否完整后面我会说怎么验证。装完ROS之后还需要安装一些后续会用到的基础工具包。sudo apt update sudo apt install ros-noetic-ros-tutorials ros-noetic-urdf-tutorial ros-noetic-gmapping ros-noetic-map-server ros-noetic-teleop-twist-keyboard这里提前装好gmapping和map_server后面就不用手动下载源码编译了直接用官方二进制包最省心。2. 思岚A1驱动安装与串口权限配置2.1 驱动源码编译的完整步骤思岚官方在GitHub上维护了rplidar_ros这个驱动包它支持A1、A2、A3等型号的雷达原理是通过串口或USB转串口读取雷达的扫描数据然后以sensor_msgs/LaserScan的消息格式发布到ROS话题里。编译驱动的第一步是创建工作空间并克隆代码。mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone https://github.com/Slamtec/rplidar_ros.git cd ~/catkin_ws catkin_make source ~/catkin_ws/devel/setup.bash编译的时候有可能会报错说找不到serial包这个是因为rplidar_ros中部分版本依赖serial库。解决办法很简单安装对应的系统包sudo apt install ros-noetic-serial装完再执行一次catkin_make正常情况下会提示构建成功。如果用的是ROS Melodic把命令中的noetic替换成melodic就行。如果你用的是ROS2和Humble版本思岚官方也有rplidar_ros2仓库克隆下来用colcon build编译但后面的建图流程建议还是用ROS1因为A1的驱动和周边生态在ROS1下面最成熟。2.2 串口权限雷达不转的头号原因A1通过USB转串口跟电脑通信在Linux上对应的设备文件通常是/dev/ttyUSB0。默认情况下普通用户没有权限访问这个设备所以即使雷达插上了、驱动也编译好了启动节点时也会报错说can not open serial port。解决办法有两种。第一种是一劳永逸地把当前用户加入dialout用户组sudo usermod -a -G dialout $USER执行完重新登录一次系统让用户组生效。第二种是直接临时修改设备权限sudo chmod 666 /dev/ttyUSB0这种方式重启后失效适合临时测试。我第一次用A1的时候不知道要给权限折腾了半天以为是雷达坏了后来才意识到是权限问题。另外如果你用的是虚拟机还需要把USB设备从宿主机切换到虚拟机里VMware或VirtualBox都有对应的USB设备直通设置Windows宿主机上如果没做这一步虚拟机里是看不到/dev/ttyUSB0的。2.3 启动雷达并验证数据流在启动驱动的launch文件之前先插上雷达然后手动查看设备是否被识别ls -l /dev/ttyUSB*如果有输出类似于/dev/ttyUSB0的内容说明设备识别正常。接着启动rplidar驱动roslaunch rplidar_ros view_rplidar_a1.launch这个launch文件里包含了rplidarNode节点和rviz的可视化配置启动后你应该能看到两个东西终端里提示RPlidar running然后弹出Rviz窗口显示雷达扫描出来的点云。A1的扫描范围是360度点云会绕成一个圆圈周围物体的轮廓会清晰可见。如果Rviz里只有一个小红点或者什么都没有大概率是帧ID配置有问题这个在后面的常见问题部分会讲。3. SLAM建图的核心原理和完整实操流程3.1 gmapping在背后做了什么事很多新手在用SLAM建图时只知道运行一个launch文件然后看着Rviz里地图从空白逐渐变满但完全不知道这个过程中数据是怎么流转的。其实gmapping的核心思想可以理解为拿雷达最新的扫描帧和已有地图做匹配估算出机器人当前最可能的位置然后把这个扫描帧插入到地图中更新栅格概率。这个过程依赖两个输入一个20Hz到50Hz的激光雷达数据话题/scan另一个是几Hz到几十Hz的里程计数据话题通常是/odom。gmapping订阅这两个话题后构建出的地图会发布在/map话题上同时它会维护并发布/tf变换把odom坐标系和map坐标系关联起来。为什么机器人必须动起来才能建图因为gmapping是利用连续雷达帧之间的几何关系来推算位置变化的如果机器人完全静止雷达看到的环境完全一致gmapping无法从静止的观测中恢复出位移信息。另一方面如果机器人移动太快前后两帧雷达数据之间的重叠区域太小匹配算法就容易失败导致地图出现错位或重影。3.2 底盘端需要准备什么要在真实机器人上建图除了雷达驱动还必须有一个能向ROS发布里程计的底盘控制节点。这里我不具体绑定某一个品牌的底盘因为市面上的方案太多了但你的底盘控制节点至少要做到这几件事周期性地发布nav_msgs/Odometry消息到/odom话题发布tf变换把odom坐标系到base_link坐标准确发布出来接收/cmd_vel话题上的geometry_msgs/Twist消息并驱动电机让底盘按指令运动。如果你暂时没有底盘但有麦克纳姆轮或普通差速底盘开发板网上有很多基于Arduino或STM32发布的ROS串口桥接包原理都是通过串口或CAN总线接收速度指令、返回编码器数据再在PC端把编码器数据换算出位置增量和速度发布成里程计。哪怕里程计有较大的累积误差也没关系因为gmapping会结合雷达观测来修正位姿这正是SLAM比单纯的航位推演高明的地方。3.3 建图launch文件逐行解析我平时使用的建图launch文件很简单但每一行都有讲究。下面是一个可以直接参考的完整文件launch !-- 启动A1激光雷达 -- node namerplidar_node pkgrplidar_ros typerplidarNode outputscreen param nameserial_port value/dev/ttyUSB0/ param nameserial_baudrate value115200/ param nameframe_id valuelaser/ param nameinverted valuefalse/ param nameangle_compensate valuetrue/ /node !-- 启动gmapping建图算法 -- node namegmapping_node pkggmapping typeslam_gmapping outputscreen param namebase_frame valuebase_link/ param nameodom_frame valueodom/ param namemap_frame valuemap/ param namemap_update_interval value2.0/ param namemaxUrange value8.0/ param namemaxRange value12.0/ param nameparticles value40/ param nameminimumScore value50/ param namelinearUpdate value0.05/ param nameangularUpdate value0.1/ param nametemporalUpdate value0.5/ param namedelta value0.05/ /node !-- 启动键盘遥控节点 -- node nameteleop_twist_keyboard pkgteleop_twist_keyboard typeteleop_twist_keyboard.py outputscreen/ /launch这里的关键参数我逐个说明一下。base_frame要跟你底盘的base_link坐标系名称一致如果底盘用的名称不是base_link比如base_footprint这里也要对应修改。maxUrange是激光数据被用于匹配的最远距离设8米表示8米以外的点不参与匹配计算这样可以减少远处噪声对定位的干扰。linearUpdate和angularUpdate分别表示机器人平移多少米或旋转多少弧度后触发一次新的扫描匹配设得太小会导致计算频繁设得太大则地图更新滞后。map_update_interval是每隔多少秒发布一次完整的地图我设的2秒表示地图每隔两秒在Rviz里刷新一次。实际建图过程中你会看到地图不是连续生成一小段然后立刻变完整的而是隔一段时间整体刷新一次这是正常的。3.4 开建了边走边画的完整过程确认雷达驱动正常后把上面的launch文件保存为a1_gmapping.launch放到一个功能包里或者直接在任意路径下用roslaunch加载也行路径写全即可启动它roslaunch a1_gmapping.launch启动完成会出现三个界面状态终端里雷达数据在持续输出Rviz如果没有自动打开手动运行rviz然后添加一个Map显示并选择话题/map键盘遥控终端会显示控制说明。在Rviz中把Fixed Frame设置为map然后添加LaserScan显示话题选/scan再把Map显示也加上你就能同时看到雷达实时扫描线以及正在构建的地图。此时用键盘控制机器人慢慢移动速度建议控制在0.2m/s左右旋转速度控制在0.5rad/s以下。移动速度过快是新手建图最常见的问题地图很容易出现错位和重影。建图路径要不要规划要但不用走非常精确的路径只要遵循慢、匀速、闭环三个原则。慢是指移动速度低匀速是指不要走走停停或突然加速闭环是指尽量把室内空间走一圈并回到起点附近这样能显著改善地图的全局一致性。走完所有空间后再让机器人原地旋转一圈到两圈让雷达能扫描到四周更多的细节特征。3.5 地图保存别把辛辛苦苦建好的图丢了建图完成后需要把内存中的栅格地图保存为文件。这个功能由map_server包提供命令如下rosrun map_server map_saver -f ~/maps/home_map-f后面跟的是保存路径和文件名前缀执行完成后会生成两个文件home_map.pgm和home_map.yaml。pgm文件就是图像格式的栅格地图yaml文件则包含了地图的分辨率、原点坐标、占据阈值等元信息。这两个文件后续在自主导航中必须同时使用amcl和move_base都会加载它们。保存地图前要确保Rviz中的地图已经是最新的最终状态因为map_saver保存的是/map话题上的最新数据。如果你刚停下车就又立刻保存地图可能还没完成最后一次刷新可以等一两秒再执行保存命令。3.6 加载地图验证结果保存完地图后可以用map_server重新加载刚才保存的地图验证文件是否能正常使用roslaunch map_server map_server.launch或者手动启动rosrun map_server map_server ~/maps/home_map.yaml然后启动Rviz把Fixed Frame设为map添加Map显示并选择话题/map你应该能看到刚才保存的地图被加载回来了。这一步虽然简单但能有效验证地图文件没有被损坏也确认yaml和pgm的搭配正确。如果你看到的地图整体是黑乎乎一片或者连轮廓都看不清说明建图过程出了问题需要回到前面的步骤重新检查。4. 常见问题速查我踩过的坑和排查实录4.1 雷达能转但Rviz里没有点云这个问题的表现是雷达电机在转、终端也打印了数据但Rviz里看不到任何点云。排查顺序很重要不要一上来就怀疑雷达坏了。第一步检查话题是否真的有数据输出rostopic echo /scan如果有数据刷屏说明驱动和串口通信正常问题出在Rviz显示配置上。大概率是Fixed Frame设置不对默认的fixed frame是map但如果你还没跑SLAMmap坐标系是不存在的应该先把Fixed Frame改成laser或者base_link。第二步检查LaserScan显示的话题名称是否选对了A1驱动默认是/scan如果你之前启动过其他包可能有多个scan话题。4.2 编译rplidar_ros时报错找不到serial这个问题在全新环境中很常见因为rplidar_ros的某些代码版本在CMakeLists.txt中声明了对serial库的依赖但你的系统还没有安装它。解决办法sudo apt install ros-noetic-serial cd ~/catkin_ws catkin_make如果你用的是源码安装的serial库在CMakeLists中可能还需要加一句find_package(serial REQUIRED)并链接。建议优先用apt安装省事。4.3 建图时地图出现错位或重影这是最让人头疼的建图问题地图上同一个墙壁会出现双重轮廓扫过的走廊越走越宽。原因通常是以下几种雷达安装位置跟base_link不在同一轴线上但没有通过静态变换发布外参或雷达数据有延迟驱动的时间戳不同步或机器人移动速度过快导致gmapping帧间匹配失败或雷达本身的测距数据有偏差。先从最简单的排查开始把机器人的移动速度降下来线速度降到0.1m/s角速度降到0.3rad/s以下再试一次。如果错位依旧检查雷达坐标系的静态变换是否发布了在Rviz中把Fixed Frame设为base_link看LaserScan是否能正确显示在雷达应该所在的位置。还有一种情况是A1在充电时使用电源适配器供电部分电源适配器的纹波干扰会导致测距数据出现周期性的偏差地图上表现为墙边出现锯齿状毛刺。建议用移动电源或电池给雷达供电测试排除。4.4 tf树报错frame_id不匹配在跑建图launch文件的时候终端偶尔会刷出Could not get transform from...或者No transform between frames的警告。这通常是tf树断裂了也就是从map到base_link这一段变换链缺了一环。要完整跑通gmapping必须保证tf树中有这么一条链路map - odom - base_link - laser。gmapping会自己发布map到odom的变换底盘驱动负责发布odom到base_link的变换雷达驱动发布的是laser相对于base_link的变换如果雷达不是直接安装在base_link的原点上需要额外发布一个静态变换来声明两者的相对位置关系rosrun tf2_ros static_transform_publisher 0 0 0 0 0 0 base_link laser比如雷达安装在底盘中心正上方10厘米处就把z参数改成0.1。很多新手只启动雷达和gmapping忘掉了底盘端的tf结果gmapping完全不工作地图一直空白。4.5 雷达数据整体偏移或方向不对A1默认的扫描方向是逆时针如果你在Rviz中看到点云的排列方向跟实际环境相反可能是雷达固定方式导致扫描方向跟base_link坐标系的Y轴方向不一致。调整方法有两个一个是在物理上调整雷达的安装方向另一个是在驱动参数中设置inverted为true或者在静态变换中调整yaw角度来纠正。4.6 Rviz里点云显示出来了但很模糊A1在测量透明玻璃、黑色物体、高反射表面如镜面、瓷砖时容易产生噪声这是所有激光雷达的物理特性决定的不是驱动问题。建图时尽量避开镜面反射强的区域或者把这些区域在后续的地图处理中手动清理。另一个原因可能是串口波特率设置错误A1默认波特率是115200如果改成其他数值会导致数据解析异常。5. 建图质量的三个底层因素和实操心得5.1 雷达帧率、角分辨率与建图分辨率的关系A1的角分辨率并不是固定的它在不同转速下有不同表现转速越快角分辨率越差。在建图这种精度优先的场景下建议把雷达转速调到最低档也就是采样率10Hz时的配置这样单圈扫描的采样点数更多点云更密集。驱动launch文件里angle_compensate参数设为true时A1会自动对角度进行补偿校正把扫描点分配得更均匀这个参数建议保持打开。gmapping的地图分辨率由delta参数控制默认0.05表示每格5厘米。如果想获得更精细的地图可以改成0.02但地图会更吃内存和计算量。一般来说家用环境5厘米分辨率够用了走廊和房间边界已经很清晰。5.2 环境复杂度决定了gmapping的上限gmapping属于滤波类SLAM它的核心假设是当前帧的位姿只跟上一帧的位姿有关如果环境中有大量几何上重复的区域比如很长的走廊、完全一样的仓库货架、空旷的厂房gmapping会逐渐累积误差最后地图可能出现扭曲或闭环不闭合。遇到这种情况可以尝试两条优化路径一是建图时主动走特征明显的路径比如沿墙走、在转角处稍微停顿让雷达多扫几帧二是切换到cartographer它在回环检测方面要强得多但配置成本高一些。A1在室内家庭场景下用gmapping就够在工厂车间或地下车库这种大面积场景建议直接上cartographer。5.3 从建图到导航的地图后处理技巧gmapping保存的地图文件打开后会看到一些杂点和噪声这些噪声如果直接喂给定位系统可能导致之后自主导航时的误匹配。最简单的后处理方式是用图像编辑软件把地图上的孤立噪点手动擦除把明显是动态物体的轮廓比如建图时一不小心误入的人腿处理掉。处理完成后重新保存为pgm文件yaml文件中的分辨率和原点信息维持不变就行。但要注意不要大幅修改地图中墙体轮廓的宽度因为yaml文件里的分辨率已经绑定了像素和物理距离的换算关系改动墙体厚度会直接影响导航时的膨胀半径计算。6. 进阶方向从静态地图到自主导航地图建好只是完成了第一步后续的自主导航需要在静态地图的基础上加入定位模块和路径规划模块。定位通常用amcl它会拿雷达实时扫描跟静态地图做匹配实时估算机器人在map坐标系下的位置。路径规划用move_base它负责在机器人当前位置和目标位置之间规划出一条安全的路径。这个方向的坑比建图还要多但从建图跨到导航是一个很自然的学习路径。我的建议是先把你建好的地图保存好然后去了解amcl的粒子滤波原理、代价地图costmap的膨胀半径配置、以及move_base的全局规划和局部规划参数。等到导航跑通了再考虑是否引入更多传感器比如IMU来做更高精度的建图或者切换到ROS2和cartographer组合。回到A1这个雷达本身它的定位是入门级在室内环境下应付绝大多数场景没有问题。但有个物理短板需要心里有数A1的测距在某些暗色物体和细长物体如桌腿上表现一般这些物体的反射信号弱或者太小扫描点会稀疏。建图时遇到桌腿特别多的情况地图上会出现一圈圆点而不是清晰的轮廓线这是正常的后期手动清理一下即可。我在实际使用中的体会是A1加gmapping这套组合虽然不算惊艳但它是理解SLAM原理最好的入门路径。它足够简单让新手能明确看到每一个模块是怎么协作的它的错误信息也足够直接排查起来不费劲。先把这条路走通再去看cartographer或者LIO-SAM的代码你会发现很多基础概念早就已经在实践中理解透了。最后再分享一个小技巧每次开建之前先让机器人原地旋转两圈再出发能给gmapping一个比较好的初始匹配样本地图初始阶段的稳定性会有明显提升。