ARTICLE DETAIL

资讯详情

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

XTDrone平台上基于2D激光雷达的无人机二维运动规划实践指南

XTDrone平台上基于2D激光雷达的无人机二维运动规划实践指南 先说结论XTDrone这套东西拿来跑2D激光雷达的二维运动规划如果你的目标不是发论文而是真正把无人机自主导航这套流程跑通、跑稳那它绝对是目前开源方案里最省心的一条路。但省心不等于没坑尤其当你从官方demo切到自己改模型、自己配导航参数的时候各种报错和诡异现象会接连不断。这篇文章我就围绕XTDrone平台上基于2D激光Lidar做二维运动规划的完整过程把那些文档里不会写、教程里一笔带过的细节和报错处理方案全部摊开讲。先说清楚“二维运动规划”在这个项目里到底是什么意思。它不是让无人机在三维空间里自由飞而是把无人机固定在一个高度平面上用2D激光雷达感知周围障碍物再在这个平面上规划出一条从当前点到目标点的无碰撞路径。这个场景特别贴近实际工程里的室内巡检、仓库盘点、管道巡查等任务——无人机不需要上下翻飞只需要在一个楼层高度上稳定巡航就行。我自己是把这套流程跑在Ubuntu 18.04 ROS Melodic PX4 1.11 Gazebo 9的组合上这也是XTDrone官方文档最推荐的版本组合。如果你用的是Ubuntu 20.04 ROS Noetic的组合部分依赖包需要自己编译坑会多不少后面我会单独提到。1. 项目脉络与整体架构1.1 XTDrone平台与二维规划任务的关系XTDrone这个平台本质上是一套基于PX4和Gazebo的无人机仿真系统它帮你把飞控、传感器、模型、通信这些底层的东西全部打通了。你在命令行里敲一个脚本就能看到一架无人机在Gazebo世界里缓缓起飞同时ROS话题里铺满了IMU、GPS、光流、激光雷达等各种数据。这种“开箱即用”的体验对做规划算法的同学来说太重要了——你没时间也没必要去折腾飞控底层的PWM信号、串口通信、姿态解算这些东西。那二维运动规划在这个平台里是怎么落地的核心是三个节点协同工作SLAM节点拿2D激光雷达的数据实时构建栅格地图这个项目里最常用的是gmapping如果你想要更好的效果cartographer也是现成可以切的。move_base节点这是ROS导航栈的核心它接收地图、定位信息和目标点通过全局规划器和局部规划器输出速度指令。PX4飞控节点负责把move_base发过来的速度指令转换成无人机实际的位置和姿态变化。三者之间的数据流大概是激光雷达发布/scan话题→gmapping订阅激光数据并发布/map→move_base订阅map和TF树接收/move_base_simple/goal目标点→输出/cmd_vel速度指令→PX4 offboard控制器订阅/cmd_vel并驱动仿真无人机。XTDrone比原生PX4 SITL多出来的价值也正在这里它把整个无人机模型和环境、传感器参数都配好了你可以直接在~/XTDrone/launch下面找到各种启动脚本不用自己从零搭一套仿真。1.2 为什么选2D激光雷达而不是视觉或3D雷达很多刚开始接触无人机导航的人会有个疑问现在视觉方案这么成熟为什么还要用2D激光雷达我的看法是在二维平面导航这个特定任务上2D激光雷达有着不可替代的优势。计算量小单线激光雷达一帧数据量大约是几百到几千个点相比视觉的几十万像素和3D雷达的几十万点云CPU开销完全是降维打击。精度高且稳定激光测距的精度是毫米级的不受光照影响。视觉在暗光、强光、纹理缺失环境下会崩激光不会。语义简单2D激光在固定高度扫描得到的轮廓天然就是平面上的障碍物边界不需要像视觉那样做目标检测和深度估计。在XTDrone里官方iris模型搭载的2D激光雷达实际上是用Gazebo的gazebo_ros_laser插件模拟的。它的扫描范围是360度最大测距30米扫描频率可以配置到10Hz左右和真实场景中rplidar A2/A3的规格非常接近。也就是说你在仿真里调通的算法迁移到真实雷达上不需要做大的改动。2. 环境准备与无人机模型改造2.1 基础环境检查清单如果你是从零开始装XTDrone我建议严格按官方文档走一遍千万别跳步骤。装完之后命令行里逐条检查下面这些项是否正常# 检查ROS主目录是否正常 echo $ROS_PACKAGE_PATH # 检查PX4固件是否编译通过 cd ~/PX4_Firmware make px4_sitl_default # 检查XTDrone脚本是否有执行权限 cd ~/XTDrone ls -la *.sh最容易出现的坑是.bashrc里的环境变量。XTDrone官方要求你把PX4、Gazebo、XTDrone的路径全部写进.bashrc但很多人电脑上以前装过别的ROS包环境变量顺序乱了就会导致Gazebo启动时找不到模型。我的建议是每次打开新终端都先执行source ~/.bashrc然后执行echo $GAZEBO_MODEL_PATH如果返回的路径里没有~/XTDrone/models那你后面所有仿真都会报模型加载失败。2.2 给无人机挂载2D激光雷达XTDrone默认的iris无人机模型是不带激光雷达的需要你自己往模型里加。这一步看着简单其实隐藏了很多细节。首先明确你要改哪个文件。我用的方式是直接修改~/PX4_Firmware/Tools/sitl_gazebo/models/iris_with_lidar/iris_with_lidar.sdf——如果你在XTDrone的模型目录里没找到现成的就自己创建一个iris_with_lidar的模型文件夹从官方iris模型拷贝一份再改。SDF文件里加激光雷达插件的关键代码是sensor namelaser typegpu_lidar always_ontrue/always_on update_rate10/update_rate visualizetrue/visualize topic_namescan/topic_name plugin namelaser_node filenamelibgazebo_ros_laser.so ros namespace//namespace remapping~/out:scan/remapping /ros output_typesensor_msgs/LaserScan/output_type fov6.28319/fov samples360/samples min0.2/min max30.0/max resolution0.01/resolution /plugin /sensor这里有几个参数要特别注意type我建议用gpu_lidar而不是ray。两者都能干活但gpu_lidar的渲染性能好很多仿真跑起来不容易卡。update_rate设成10Hz就是每秒10帧gmapping和move_base对这个频率都很友好。如果你设得太低比如5Hz建图会明显卡顿太高比如50HzCPU直接爆炸。fov是扫描角度范围6.28319就是2π代表360度全向扫描。由于是二维平面规划传感器坐标系Z轴要和无人机机体Z轴平行。改完模型之后还有个关键步骤配置TF变换。激光雷达的数据只有转换到base_link坐标系下才有意义。XTDrone里这个变换通常在iris_with_lidar.sdf的同名配置文件里定义但更常见的做法是在launch文件里加一个静态变换node pkgtf2_ros typestatic_transform_publisher namelaser_to_base args0 0 0.1 0 0 0 base_link laser/这行代码的意思是把laser坐标系固定在base_link坐标系正上方0.1米处三轴无旋转。实际项目中这个高度值要根据你雷达的安装位置来填装高了会漏掉低矮障碍物装低了会打到地面产生大量异常点。3. 建图与定位3.1 gmapping建图原理简析gmapping是基于粒子滤波的2D SLAM算法。它的核心思想是维护一群“粒子”每个粒子代表机器人无人机的一条可能轨迹和对应的地图假设。每来一帧激光数据算法就根据当前粒子的位姿和激光观测去更新地图置信度同时按照观测匹配程度给粒子打分分数低的淘汰分数高的复制如此迭代收敛出最优轨迹和地图。但在XTDrone里跑gmapping有一个很多人没意识到的BUG无人机和地面机器人不一样它在空中会晃动。即使你在Gazebo里把无人机定高锁在一个平面上微小的姿态波动都会让激光雷达扫出来的数据产生扭曲。所以启动gmapping之前一定要把无人机的姿态控制切到offboard模式并且先让它稳定悬停一两分钟等位姿收敛了再开始建图。启动gmapping的核心命令roslaunch xtdrone_nav gmapping.launch里面的关键参数我建议这样设参数推荐值说明map_update_interval5.0地图更新间隔太短CPU狂转太长地图滞后linearUpdate1.0移动多少米触发一次扫描匹配angularUpdate0.5旋转多少弧度触发一次扫描匹配iterations5扫描匹配迭代次数particles30粒子数室内小场景30够了xmin/xmax/ymin/ymax根据场景设置地图边界设太小会导致墙被截断3.2 手动遥控建图的关键操作XTDrone里启动建图后你需要通过QGC地面站或者键盘控制脚本遥控无人机在环境中飞行一圈把整个地图扫出来。这一步比大多数人想象的要费劲因为无人机不像小车它不能原地旋转也不能急停控制不好就会飞出边界。我试过两种方式最终推荐用XTDrone自带的键盘控制脚本cd ~/XTDrone/misc/script python3 keyboard_control.py iris 1 100这个脚本启动后你可以用键盘的WASD控制前后左右方向键控制旋转。注意100这个数字代表的是控制增益它决定了键盘输入的灵敏度数值越大飞机反应越猛新手建议从50开始练。实操中我建议的建图路径是先让飞机原地缓慢旋转360度让雷达把整个房间扫一圈然后沿墙边飞把房间的边界打出来最后再横穿几次房间内部把中间区域的障碍物补全。这样扫出来的地图闭合性好后续move_base规划也不会出问题。4. move_base导航栈的配置4.1 全局代价地图与局部代价地图参数move_base是ROS导航栈的核心它内部包含global_costmap全局代价地图和local_costmap局部代价地图两层分别服务于全局路径规划和局部避障。XTDrone项目里这两层代价地图的配置通常放在move_base.launch或者独立的yaml文件里。我把几个最容易影响无人机任务成败的参数拎出来讲global_costmap参数global_costmap: global_frame: map robot_base_frame: base_link update_frequency: 1.0 publish_frequency: 0.5 static_map: true inflation_radius: 0.5 cost_scaling_factor: 3.0static_map设为true意味着全局地图是固定的就是gmapping建好的那张图不会每次观测都更新。这在建图完成后的导航阶段完全没问题但如果有人在环境中动了障碍物就需要重新建图或者把static_map改成false。local_costmap参数local_costmap: global_frame: odom robot_base_frame: base_link update_frequency: 5.0 publish_frequency: 2.0 static_map: false rolling_window: true width: 4.0 height: 4.0 resolution: 0.05 inflation_radius: 0.4 cost_scaling_factor: 5.0局部代价地图的global_frame要设成odom而不是map这是个非常容易踩的坑。因为局部规划器需要的是一个连续增量式的定位参考而map坐标系是全局地图的绝对参考两者混用会导致局部规划器认为机器人一直在剧烈“跳动”。4.2 move_base与PX4飞控的接口衔接这是这个项目里最核心、也最容易出问题的地方。move_base输出的速度指令是geometry_msgs/Twist发布在/cmd_vel话题上。而XTDrone的PX4 SITL仿真里无人机的位置和速度控制是由一个叫做offboard的控制器来接收的。你需要有一个转换节点把/cmd_vel转换成PX4的/mavros/setpoint_velocity/cmd_vel_unstamped。XTDrone里这个转换节点写在xtdrone_nav功能包里核心逻辑是def cmd_vel_callback(msg): setpoint PositionTarget() setpoint.type_mask PositionTarget.IGNORE_PX | PositionTarget.IGNORE_PY | PositionTarget.IGNORE_PZ | PositionTarget.IGNORE_AFX | PositionTarget.IGNORE_AFY | PositionTarget.IGNORE_AFZ setpoint.coordinate_frame PositionTarget.FRAME_LOCAL_NED setpoint.velocity.x msg.linear.x setpoint.velocity.y msg.linear.y setpoint.velocity.z 0 setpoint.yaw 0 velocity_pub.publish(setpoint)这里需要特别强调一个坐标系的坑ROS的cmd_vel用的是ENU东北天坐标系而PX4的姿态和速度控制用的是NED北东地坐标系。所以从move_base到飞控的转换绝对不能只是简单的转发必须做坐标变换。XTDrone的offboard模式里通常是在setpoint里把Y轴速度取反X轴和Y轴交换具体要看你的PX4的MAV_FRAME设置。如果你发现无人机收到速度指令后乱飞、横着走百分之九十是这个转换出了问题。为了debug我建议你建一个脚本专门监听/cmd_vel这条线rostopic echo /cmd_vel rostopic echo /mavros/setpoint_velocity/cmd_vel_unstamped两个话题同时打印一组一组对比看看转换关系是否符合预期。5. 实操全过程与核心环节实现5.1 完整启动流程在XTDrone上跑通整个二维运动规划我总结了一套稳定的启动顺序写在这里第一步启动XTDrone基础仿真cd ~/XTDrone ./launch/launch_xtdrone.sh这个脚本会启动Gazebo、PX4 SITL和QGC地面站。等Gazebo完全加载出来你看到那架iris无人机在跑到上再等QGC右上角显示连接成功后进行下一步。第二步启动通信桥接和无人机控制脚本cd ~/XTDrone/misc/script python3 communication.py iris 0这一步是在ROS和PX4之间建立offboard通信通道同时完成坐标系转换。脚本跑起来后你的rostopic list里会出现/mavros/setpoint_position/global、/mavros/setpoint_velocity等话题说明通信链路已经建立了。第三步解锁并起飞到指定高度rostopic pub -r 10 /xtdrone/iris/cmd_pose_enu geometry_msgs/Pose position: {x: 0.0, y: 0.0, z: 1.5}注意这个命令是持续发布的必须用-r 10保持10Hz发送频率否则PX4会认为offboard指令丢失自动退出offboard模式。这个高度z: 1.5很关键无人机飞到1.5米高度后激光雷达离地面有一定距离既能避开地面的随机噪点又不会因为太高而漏掉大部分室内障碍物。第四步启动SLAM建图cd ~/XTDrone/navigation roslaunch xtdrone_nav gmapping.launch等Rviz里出现地图轮廓后启动键盘控制脚本遥控无人机把整个环境扫一遍cd ~/XTDrone/misc/script python3 keyboard_control.py iris 1 100第五步保存地图并启动move_baserosrun map_server map_saver -f ~/map roslaunch xtdrone_nav move_base.launchmove_base.launch里需要指定地图文件路径和各类代价地图参数这个我在第4节已经详细讲了。第六步发送导航目标点rostopic pub /move_base_simple/goal geometry_msgs/PoseStamped header: {frame_id: map}, pose: {position: {x: 5.0, y: 3.0, z: 0.0}, orientation: {w: 1.0}}执行完这一步你会看到Rviz里出现一条从当前点到目标点的规划路径无人机开始自动飞行。整个过程里面试了很多次最稳的还是要保证目标点是在free空间里离地图边界和障碍物至少留0.5米的安全距离。5.2 一个完整飞行任务的现场记录我举一个实际在XTDrone跑的室内房间任务做例子。环境是一个约10米×8米的房间中间放了四个方柱障碍物目标是把无人机从房间一角导航到对角位置。实际执行中无人机的表现是这样的起飞爬升到1.5米高度原地旋转扫描确认周围无障碍然后开始沿着全局规划路径直线飞行。当它飞近中间第一根柱子时局部代价地图先检测到柱子轮廓局部规划器我用的TEB开始调整航向绕行。绕行结束后无人机自动恢复向目标点的直线飞行。整个过程大概耗时45秒全程没有触发move_base的“无法规划路径”警告。这45秒里其实隐含了大量参数在起作用。TEB算法有两个参数对无人机影响最大min_obstacle_dist最小避障距离和max_vel_x最大速度。我把min_obstacle_dist设成了0.3米max_vel_x设成了1.0米/秒这样既保证了安全性又不会让无人机因为速度太快导致惯性冲出安全边界。6. 高频报错排查与细节提醒这一节我决定直接上实战记录。以下每一个报错、每一个现象都是我在XTDrone上实际碰到过并且花了不少时间解决的。整理成一个速查表性质的内容方便你遇到了直接对照排查。6.1 TF树异常导致gmapping地图不更新现象gmapping启动后Rviz里看不到地图或者地图只更新几帧就停住不动了。终端里不断刷Waiting for transform from map to scan...。排查思路TF树不完整是首要嫌疑。执行rosrun tf view_frames会生成一个frames.pdf用浏览器打开看整体结构。正常情况下必须有map→odom→base_link→laser这条完整链路。如果odom→base_link缺失说明PX4的里程计发布有问题如果base_link→laser缺失说明你模型文件里的静态坐标变换没加载成功。我遇到过一次奇怪的情况TF树完整但laser坐标系的Z高度是0也就是雷达和base_link完全重合。原因是static_transform_publisher的launch文件里参数顺序写错了前三个数字是xyz后三个数字是rpy我把xyz的0.1填到了rpy的位置。这种低级错误排查起来特别费眼神建议直接一行一行对。终极解决方案检查坐标变换顺序后如果还是不行直接重启整个仿真环境不要试图在运行状态下热修复TF。XTDrone的TF树一旦乱掉很难手工恢复不如重启一次来得干净。6.2 move_base启动即崩溃或规划失败现象启动move_base节点后终端马上刷红色报错或者启动成功但在发送目标点时提示Aborting because the planner failed。常见原因和解决第一个原因是代价地图size设置太小。我之前用默认的10x10米地图结果房间里到处都是障碍物膨胀区域目标点在代价地图边界之外规划器直接判定无解。把local_costmap的width和height调大或者把global_costmap的resolution调低都能解决。第二个原因是inflation_radius设置过大。如果膨胀半径比房间通道还宽规划的路径会被切得支离破碎甚至完全无法通过。一个小技巧是先用costmap_visualization话题把代价地图可视化出来看膨胀区域会不会把通道堵死再做参数调整。第三个原因最隐蔽——ros::Time问题。XTDrone在Gazebo里跑久了/use_sim_time参数如果和系统时钟不同步会导致move_base认为所有传感器数据都过期从而拒绝规划。你的launch文件里必须显式设置param name/use_sim_time valuetrue/同时确保roscore和Gazebo启动顺序是先gazebo后roscore否则模拟时间戳会错乱。6.3 无人机高度漂移或乱飞现象move_base开始规划后无人机不是水平飞到目标点反而上下乱窜或者向某个方向猛冲直接飞丢。这个问题我调试了整整两天最后定位到两个原因。第一个原因是对接节点的速度指令没有控制Z轴。许多自己写的转换节点只处理了X和Y轴速度Z轴直接置零但PX4的offboard控制器要求你发的是完整的位姿或速度setpointPZZ轴位置或者VZZ轴速度都得给一个明确的数值。我给的是位置接口所以Z位置必须恒定设置为1.5米不能是0。第二个原因是PX4的MPC_XY_VEL_MAX参数。这个参数限制了机体在水平方向的最大速度默认值是3.5米/秒。如果你把move_base的max_vel_x设得比这个大还好但如果你设置的速度上限太小PX4的内环控制和外环期望之间会产生矛盾具体表现就是飞机抖、绕圈、轨迹歪斜。解决方式是直接调PX4的参数param set MPC_XY_VEL_MAX 2.0 param set MPC_Z_VEL_MAX 1.0这两个参数在QGC的MAVLink控制台里也能设。调完以后就会稳很多。6.4 Gazebo仿真卡顿与建图异常现象Gazebo界面帧率极低建图时地图出现大量“重影”或漂移。XTDrone的仿真对CPU要求非常高尤其是GPU雷达和TEB局部规划器同时启动时。你可以在启动之前把Gazebo渲染的垂直同步关掉然后在~/.bashrc里限制物理引擎频率export GAZEBO_PHYSICS_FREQ500物理频率越低CPU占用越少但也不能低于250否则无人机在仿真里的动力学会明显失真。重影问题通常是雷达数据帧间匹配误差导致的。把激光的update_rate改成和gmapping的linearUpdate匹配比如雷达10Hzgmapping每5帧0.5秒更新一次地图这样匹配窗口更合理。还有一个建议是把house这类复杂环境换成一个空旷的厂房模型来跑等流程完全跑通后再回归复杂场景。6.5 cartographer切换中的常见坑如果gmapping效果不好想切换成cartographerXTDrone也有对应的launch文件。但cartographer对传感器时间戳的一致性要求极高激光雷达数据和IMU数据的时钟必须同步。实际使用中经常遇到报错Failed to transform cloud from ... frame to tracking frame——这就是雷达到IMU的外参TF没配好。解决方式是在cartographer_occupancy_grid_node里面单独指定tracking_frame: base_link laser_frame: laser baselink_frame: base_link同时要保证雷达数据不丢帧。rosbag record /scan看实际发布频率如果波动太大说明系统实时性不足需要把update_rate降到8Hz来换取稳定帧率。7. 项目扩展思考与个人体会这个项目跑通之后我最大的感受是XTDrone这套仿真平台的价值远不止于跑通一个demo它其实是把“无人机导航”从工程问题变成了算法问题。你在仿真里可以随心所欲地换环境、换传感器、换算法而不用担心炸机风险。甚至可以批量跑几百组随机环境来做路径规划算法的鲁棒性测试。另外一个很实用的扩展方向是把2D激光导航升级为2.5D导航。做法很简单在move_base的costmap里加入高度维度也就是“膨胀层”和“障碍物层”分别配置最小和最大高度范围。这样无人机可以在1.2米和1.8米两个高度之间切换飞行极大拓展了避障能力。虽然严格来说不是纯三维规划但在实际工程中非常常用。把二维运动规划在XTDrone上跑通之后再回看那些教你怎么启动demo的教程你会觉得它们其实没讲透。真正的坑全在参数之间、话题之间、坐标系之间那些看不见的关联里。希望这篇文章能让你少走一些弯路至少别像我一样在TF树上和Z轴速度上各浪费一整天。如果你在实操中遇到我上面没提到的报错欢迎按着“先查TF、再查时间戳、再查坐标系、最后查参数边界”这个顺序去排查大概率能快速定位问题。
返回列表