
项目已开源到Github欢迎StarGitHub - Ikunio/Lidar_nav2_ws: 基于 Livox MID-360 3D LiDAR 的 ROS 2 自主导航工作空间集成 LIO 里程计、重定位、Nav2 导航支持仿真与实机部署。 · GitHub基于 Livox MID-360 3D LiDAR 的 ROS 2 自主导航工作空间集成 LIO 里程计、重定位、Nav2 导航支持仿真与实机部署。 - Ikunio/Lidar_nav2_wshttps://github.com/Ikunio/Lidar_nav2_ws做 3D LiDAR 导航时很多人会遇到一个很微妙但很折磨的问题FAST-LIO 能跑Point-LIO 也能跑点云建图看着也挺帅但一接 Nav2机器人就开始怀疑人生。RViz 里点云很稳轨迹也有甚至/cloud_registered看起来像那么回事。但到了机器人导航这一步问题就来了Nav2 想要的是odom - base_footprintLIO 算法输出的却往往是camera_init - bodyFAST-LIO 和 Point-LIO 的里程计话题还不一样点云坐标系、车体坐标系、雷达坐标系、IMU 坐标系混在一起最后 TF 树一看像一碗没拌匀的麻酱面所以我在这个 ROS 2 3D LiDAR 导航工作空间里专门做了一层LIO 里程计桥接器。它的作用很简单但非常关键把 FAST-LIO / Point-LIO 这种偏算法内部使用的 LIO 位姿转换成机器人导航真正需要的标准里程计odom - base_footprint。换句话说它不是为了让 LIO “看起来能跑”而是为了让 LIO真的能被机器人拿来导航。1. 问题本质LIO 的里程计不等于机器人底盘的里程计很多 LIO 算法输出的位姿本质上描述的是camera_init - body其中camera_initLIO 初始化时建立的世界坐标系body算法内部使用的机体系通常和 IMU / LiDAR 外参强相关位姿含义当前传感器 body 相对于初始化坐标系的运动这对 LIO 算法本身没问题。因为算法只关心我现在相对刚启动时动到了哪里但机器人导航系统尤其是 Nav2更关心的是我的底盘中心在哪里 我能不能基于这个底盘位姿规划、避障、控制这就是区别。LIO 输出的是“传感器 / 算法 body 的位姿”Nav2 需要的是“机器人底盘的位姿”。一个是算法视角。一个是机器人视角。这俩要是不桥接Nav2 就像拿着体检报告去修车——不是没信息是信息语义不对。2. Nav2 真正想要什么在移动机器人导航里常见 TF 树应该长这样map └── odom └── base_footprint └── chassis / base_link └── livox_frame其中map - odom由重定位 / 全局定位模块发布odom - base_footprint由里程计模块发布base_footprint - chassis / base_link机器人底盘静态关系base_link / chassis - livox_frame雷达外参这里面最关键的是odom - base_footprint这条 TF 是局部连续里程计。Nav2 的局部代价地图、控制器、轨迹跟踪都需要它。所以如果你直接把 LIO 的camera_init - body原样丢给 Nav2问题就可能出现body不一定是底盘中心body可能带有雷达 / IMU 安装偏移camera_init不是标准语义下的odom机器人底盘高度、roll、pitch 可能影响 2D 导航FAST-LIO / Point-LIO 输出接口不统一结果就是LIO我没问题我输出了位姿。 Nav2你这位姿是谁的 LIObody 的。 Nav2body 又是谁 LIO这你别管。 Nav2那我也别跑了。3. 桥接器要解决什么这个桥接器的目标不是重新写 LIO也不是重新造 Nav2。它做的是中间这层最容易被忽略、但工程上非常关键的事情FAST-LIO / Point-LIO 输出 ↓ 统一里程计接口 ↓ 坐标系语义转换 ↓ 发布机器人标准 odom ↓ Nav2 可直接使用核心目标有三个3.1 统一 FAST-LIO 和 Point-LIO 的输出FAST-LIO 和 Point-LIO 都是 LIO但输出接口并不完全一样。典型情况是FAST-LIO → /Odometry Point-LIO → /aft_mapped_to_init如果每次切换 LIO 后端都要改 Nav2、改重定位、改 TF、改参数那这个系统就很难维护。所以桥接器第一步就是统一输入FAST-LIO /Odometry Point-LIO /aft_mapped_to_init ↓ 统一转成标准里程计数据这样后面的 Nav2、重定位、点云切片模块都不需要关心你前面用的是 FAST-LIO 还是 Point-LIO。前端可以换后端不用崩。这就叫解耦。说人话就是你 LIO 在前面卷你的算法我 Nav2 在后面开我的车大家通过标准接口说话别互相折磨。3.2 把camera_init - body转成odom - base_footprint这是桥接器最核心的部分。LIO 内部常见位姿可以理解为T_camera_init_body但机器人导航需要的是T_odom_base_footprint所以我们要完成语义转换camera_init ≈ odom body → base_footprint但注意这里不是简单改名字。不是把 frame_id 从camera_init改成odom再把 child_frame_id 从body改成base_footprint就完事。那叫“TF 化妆”不叫“TF 转换”。真正要考虑的是T_odom_base_footprint T_camera_init_body × T_body_base_footprint其中T_camera_init_body来自 LIOT_body_base_footprint是 body 到底盘中心的外参关系输出结果才是机器人底盘在 odom 下的位置如果body本身和底盘中心完全重合那这一步可以简化。但在真实机器人上LiDAR / IMU 往往安装在车体上方或前方不一定在底盘旋转中心。如果不处理这层外参机器人在 Nav2 里就可能出现车体中心偏移旋转时轨迹绕错点局部代价地图和真实底盘不重合雷达点云看似正常但底盘 footprint 位置不对导航时“明明没撞地图上已经撞了明明撞了地图上还说没事”这类问题最阴间因为它不是代码直接报错而是机器人用行为告诉你我能跑但我不想正常跑。3.3 让 3D LIO 更适合 2D 移动机器人导航FAST-LIO / Point-LIO 都是 3D LiDAR-Inertial Odometry。它们可以估计 6DoF 位姿x, y, z, roll, pitch, yaw但大多数室内移动机器人尤其是四轮滑移底盘Nav2 实际上更关心平面运动x, y, yaw也就是说机器人可以在 3D 世界里感知但底盘控制主要还是 2D 运动。所以桥接器需要把 LIO 的 3D 位姿整理成适合底盘导航的形式LIO 6DoF Pose ↓ 提取 x / y / yaw ↓ 构造 base_footprint 平面位姿 ↓ 发布 odom - base_footprint这样做的好处是保留 LIO 的高精度位移估计避免 roll / pitch 直接污染 2D 导航让 Nav2 使用更稳定的底盘平面坐标让代价地图、规划器、控制器的坐标语义更清晰如果不做这层处理机器人在坡度、IMU 抖动、雷达安装倾角变化时Nav2 可能会出现奇怪的位姿抖动。3D LIO 很强但 Nav2 不需要你把所有 3D 姿态都塞给它。就像你问一个人今天吃什么他给你背了一篇《舌尖上的中国》——信息量很大但不一定能下单。4. 桥接后的系统结构整个系统可以理解成下面这条链路Livox MID-360 IMU ↓ FAST-LIO / Point-LIO ↓ LIO Interface ↓ sensor_scan_generation ↓ /odom /tf: odom - base_footprint /registered_scan ↓ 3D 重定位 / 2D 激光切片 / Nav2其中桥接层主要承担两个任务。第一层lio_interface它负责把不同 LIO 后端的输出统一起来。FAST-LIO: /Odometry Point-LIO: /aft_mapped_to_init 统一后: 标准 LIO 位姿输出它解决的是“不同算法接口不一致”的问题。第二层sensor_scan_generation它负责面向机器人导航发布标准数据/tf: odom - base_footprint /odom /registered_scan它解决的是“算法输出不能直接给 Nav2 用”的问题。这两层加起来就把系统从算法能跑提升到了机器人能用这两句话看起来差不多但工程上差了一个通宵。5. 为什么这个桥接器很重要因为机器人系统不是单个算法 Demo。一个完整的 ROS 2 导航系统里面至少有这些模块LIO 里程计TF 树3D 点云重定位2D 激光切片Nav2 代价地图局部规划器全局规划器底盘控制仿真 / 实机切换每个模块都对坐标系有预期。如果坐标系语义不统一就会出现经典问题LIO 说自己没问题 Nav2 说 TF 不对 RViz 说看起来还行 机器人说我选择撞墙这时候你去调参数往往越调越乱。真正的问题不一定是Nav2 参数没调好而可能是你喂给 Nav2 的里程计本来就不是机器人底盘里程计所以桥接器的价值在于它把 LIO 的“算法位姿”翻译成 Nav2 能理解的“机器人底盘位姿”。这一步做好了后面的重定位、导航、代价地图、控制器才有稳定基础。6. FAST-LIO 和 Point-LIO 可以自由切换后端不用大改这个工作空间里同时支持 FAST-LIO 和 Point-LIO。两者各有特点FAST-LIO成熟、稳定、工程使用广泛Point-LIO高频、响应快对部分激烈运动场景更友好如果没有桥接器切换 LIO 后端时可能要连带修改订阅话题TF frameodom 发布逻辑点云输入话题重定位输入Nav2 参数但加入桥接层之后系统结构就变成FAST-LIO ┐ ├── lio_interface ── 标准 odom / TF / registered_scan ── Nav2 Point-LIO ┘后端看到的是统一接口。所以你可以更专注地比较当前场景更适合 FAST-LIO还是 Point-LIO而不是每换一次算法就把整个 ROS 2 工作空间重新做一次“开颅手术”。7. 和重定位模块的关系odom稳了map - odom才有意义在这个系统里重定位模块会发布map - odom而 LIO 桥接器发布odom - base_footprint最终机器人在地图中的位姿就是map - odom - base_footprint这个结构非常关键。LIO 负责局部连续运动。重定位负责把局部里程计对齐到全局地图。Nav2 负责基于全局地图规划和局部避障。如果odom - base_footprint本身就不稳定那么map - odom再准也救不回来。这就像你用高精度 GPS 给一个轮子歪的车导航。地图是准的路线是对的车是斜着跑的。所以桥接器是重定位和 Nav2 的地基。地基不稳别说 KISS-Matcher亲嘴都 Matcher 不上。8. 工程实现思路桥接器的核心实现思路可以概括为// 1. 订阅 LIO 输出 subscribe(lio_odom_topic); // 2. 读取 LIO 位姿 T_camera_init_body odom_msg.pose; // 3. 查询或配置 body 到 base_footprint 的外参 T_body_base getStaticExtrinsic(); // 4. 计算机器人底盘位姿 T_odom_base T_camera_init_body * T_body_base; // 5. 根据移动机器人需求处理平面位姿 x T_odom_base.x; y T_odom_base.y; yaw extractYaw(T_odom_base.rotation); // 6. 发布标准 odom 消息 publish(nav_msgs::msg::Odometry); // 7. 广播 TF broadcastTransform(odom, base_footprint);逻辑不复杂但语义非常重要。这里最容易犯的错误是child_frame_id base_footprint;然后直接把 LIO 的 body 位姿塞进去。这相当于把身份证名字改成“底盘中心”但本人还是雷达。Nav2 不一定立刻报警但机器人迟早用行为艺术表达不满。9. 这个设计带来的收益9.1 Nav2 接入更自然Nav2 不需要理解 FAST-LIO / Point-LIO 的内部坐标系。它只需要标准 TFodom - base_footprint和标准里程计话题/odom这让系统更符合 ROS 2 移动机器人导航的通用范式。9.2 仿真和实机更容易统一仿真和实机最大的区别通常在传感器驱动、URDF、时间源、点云格式。但导航后端最好保持一致。桥接器把前端 LIO 的差异消化掉让后端统一使用/odom /registered_scan odom - base_footprint这样就可以实现仿真调通 → 实机少改 → 直接迁移不是那种“仿真里猛如虎实机上原地杵”的系统。9.3 后续模块更容易复用只要桥接器输出稳定后面模块都可以复用pointcloud_to_laserscansmall_gicp_relocalizationglobal_relocalization_kiss_matcherNav2RViz 可视化底盘控制接口LIO 可以换导航不用换。雷达可以换TF 语义不乱。这就是工程系统里面最值钱的东西模块边界清楚。10. 总结这个桥接器不是配角它是 LIO 走向机器人导航的翻译官很多 3D LiDAR 项目卡住不是因为 LIO 不够强也不是因为 Nav2 不好用。而是中间缺了一层把算法位姿转换成机器人位姿的工程桥接层FAST-LIO / Point-LIO 输出的是 LIO 世界里的位姿。Nav2 需要的是移动机器人世界里的里程计。所以这个桥接器做的事情本质上是camera_init - body ↓ odom - base_footprint它把“算法能跑”变成“机器人能用”。如果说 LIO 是机器人的空间感知能力Nav2 是机器人的行动决策能力那这个桥接器就是中间的翻译官。没有它LIO 在讲高等数学Nav2 在等普通话。有了它机器人终于听懂了你现在在哪车头朝哪可以往哪走。项目地址https://github.com/Ikunio/Lidar_nav2_ws如果你也在做 ROS 2、Livox MID-360、FAST-LIO、Point-LIO、3D LiDAR 重定位或者 Nav2 导航可以看看这个工作空间。别再让 Nav2 硬吃 LIO 原始坐标系了。机器人不是不能跑它只是需要一个靠谱的翻译。