ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

基于hector_mapping与思岚S2的2D激光建图实战指南

基于hector_mapping与思岚S2的2D激光建图实战指南 1. 为什么是思岚S2为什么是hector_mapping1.1 S2这台雷达的定位与参数手里这台思岚S2是我做移动机器人入门时用的第二台雷达。第一台是某宝几十块的玩具级红外测距模块只能测一个方向没法谈建图。后来借了朋友的车载雷达试了一次一次扫描能出三百六十度的点云那种世界在你眼前展开的感觉确实容易让人上头。思岚S2是RPLIDAR S系列里偏均衡的一款官方标称测距半径在12米左右采样频率约9200Hz默认扫描频率10Hz能输出360度全向扫描数据。它用的还是思岚传统的那套三角测距方案激光发射到物体表面反射光经过透镜打在一颗CMOS感光芯片上根据光斑在芯片上的位置用几何关系解出距离。这个原理的好处是成本压得住、近距离精度够用、体积也能做小室内小车的建图需求基本都能满足。S2比较戳我的点是整体设计紧凑一个手掌能握住重量也不大USB供电就能跑不需要额外接电机驱动板。相比之下A系列虽然测得更远、采样率更高但体积和功耗会大一圈适合对距离有硬需求的场景。我第一版小车没预留大空间S2这种插上USB就能转的形态就很合适。1.2 hector_mapping和gmapping到底怎么选ROS生态里做2D建图绕不开gmapping、hector_mapping、cartographer这几个名字。如果你去论坛搜S2建图最常见的组合其实是gmapping因为它有大量现成教程。但gmapping有一个硬前提必须要有稳定的里程计输入不然粒子滤波那一套没法定位。hector_mapping就不一样它走的是扫描匹配路线。什么意思它不需要轮式里程计也不需要IMU只靠激光雷达点云本身就能在地图中推算当前位置并完成建图。S2一批批地往外吐扫描帧hector在后台做这帧点云和已有地图怎么对齐的优化计算位姿和地图就这样一步步长出来了。这就决定了它们的适用场景维度gmappinghector_mapping是否需要odom需要且质量影响很大不需要自带scan matching适合载体差速底盘、全向底盘手持、无人机、无编码器底盘初始化难度需要机器人先动起来 / 有里程信息雷达转起来就能出图长走廊表现相对稳健但有里程计累计误差容易漂移需要人为规避调参成本粒子数、更新频率等参数较多参数少但地图尺寸依赖强如果你手头已经有完整的差速小车里程计质量还可以建图直接上gmapping或者cartographer都没问题。但如果你跟我一样先用一块雷达验证算法、或者想在手持模式下扫一个房间hector_mapping是最省事的入口。1.3 我踩的第一个坑接上雷达并不等于能建图第一次跑的时候我天真地以为驱动装好、雷达转起来、Rviz里出现点云就算成功了一半结果被现实狠狠教育了一顿。当时我按教程装了rplidar_ros启动后Rviz里确实有了一团团扫描线但hector_mapping节点压根没起地图当然一片空白。更迷惑的是一个小时后我终于把hector节点拉起来了Rviz却开始刷tf错误提示找不到从map到laser的坐标变换。那一刻我才意识到建图不是雷达和建图算法两个程序拼在一起就完事中间还横着一条完整的TF坐标链。这也是为什么我在这篇文章里专门用一整章讲tf没把坐标变换理顺后面所有时间都在跟报错搏斗。2. Ubuntu 20.04 Noetic下的驱动准备从源码到串口2.1 安装rplidar_ros的正确姿势我的环境是Ubuntu 20.04配ROS Noetic。S2的驱动包思岚官方维护在GitHub上开发代号rplidar_ros。我建议直接拉源码编译不要只依赖apt里的旧版本因为新版launch文件里已经适配了S1、S2、S2E等一堆型号旧版往往只到A2。mkdir -p ~/s2_ws/src cd ~/s2_ws/src git clone https://github.com/Slamtec/rplidar_ros.git cd ~/s2_ws catkin_make echo source ~/s2_ws/devel/setup.bash ~/.bashrc source ~/.bashrc编译过程一般没有坑依赖就是roscpp、sensor_msgs、std_msgs这些基础包Noetic默认都有。编译完以后去~/s2_ws/src/rplidar_ros/launch/目录下拉个清单能看到rplidar_s2.launch这样的文件。有个小提醒如果你电脑上以前装过别的rplidar包先确认它们不会互相污染ROS_PACKAGE_PATH。我遇到过两次roslaunch起了一个不知名旧版本launch文件的情况排查了半天最后发现是~/.bashrc里source了不止一个工作空间顺序还不对。简单的做法是建图专用的工作空间只保留rplidar_ros和hector相关包别什么都往里堆。2.2 串口权限与设备识别大部分雷达没数据的根源S2通过USB转串口跟电脑通信默认设备名一般是/dev/ttyUSB0。第一次插上雷达后你会发现ls -l /dev/ttyUSB0的权限经常是crw-rw----只有root和dialout组的用户能读。当前用户不在dialout组里就会出现权限拒绝。永久解决方式是把用户加进dialout组sudo usermod -a -G dialout $USER加组以后需要注销重新登录一次组权限才会生效这一步很多人会忽略结果还是报Permission denied。另外建议用lsusb看一眼雷达的USB信息。S2的USB转串口芯片一般是Silicon Labs的CP2102lsusb输出里能看到类似10c4:ea60的编号。这个信息在写udev规则、绑固定设备名时特别有用。如果你的电脑上同时插了Arduino、USB转串口板之类的东西/dev/ttyUSB0可能会漂移。我处理这种问题习惯加一条udev规则把雷达固定成/dev/rplidarKERNELttyUSB*, ATTRS{idVendor}10c4, ATTRS{idProduct}ea60, MODE0666, SYMLINKrplidar保存为/etc/udev/rules.d/99-rplidar.rules然后sudo udevadm control --reload-rules。以后再插雷达直接用/dev/rplidar就行不用每次猜设备名。2.3 用官方SDK先测一遍硬件把问题分层装ROS驱动前我强烈建议先用思岚官方SDK跑一次裸测。这一步能把硬件不行和ROS配置有问题这两类问题分得清清楚楚省下后面一半的排错时间。思岚官方SDK叫rplidar_sdk同样在GitHub上git clone https://github.com/Slamtec/rplidar_sdk.git cd rplidar_sdk make ./output/Linux/Release/ultra_simple /dev/ttyUSB0如果终端开始刷scan count: xxx、角度、距离这类数据说明雷达硬件、USB线、串口通信都正常问题只可能出在ROS层。如果超时、打不开串口先把供电和USB线换一遍再试。我遇到过最典型的假故障是供电不足雷达电机能转但激光不输出数据。后来把USB线从扩展坞换到电脑原生USB口一切正常。所以裸测这一步真的别省。3. hector_mapping的核心逻辑没有里程计也能建图3.1 scan-to-map匹配到底在算什么要理解hector为什么不需要odom得先搞清楚它每时每刻在做什么计算。雷达给出一帧点云hector把这一帧点云和已经建好的栅格地图做匹配。所谓匹配就是寻找一个位姿变化量让当前这帧点云投影到地图上之后跟地图里已经画出来的墙壁、障碍物的重合度最高。这个优化问题hector用高斯牛顿法求解对栅格地图做双线性插值来保证梯度信息可用。用人话说就是闭着眼睛在一个黑暗房间里每走一步都伸出手去摸墙。如果摸到墙的位置和脑子里记忆的墙的位置一致就能确信自己还在原来的位置上。激光雷达就是那只手hector_mapping就是那个用摸墙结果不断修正人在哪的算法。由于这个匹配过程完全不依赖轮子转了几圈、编码器读了多少脉冲所以雷达装在一个没有轮子的手持支架上也能建图。这也是S2这种独立扫描雷达和hector是绝配的原因。但代价也很直接它每一步的位姿修正都是增量式的只要某一帧匹配错了后面的所有帧都会在这个错误基础上继续积累。这就是为什么hector的建图过程需要人为控制速度、避免剧烈晃动。3.2 tf树里谁是谁map、odom、base_link、laser一次理清ROS里的tf树对新手来说是最劝退的抽象概念之一。对建图来说你需要理清四个坐标系map世界坐标系最终地图就是在它下面展开的。odom里程计坐标系通常由轮式编码器、IMU或者视觉里程计维护是连续、平滑的。base_link机器人本体的基准坐标系一般固定在底盘中心。laser激光雷达的坐标系位于雷达物理安装位置。在带底盘的常规机器人里odom到base_link的变换由里程计节点发布base_link到laser的变换按雷达安装位置写死map到odom的变换由定位或建图节点发布。gmapping就是一边用里程计作为位姿预测先验一边算出map到odom的修正量。hector_mapping也有类似行为它发布map到odom的变换但前提是它能在tf树里找到odom - base_link - laser这条链路。所以即便hector不用odom里的轮速信息tf树上也得有一个odom - base_link变换存在哪怕这个变换是恒等的。很多新手栽在这里单独启动雷达驱动和hector_mapping结果Rviz报Could not find transform from map to laser。缺的就是这条链路。3.3 手持模式下的tf补全方案没有轮式底盘的手持建图场景最简单的做法是发布两个静态坐标变换一个把odom和base_link绑成恒等变换一个按照雷达实际安装位置发布base_link和laser之间的变换。典型的命令是这样的# odom到base_link手持场景下没有真实里程计用恒等变换占位 rosrun tf2_ros static_transform_publisher 0 0 0 0 0 0 odom base_link # base_link到laser如果雷达就在底盘坐标系原点、方向一致也是恒等变换 rosrun tf2_ros static_transform_publisher 0 0 0 0 0 0 base_link laser如果雷达不是正装比如装反了、激光发射口朝后就需要在偏航角上加π。示例命令里的六个数字分别是xyz和rpy把最后一个参数改成3.14159就能把激光方向转180度。laser和base_link分离还有一个实际意义雷达装在底盘几何中心前面比如前侧10厘米处那就把static_transform的x改成0.1。不要小看这点偏移不做补偿的话建出来的图在转弯处会有明显的拖影。我自己在手持建图时习惯把雷达和一块小板绑在一起base_link和laser几乎重合所以直接用了恒等变换。但你如果是往小车上装务必量好安装位置。4. 建图实操一个能跑的launch文件到Rviz4.1 完整的launch文件下面这个launch文件是我在S2上验证过的完整组合集成了雷达驱动、hector_mapping、tf补全和Rviz。把它保存为s2_hector.launch放到你的工作空间里roslaunch直接跑就行launch !-- 雷达驱动 -- node pkgrplidar_ros typerplidarNode namerplidarNode outputscreen param nameserial_port value/dev/ttyUSB0/ param nameserial_baudrate value115200/ param nameframe_id valuelaser/ param nameinverted valuefalse/ param nameangle_compensate valuetrue/ /node !-- hector_mapping -- node pkghector_mapping typehector_mapping namehector_mapping outputscreen param namemap_frame valuemap/ param nameodom_frame valueodom/ param namebase_frame valuebase_link/ param namescan_topic value/scan/ param namepub_map_odom_transform valuetrue/ param namemap_size value1024/ param namemap_resolution value0.05/ param namelaser_min_dist value0.15/ param namelaser_max_dist value10.0/ /node !-- 手持模式下的虚拟里程计tf -- node pkgtf2_ros typestatic_transform_publisher nameodom_to_base args0 0 0 0 0 0 odom base_link/ node pkgtf2_ros typestatic_transform_publisher namebase_to_laser args0 0 0 0 0 0 base_link laser/ !-- Rviz -- node pkgrviz typerviz namerviz args-d $(find hector_slam_launch)/rviz_cfg/mapping_demo.rviz/ /launch如果你机器上没装hector_slam_launch这个包Rviz那行会报找不到文件。保险的做法是直接用rosrun rviz rviz手动打开Rviz然后在里面添加Map显示和LaserScan显示把Map的topic选成/mapLaserScan的topic选成/scan。4.2 关键参数逐条说明参数不是越多越好hector_mapping需要重点关注的就这么几个map_frame、odom_frame、base_frame三个坐标系的名称必须和tf里发布的一致。我习惯统一用map/odom/base_link/laser这套命名后续接navigation栈时省事。scan_topic要订阅的激光话题rplidar_ros默认发布/scan一般不用改。pub_map_odom_transform设为true时hector会发布map - odom的变换。对于手持模式我们的odom - base_link是恒等变换所以map - base_link实际上就是hector维护的机器人真实姿态。map_size地图的尺寸单位是格子数而不是米。配合0.05的map_resolution1024格意味着地图覆盖约51米乘51米的范围。一般人活动范围不超过这个但你要是打算扫一整层办公楼记得把这个值放大。map_resolution每个格子的物理尺寸单位是米/格。0.05是精度和性能的折中。追求更快就用0.1追求细节就用0.025。laser_min_dist和laser_max_dist参与匹配的激光距离范围。0.15米以下的点一般是雷达近处的杂散噪声参与匹配只会添乱10米以上的点太远精度下降也建议过滤掉。这里最容易被忽略的是map_size和map_resolution的关系。如果只调大map_size忘了map_resolution地图覆盖范围会变但内存和CPU开销也直线上升如果你想扫更精细的图直接把map_resolution调小就行但记得map_size要么跟着调大要么你活动范围本来就很小。4.3 建图操作的节奏与技巧launch文件跑起来以后Rviz里应该能看到灰色底图逐渐被黑色障碍物填满。如果一切正常雷达会像一只无形的手把周围墙壁描出来。但这只是开始建图的成败七成取决于你怎么移动雷达。我的操作习惯是这样的先在原地把雷达左右转一整圈让hector对初始位置有一个可靠的估计。然后沿着墙边缓慢移动速度控制在每秒二三十厘米以内转弯的时候尤其要慢。碰到走廊或者门框这种几何特征明显的位置多停留一两秒让雷达把特征吃透。另一个重点是路线规划。hector没有回环检测扫过的地方如果漂移了回头再扫一遍并不能自动纠正反而会让地图出现重影。我一般会刻意走回字形路线从一个房间开始绕一圈回起点再进入下一个区域尽量不让轨迹出现大跨度跳跃。建图过程中千万不要在空旷的墙面前长时间停留太久。一面没有任何凹凸的白墙在激光看来就是一条直线这条直线前后移动时特征极弱hector很容易在这一维度上滑走。看到这种环境快速通过远比慢刷有效。5. 建图过程中的疑难杂症排查5.1 雷达无数据的完整排查链路如果你启动后/scan话题没有数据按下面这条链路查基本能覆盖九成问题lsusb看电脑是否识别到USB设备。如果没有换USB口、换线。dmesg | grep ttyUSB看内核日志里有没有设备接入记录。如果看到usb 1-1: cp210x converter now attached to ttyUSB0说明设备端正常。ls -l /dev/ttyUSB*看设备权限。如果所属组没有你的用户回到2.2节处理。用官方SDK的ultra_simple裸测。如果SDK能出数据说明硬件和串口都没问题问题在ROS launch参数。检查launch里serial_port和serial_baudrate。S2一般用115200但某些固件版本可能不同以官方launch文件为准。如果以上都正常但Rviz还是没点检查话题名是不是/scan以及Rviz的Fixed Frame是不是laser或map。排查串口问题时一个容易忽视的细节是供电。我用过一根五米长的USB延长线雷达插上去电机转动正常但激光数据时断时续rostopic hz /scan抖动得厉害。换成随机附带的短线以后数据瞬间稳定。工业现场如果必须用长线优先选带磁环、粗线芯的线缆。5.2 点云错位和重影的处理建图时最打击人信心的画面是一面笔直的墙在地图上变成了两条近似的平行线或者墙角处多出一团毛刺。这通常是三个原因叠加的结果。第一个原因是base_link - laser的坐标变换没写对。雷达哪怕偏了1厘米在近距离扫描时也能看出重影。处理方式是把雷达安装到固定支架上量好实际位置填进静态变换的参数里。第二个原因是雷达在旋转扫描的过程中载体也在移动。激光雷达每一个扫描周期是0.1秒如果这0.1秒里你正好在快速转动雷达那么这一帧点云的不同角度其实对应着不同的雷达位置直接拼起来就糊了。hector的扫描匹配能在一定程度上补偿这个畸变但补偿有限。手动扫图时转动要匀、平移要慢这是最有效的消除重影办法。第三个原因藏在rplidar_ros的参数angle_compensate里。这个参数开启后驱动会尝试对旋转运动造成的点云角度偏差做插值补偿。实测下来开着它对动态场景是有帮助的建议保持true。如果地图已经出现明显的错位改参数是救不回来的。正确做法是清空地图重新扫。hector没有回环优化别指望它能自动修复已经画歪的墙。这也是2D建图绕不开的物理现实。5.3 走廊与空旷场景的漂移问题hector最怕的环境是长走廊。走廊方向上的激光分布几乎是一条条平行线scan-to-map匹配在这个方向上缺乏有效的约束高斯牛顿迭代会在走廊轴向自由滑动表现出来就是扫描着扫描着地图突然向侧面扭歪。我扫过一条二十多米长的走廊走到中段时地图边缘已经开始出现锯齿状错位墙与墙之间的夹角也不再是90度。这是算法层面的退化不完全是雷达的锅。应对办法有几个。第一进走廊前在入口处多停留、多转几圈让地图对入口区域建立强特征。第二在走廊里不要直线走到黑走轻微的蛇形路线或者Z字路线给匹配算法沿轴向的约束。第三如果条件允许用带门洞、消火栓、指示牌这种凸起物丰富特征的走廊。如果走廊又长又平那基本可以提前接受地图会有偏差的现实。相比之下S2在桌椅林立的办公室里建图就游刃有余。桌腿、椅子腿、显示器边缘这些密集的几何特征给了hector充足的匹配支撑。所以如果你只是要扫一间办公室不用担心太多大胆跑。5.4 运行久了地图糊了CPU与分辨率的平衡另外一个容易被忽略的坑是运行时长的资源消耗。S2以9200Hz的频率出点云hector每帧都在做栅格地图插值匹配如果map_resolution设得太小或者map_size设得太大老旧的CPU会直接跑满。我试过map_resolution0.025加map_size2048在一颗低压笔记本CPU上Rviz的帧率明显下降建图过程也开始一顿一顿。后来把分辨率调回0.05流畅度立刻回来了。0.05米的分辨率对于室内导航来说已经足够再细的图主要是好看实用性提升有限。还有desired_publish_period这个参数控制hector发布地图Topic的频率默认大概是0.05秒一次。发布太频繁CPU压力大发布太慢Rviz刷新又跟不上。我一般保持默认只有在树莓派这类低性能平台上才会改成0.1。如果你用树莓派跑S2加hector建议做一个心理准备能跑但很吃力地图刷新会有可见延迟。有条件的话把Rviz放到另一台电脑上通过局域网查看树莓派上只跑雷达驱动和hector性能压力会小很多。6. 地图保存与后续扩展6.1 用map_server保存地图并重新加载扫完整片区域后地图保存在ROS的话题/map里。需要持久化保存到磁盘用map_server自带的map_saver最直接mkdir -p ~/maps rosrun map_server map_saver -f ~/maps/office运行后会生成office.pgm和office.yaml两个文件。.pgm是灰度位图黑色代表障碍物、白色代表自由区域、灰色代表未知区域.yaml里记录了分辨率、原点、阈值等元数据。保存前有个小技巧停住手里的雷达两秒钟等地图没有明显变化后再执行map_saver。这样保存下来的地图里不会混入正在移动的残影。重新加载地图验证一下rosrun map_server map_server ~/maps/office.yaml在Rviz里添加Map显示Topic选/map如果看到和建图时一致的地图轮廓说明保存成功。6.2 从2D地图到导航AMCL和move_base的衔接地图建好了下一步自然是导航。把S2、hector和navigation栈串起来的常见做法是先用map_server发布静态地图然后启动AMCL做自适应蒙特卡洛定位最后用move_base做路径规划。有一点要提前说清楚不管建图时用的是gmapping还是hector导航阶段的定位最好不要继续用hector实时scan matching。原因很简单导航时机器人可能在未知扰动下移动hector没有全局重定位能力一旦起步位姿错一点就拉不回来。AMCL不一样它会在整张地图上撒粒子即使机器人被外力推了一把也能重新收敛到正确位置。AMCL跑起来需要一个质量还不错的/odom话题。如果你的底盘轮式里程计精度太差AMCL的表现会很难看。这里可以接受的做法是用轮式编码器搭一个简单的里程计节点发布odom - base_link变换再让AMCL维护map - odom。整个tf链跟建图时是同一套只是odom - base_link不再是一个恒等变换而是真实的轮式里程计数据。6.3 从S2到3D建图云台倾斜与多线雷达如果你用S2把2D建图彻底玩明白了再往深处走有三条路。第一条路是给S2加一个单轴云台让它上下俯仰扫描配合IMU和LIO-SAM这类LiDAR-Inertial里程计算法拼出带高度的3D点云地图。这个方案成本可控但工程复杂度不低云台的角度同步、时间同步、IMU标定都是硬骨头。第二条路是直接上多线雷达。现在Livox MID-360配合FAST-LIO2是社区里很火的组合3D实时建图效果非常惊艳代价是价格和算力需求都上去了。如果你只是在室内小车项目里做导航S2的经济性和够用性其实更有优势。第三条路是继续深挖2D算法本身比如把建图工具换成cartographer。它的2D模式有回环检测建大场景时的鲁棒性比hector高不少但配置复杂度也高了一个数量级。先把你手上的S2和hector彻底跑通再切换到cartographer你会更清楚每个参数的效益。最后说一点个人体会。我前后用S2跑了不下二十遍hector最大的心得是建图失败往往不是雷达不行而是人在操作时太着急。雷达转一圈只有0.1秒这点时间内如果载体移动了十几厘米后面的scan matching就要在误差里硬找解。把速度放慢、提前规划好路线、在地图边界附近多建立特征比调任何参数都管用。串口权限和tf树这两个基础问题建议第一次就彻底搞定否则后面次次都踩坑。希望这篇折腾记录能让你少走点弯路一次就把图建得整整齐齐。
返回列表