ARTICLE DETAIL

资讯详情

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

镭神N10激光雷达+IMU融合Cartographer建图实战指南

镭神N10激光雷达+IMU融合Cartographer建图实战指南 1. 为什么选镭神N10搭配Cartographer做建图1.1 硬件选型的现实考量镭神N10是我用过的入门级激光雷达里性价比相当能打的一款。它是一款二维单线激光雷达测距范围在0.05米到10米之间扫描频率可以跑到10Hz角分辨率在0.5度左右。这个参数放在室内建图场景里完全够用尤其是做SLAM建图的时候10米的量程覆盖一个普通房间或者走廊绰绰有余。我当初选它主要看中三点一是价格友好比某些进口品牌便宜一大截二是接口简单直接USB转串口就能出数据不需要额外的驱动板三是ROS生态里已经有现成的驱动包不用自己从零写通信协议。对于刚入门SLAM的玩家来说这三点能省下大量折腾的时间。Cartographer是Google开源的一套SLAM算法框架它的核心优势在于基于图优化的后端能够把激光雷达数据和IMU数据做深度融合。相比Gmapping那种基于粒子滤波的方案Cartographer在回环检测和全局一致性上表现更好建出来的地图不会出现明显的重影或者错位。尤其是在长走廊这种容易累积误差的场景里Cartographer的回环优化能力能救命。1.2 为什么必须加IMU很多人第一次用激光雷达建图的时候会想雷达本身就能测距离为什么还要加IMU这个问题我在刚开始玩的时候也纠结过。实际跑下来发现纯激光雷达在两种情况下会出大问题一是快速旋转的时候雷达帧之间的匹配容易丢失二是走到特征稀疏的区域比如一面白墙扫描匹配会失效。IMU的作用就是提供角速度和加速度信息在激光匹配失效的瞬间用惯性数据推算位姿变化给Cartographer一个先验估计。镭神N10本身不带IMU所以需要外接一个。我用的是常见的九轴IMU模块通过串口和主控连接。IMU和激光雷达之间的外参标定是绕不过去的坎后面会详细讲怎么处理。1.3 整体方案架构整个系统的数据流是这样的镭神N10通过USB转串口把扫描数据发给主控IMU通过另一个串口发姿态数据两个数据源在ROS里分别由对应的驱动节点接收然后统一喂给Cartographer节点做融合建图。主控我用的是一台装了Ubuntu 20.04的迷你主机ROS版本是Noetic。这个组合是目前最稳的社区资料也最全。注意Ubuntu版本和ROS版本必须对应20.04对应Noetic22.04对应Humble。版本不匹配会导致大量依赖问题新手很容易在这里卡住。2. 环境搭建与驱动配置的完整流程2.1 ROS安装的省心方案ROS安装这件事说难不难说简单也不简单。官方教程给的步骤是逐条添加源、安装依赖、初始化rosdep但国内网络环境下rosdep初始化经常失败。我试过几种方案最后觉得最省事的是用鱼香ROS的一键安装脚本。这个脚本会自动处理源替换和依赖安装基本上一条命令就能搞定。安装命令很简单打开终端执行wget http://fishros.com/install -O fishros bash fishros运行之后会出现一个菜单选择对应的ROS版本Noetic然后跟着提示走就行。脚本会自动换源、安装ROS核心包、初始化rosdep。整个过程大概十分钟左右比手动一步步来快得多。安装完成后验证一下环境roscore如果能看到ROS master启动的输出说明安装成功。这时候别急着关另开一个终端测试rosrun turtlesim turtlesim_node看到小海龟窗口弹出来就说明ROS环境没问题了。2.2 镭神N10驱动编译与串口配置镭神N10的ROS驱动包在GitHub上有官方维护的版本直接clone到工作空间的src目录下编译就行。但这里有几个坑需要注意。首先是串口权限问题。Linux默认不允许普通用户直接访问串口设备每次插上雷达都要用sudo才能跑驱动这显然不现实。解决办法是把当前用户加到dialout组sudo usermod -aG dialout $USER执行完之后需要注销重新登录才能生效。这一步很多人会忘结果驱动一直报权限错误。然后是驱动包的编译。创建工作空间mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone https://github.com/leishen-lidar/LSlidar_ROS1.git cd .. catkin_make编译过程中如果报缺少依赖用rosdep补一下rosdep install --from-paths src --ignore-src -r -y编译成功后需要修改launch文件里的串口参数。镭神N10默认的串口波特率是230400串口号通常是/dev/ttyUSB0。但如果你同时接了IMU串口号可能会变。建议用udev规则给设备固定名称避免每次插拔后串口号跳来跳去。创建udev规则文件sudo nano /etc/udev/rules.d/99-lidar.rules写入以下内容根据实际设备的idVendor和idProduct修改KERNELttyUSB*, ATTRS{idVendor}1a86, ATTRS{idProduct}7523, MODE:0666, SYMLINKlidar这样雷达的串口就会固定成/dev/lidarIMU也可以类似处理固定成/dev/imu。2.3 IMU驱动接入与数据验证IMU我用的是维特智能的九轴模块ROS驱动也有现成的包。安装方式和雷达类似clone下来编译就行。关键是配置好串口和波特率确保数据能正常发布到/imu/data话题上。验证IMU数据是否正常可以用rostopic echo /imu/data正常情况下应该能看到orientation、angular_velocity、linear_acceleration三组数据在刷新。如果数据全是零或者不动说明串口配置有问题。如果数据跳动很厉害可能是IMU没有做校准需要先做静态校准。实操心得IMU上电后不要马上移动静置十几秒等它内部完成初始校准。很多便宜的IMU模块没有自动校准功能需要手动发校准指令具体看模块手册。2.4 Cartographer安装与配置Cartographer的安装有两种方式二进制包和源码编译。二进制包安装快但版本可能和你的ROS不完全匹配。源码编译慢但可控性强。我建议用源码编译虽然费点时间但后面改配置和调试方便。安装依赖sudo apt-get install -y \ cmake \ g \ git \ google-mock \ libboost-all-dev \ libcairo2-dev \ libeigen3-dev \ libgflags-dev \ libgoogle-glog-dev \ liblua5.2-dev \ libsuitesparse-dev \ libwebp-dev \ ninja-build \ protobuf-compiler \ python3-sphinx \ libatlas-base-dev然后创建工作空间编译mkdir -p ~/cartographer_ws/src cd ~/cartographer_ws/src git clone https://github.com/cartographer-project/cartographer.git git clone https://github.com/cartographer-project/cartographer_ros.git cd .. rosdep install --from-paths src --ignore-src --rosdistronoetic -y catkin_make_isolated --install --use-ninja编译过程大概需要二十分钟到半小时取决于机器性能。编译完成后source一下环境source ~/cartographer_ws/install_isolated/setup.bash3. 核心配置文件的逐项拆解3.1 Lua配置文件的关键参数Cartographer的配置文件是Lua格式的里面参数很多但真正影响建图效果的就那么几个。我拿镭神N10的实际配置来逐项说明。首先是传感器配置部分tracking_frame imu_link, published_frame base_link, odom_frame odom, provide_odom_frame true, publish_frame_projected_to_2d false,tracking_frame指定用哪个坐标系做位姿跟踪。因为我们要融合IMU所以设成imu_link。published_frame是发布出去的坐标系一般设base_link。provide_odom_frame设true的话Cartographer会自己发布odom到map的变换不需要额外的里程计节点。然后是雷达参数num_laser_scans 1, num_multi_echo_laser_scans 0, num_subdivisions_per_laser_scan 1, num_point_clouds 0,镭神N10是单线雷达输出的是LaserScan类型的数据所以num_laser_scans设1其他都设0。num_subdivisions_per_laser_scan这个参数控制一帧扫描拆成几段处理设1就行设大了反而增加计算量。接下来是IMU相关use_imu_data true, imu_gravity_time_constant 10.,use_imu_data必须设true否则IMU数据不会被使用。imu_gravity_time_constant是重力滤波的时间常数默认10秒一般不用改。3.2 坐标系变换的配置要点Cartographer对坐标系变换TF的要求比较严格配置错了直接导致建图失败。需要确保以下几个变换链是完整的base_link到imu_link的静态变换base_link到laser_link的静态变换雷达和IMU之间的外参变换这些静态变换通过URDF文件或者static_transform_publisher来发布。我习惯用URDF因为结构清晰改起来方便。一个典型的URDF片段link namebase_link/ link namelaser_link/ link nameimu_link/ joint namelaser_joint typefixed parent linkbase_link/ child linklaser_link/ origin xyz0.1 0 0.2 rpy0 0 0/ /joint joint nameimu_joint typefixed parent linkbase_link/ child linkimu_link/ origin xyz0 0 0.1 rpy0 0 0/ /joint这里的xyz和rpy就是雷达和IMU相对于base_link的安装位置和姿态。如果你把雷达和IMU装在不同的高度和角度这些值必须准确填写否则建图会飘。注意雷达和IMU之间的相对位姿比它们各自相对于base_link的位姿更重要。如果两个传感器装得很近可以简化成只有平移没有旋转但如果有明显角度差必须精确标定。3.3 回环检测与子图参数调优Cartographer的核心是子图submap和回环检测。每个子图是一段时间内的扫描累积当机器人走过一段距离后会创建一个新的子图。回环检测就是判断当前扫描是否和之前的子图匹配如果匹配就添加约束优化全局地图。关键参数submaps.num_range_data 90, POSE_GRAPH.optimize_every_n_nodes 90, POSE_GRAPH.constraint_builder.min_score 0.55,num_range_data控制每个子图包含多少帧扫描。设太小子图之间重叠不够回环检测容易失败设太大计算量增加实时性下降。90是一个比较平衡的值对应大约9秒的数据10Hz扫描频率。optimize_every_n_nodes控制多久做一次全局优化。设成和num_range_data一样就行每创建一个新子图就优化一次。min_score是回环检测的最低匹配分数范围0到1。设太高回环检测太严格可能漏掉正确的回环设太低容易误匹配导致地图变形。0.55是经验值室内场景一般够用。3.4 launch文件的组织方式一个完整的launch文件需要启动以下节点雷达驱动节点IMU驱动节点静态TF发布节点或者URDFCartographer节点可选rviz可视化节点我习惯把雷达和IMU的驱动分开写launch文件然后在主launch里include进来。这样调试的时候可以单独启动某个传感器方便排查问题。主launch文件的结构launch include file$(find lslidar_driver)/launch/lslidar_n10.launch/ include file$(find imu_driver)/launch/imu.launch/ node pkgtf2_ros typestatic_transform_publisher namebase_to_laser args0.1 0 0.2 0 0 0 base_link laser_link/ node pkgtf2_ros typestatic_transform_publisher namebase_to_imu args0 0 0.1 0 0 0 base_link imu_link/ node namecartographer_node pkgcartographer_ros typecartographer_node args-configuration_directory $(find cartographer_ros)/configuration_files -configuration_basename lslidar_n10.lua outputscreen/ node namecartographer_occupancy_grid_node pkgcartographer_ros typecartographer_occupancy_grid_node args-resolution 0.05/ /launchoccupancy_grid_node负责把Cartographer的子图转换成栅格地图resolution设0.05表示每个栅格代表5厘米这是室内建图的常用精度。4. IMU融合的标定与调试技巧4.1 IMU静态校准的正确做法IMU的静态校准是很多新手容易忽略的一步。便宜的IMU模块出厂时虽然有初始校准但零偏会随温度和时间漂移。如果不做校准角速度的零偏会导致建图时地图缓慢旋转走一圈回来发现地图歪了。校准的方法很简单把IMU水平静置在桌面上确保没有任何震动然后运行校准程序。不同厂家的IMU校准指令不一样维特智能的模块可以通过串口发送校准命令也可以用厂家提供的上位机软件。校准完成后验证零偏是否在合理范围内。正常情况下静止时角速度的绝对值应该小于0.01 rad/s加速度的模长应该接近9.8 m/s²。如果偏差太大需要重新校准或者检查IMU是否损坏。实操心得校准IMU的时候最好把它装到机器人上再校准因为安装应力会影响零偏。如果先校准再安装装上去之后零偏可能又变了。4.2 雷达与IMU的外参标定外参标定是IMU融合里最麻烦的一步。理论上雷达和IMU之间的旋转和平移可以通过标定算法自动求出来但实际操作中如果两个传感器装得比较近平移量可以忽略只需要标定旋转。我用的方法比较土但很有效把机器人放在一个特征明显的环境里比如有直角墙角的房间先只用雷达建一次图记录地图的样子然后加上IMU再建一次对比两次地图的差异。如果地图出现旋转或者扭曲说明外参的旋转部分有误差手动调整rpy值直到地图正常。更科学的方法是用kalibr工具做联合标定但那个需要标定板和特定的运动轨迹对普通玩家来说门槛偏高。手动调参虽然笨但胜在直观。4.3 IMU数据与雷达数据的时间同步时间同步是融合建图的另一个关键点。如果IMU数据和雷达数据的时间戳差太多融合出来的位姿会抖动。镭神N10的驱动会用自己的时间戳IMU驱动也是两个时间戳如果不同步Cartographer会报错。解决办法是在launch文件里给两个驱动节点都设置use_sim_time参数为false让它们都用系统时间。如果系统时间本身不准可以用ntp同步一下。另外Cartographer有一个参数叫imu_data_queue_size控制IMU数据的缓冲队列长度。默认是10如果发现IMU数据丢帧可以适当加大。4.4 建图飘移的排查思路建图飘移是SLAM里最常见的问题原因可能有很多。我总结了一个排查顺序现象可能原因排查方法地图整体旋转IMU零偏未校准检查静止时角速度输出地图局部扭曲外参标定不准对比纯雷达和融合建图结果回环处错位回环检测参数过严降低min_score试试快速移动时丢失雷达帧率不够提高扫描频率或降低移动速度长走廊累积误差特征稀疏增加IMU权重或加视觉辅助这个表是我踩坑多次后总结的基本上覆盖了八成以上的飘移问题。遇到问题的时候按顺序排查能省不少时间。5. 建图实操与地图保存5.1 启动顺序与注意事项整个系统的启动顺序有讲究。正确的顺序是先启动roscore启动雷达驱动确认/scan话题有数据启动IMU驱动确认/imu/data话题有数据启动静态TF发布最后启动Cartographer如果顺序反了Cartographer启动时找不到传感器数据会直接报错退出。虽然可以设置等待超时但不如按顺序来省心。启动后在rviz里添加LaserScan和Map显示应该能看到雷达扫描线和逐渐构建的地图。如果地图不动或者全是乱线检查TF树是否完整rosrun tf view_frames生成的frames.pdf会显示所有坐标系之间的关系缺哪个补哪个。5.2 建图过程中的操作技巧建图的时候机器人的移动速度很关键。镭神N10的扫描频率是10Hz意味着每0.1秒出一帧数据。如果移动太快相邻帧之间的重叠区域太小扫描匹配容易失败。我实测下来线速度控制在0.3米/秒以内角速度控制在0.5 rad/s以内建图效果最稳。转弯的时候要特别注意尽量匀速转不要急停急转。急转会导致IMU数据突变如果IMU校准不好这时候地图就容易飘。另外建图过程中尽量走回环。比如绕着一个房间走一圈回到起点附近让Cartographer有机会做回环检测。回环检测成功后地图会明显变得更整齐。5.3 地图保存与格式转换建图完成后保存地图有两种方式。一种是保存Cartographer的pbstream格式这种格式保留了所有子图和约束信息后面可以继续优化rosservice call /write_state {filename: ${HOME}/map.pbstream}另一种是保存成ROS标准的栅格地图格式pgmyaml方便后续导航使用rosrun map_server map_saver -f ~/my_map这会生成my_map.pgm和my_map.yaml两个文件。pgm是地图图像yaml是元数据包含分辨率、原点位置等信息。注意Cartographer的occupancy_grid_node发布的地图话题是/mapmap_saver订阅的也是这个话题。如果保存出来是空白地图检查occupancy_grid_node是否正常运行。5.4 建图效果的评估标准怎么判断建出来的地图好不好我一般看三点一是墙壁是否直。好的地图里直墙应该是一条直线不应该有锯齿或者弯曲。如果墙是弯的说明位姿估计有累积误差。二是回环处是否闭合。走一圈回到起点起点附近的地图应该和之前建的重合不应该有错位。如果错位明显说明回环检测没做好。三是地图是否完整。走过的地方都应该有地图不应该有大片空白。如果有空白可能是雷达被遮挡或者扫描匹配失败。6. 常见问题速查与避坑指南6.1 驱动层面的典型问题问题一雷达驱动报错“cannot open /dev/ttyUSB0”这是串口权限或者串口号不对。先检查设备是否识别ls /dev/ttyUSB*如果设备存在但还是报错检查权限ls -l /dev/ttyUSB0如果权限是crw-rw----说明当前用户不在dialout组里按前面说的方法加组。问题二IMU数据频率不稳定便宜的IMU模块在USB转串口的时候容易出现数据丢帧。解决办法是降低波特率或者换一个质量好点的USB转串口芯片。CH340芯片在高速率下丢帧比较严重FT232芯片会好很多。问题三Cartographer启动后立即退出八成是Lua配置文件路径不对。检查launch文件里的configuration_directory和configuration_basename是否正确。另外Lua文件里的语法错误也会导致启动失败可以用lua命令单独测试配置文件lua5.2 -e dofile(your_config.lua)6.2 建图效果的调优经验地图重影严重重影通常是扫描匹配的精度不够。可以尝试调小submaps.num_range_data让每个子图包含更少的帧这样局部匹配更准。但也不能太小太小会导致回环检测失败。我一般从90开始试不行就降到60。地图在长走廊里弯曲长走廊是SLAM的经典难题因为走廊里特征太少雷达扫描匹配容易失效。这时候IMU的作用就体现出来了。可以尝试调大imu_gravity_time_constant让IMU的权重更高。另外走走廊的时候尽量走中间不要贴着墙走这样雷达能看到两侧墙壁特征会多一些。回环检测不触发如果走回起点但地图没有闭合说明回环检测没触发。先检查min_score是不是设太高了降到0.5试试。如果还不行检查POSE_GRAPH.constraint_builder.global_localization_min_score这个参数它控制全局定位的最低分数也需要适当降低。6.3 性能优化的实用技巧Cartographer对CPU性能有一定要求尤其是在做全局优化的时候。如果发现建图过程中电脑卡顿可以尝试以下优化一是降低雷达的分辨率。镭神N10支持多种角分辨率如果不需要太高精度可以设成1度数据量减半。二是关闭rviz的实时显示。rviz渲染地图很吃资源建图的时候可以先把rviz关掉建完再看。三是调整Cartographer的线程数。在Lua配置里可以设置num_threads根据CPU核心数调整。一般设成4就行设太多反而增加调度开销。6.4 从建图到导航的过渡建好图之后下一步通常是做导航。Cartographer建出来的地图可以直接给move_base或者nav2使用。但需要注意几点一是地图的原点要和机器人的初始位姿对齐。Cartographer建图时机器人起点就是地图原点导航时也要从同一个位置启动。二是地图的分辨率要合适。0.05米的分辨率对室内导航够用如果场地很大可以降到0.1米节省内存。三是如果要做自主导航还需要配置代价地图、路径规划器等参数这些就不在本文展开了。实操心得建图和导航最好用同一套TF配置避免坐标系不一致导致定位跳变。我习惯把建图时的URDF直接复制到导航包里省得重新配。6.5 长期使用的维护建议这套系统跑久了有几个地方需要定期检查IMU的零偏会随温度漂移建议每次使用前都做一次静态校准。如果发现建图质量突然下降先检查IMU。雷达的镜头要定期清洁灰尘会影响测距精度。镭神N10的镜头在侧面用眼镜布擦就行别用酒精会伤镀膜。USB连接线要固定好建图过程中如果线松了数据中断会导致建图失败。我一般用扎带把线绑在机器人上留一点余量防止拉扯。最后再分享一个小技巧如果觉得每次启动一堆节点太麻烦可以写一个总的launch文件把所有节点都include进去再加一个开机自启动脚本。这样机器人上电后自动进入建图模式省去手动操作的麻烦。我用的是systemd服务把launch文件包装成服务开机自动运行稳定性比手动启动好很多。
返回列表