三维SLAM算法LeGO-LOAM源码阅读(四)

本文深入探讨了位姿信息融合计算的过程,详细分析了通过odomAftMappedHandler和laserOdometryHandler函数如何处理精配准和粗配准的里程计信息,实现位姿与速度的综合计算并发布最终里程计话题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最后一个部分是对位姿信息的融合计算,难得代码不长,先看看构造函数:

//综合后发送的里程计信息
pubLaserOdometry2 = nh.advertise<nav_msgs::Odometry> ("/integrated_to_init", 5);
//特征匹配时粗配准的里程计信息
subLaserOdometry = nh.subscribe<nav_msgs::Odometry>("/laser_odom_to_init", 5, &TransformFusion::laserOdometryHandler, this);
//建图精配准之后的里程计信息
subOdomAftMapped = nh.subscribe<nav_msgs::Odometry>("/aft_mapped_to_init", 5, &TransformFusion::odomAftMappedHandler, this);

因此该节点是由两个回调函数所驱动的。我们先看到odomAftMappedHandler这个回调函数:

void odomAftMappedHandler(const nav_msgs::Odometry::ConstPtr& odomAftMapped)
    {
        double roll, pitch, yaw;
        geometry_msgs::Quaternion geoQuat = odomAftMapped->pose.pose.orientation;
        tf::Matrix3x3(tf::Quaternion(geoQuat.z, -geoQuat.x, -geoQuat.y, geoQuat.w)).getRPY(roll, pitch, yaw);
        //位姿作为计算的基础
        transformAftMapped[0] = -pitch;
        transformAftMapped[1] = -yaw;
        transformAftMapped[2] = roll;

        transformAftMapped[3] = odomAftMapped->pose.pose.position.x;
        transformAftMapped[4] = odomAftMapped->pose.pose.position.y;
        transformAftMapped[5] = odomAftMapped->pose.pose.position.z;
        //速度作为下一次计算的先验
        transformBefMapped[0] = odomAftMapped->twist.twist.angular.x;
        transformBefMapped[1] = odomAftMapped->twist.twist.angular.y;
        transformBefMapped[2] = odomAftMapped->twist.twist.angular.z;

        transformBefMapped[3] = odomAftMapped->twist.twist.linear.x;
        transformBefMapped[4] = odomAftMapped->twist.twist.linear.y;
        transformBefMapped[5] = odomAftMapped->twist.twist.linear.z;
    }

因此是通过odomAftMappedHandler函数获取精配准后的位姿作为transformAftMapped,而获取配准后的速度信息作为transformBefMapped准备下一次计算。

而laserOdometryHandler是将粗配准的里程计信息与精配准的里程计信息融合计算,并在回调函数中便发送了最终外发的里程计话题。在该回调函数中的TF与里程计话题才是最终决定的。融合计算的过程实在头晕,下次再仔细看看。。。

void laserOdometryHandler(const nav_msgs::Odometry::ConstPtr& laserOdometry)
    {
        currentHeader = laserOdometry->header;

        double roll, pitch, yaw;
        geometry_msgs::Quaternion geoQuat = laserOdometry->pose.pose.orientation;
        tf::Matrix3x3(tf::Quaternion(geoQuat.z, -geoQuat.x, -geoQuat.y, geoQuat.w)).getRPY(roll, pitch, yaw);

        transformSum[0] = -pitch;
        transformSum[1] = -yaw;
        transformSum[2] = roll;

        transformSum[3] = laserOdometry->pose.pose.position.x;
        transformSum[4] = laserOdometry->pose.pose.position.y;
        transformSum[5] = laserOdometry->pose.pose.position.z;
        //位姿与速度的融合计算
        transformAssociateToMap();

        geoQuat = tf::createQuaternionMsgFromRollPitchYaw
                  (transformMapped[2], -transformMapped[0], -transformMapped[1]);

        laserOdometry2.header.stamp = laserOdometry->header.stamp;
        laserOdometry2.pose.pose.orientation.x = -geoQuat.y;
        laserOdometry2.pose.pose.orientation.y = -geoQuat.z;
        laserOdometry2.pose.pose.orientation.z = geoQuat.x;
        laserOdometry2.pose.pose.orientation.w = geoQuat.w;
        laserOdometry2.pose.pose.position.x = transformMapped[3];
        laserOdometry2.pose.pose.position.y = transformMapped[4];
        laserOdometry2.pose.pose.position.z = transformMapped[5];
        pubLaserOdometry2.publish(laserOdometry2);

        laserOdometryTrans2.stamp_ = laserOdometry->header.stamp;
        laserOdometryTrans2.setRotation(tf::Quaternion(-geoQuat.y, -geoQuat.z, geoQuat.x, geoQuat.w));
        laserOdometryTrans2.setOrigin(tf::Vector3(transformMapped[3], transformMapped[4], transformMapped[5]));
        tfBroadcaster2.sendTransform(laserOdometryTrans2);
    }

那么我们回溯一下这两个话题,粗配准的里程计信息是FeatureAssociation发出的,精配准的信息是mapOptimization发出的,均以200Hz的频率,当odomAftMappedHandler收到精配准信息后更新位姿,这个位姿将在laserOdometryHandler收到下一条粗配准信息后综合计算再发出。

最后来一张搓搓的图解释整个过程:

### KITTI 数据集与 LEGO-LOAM 激光雷达里程计算法实现 #### 关于 KITTI 数据集 KITTI 是一个广泛用于自动驾驶研究的数据集,提供了丰富的传感器数据,包括立体相机、单目相机、GPS/IMU 和 Velodyne 激光扫描仪获取的信息。该数据集不仅涵盖了城市道路场景下的多种交通状况,还包含了标注好的目标检测框以及语义分割标签等辅助信息[^2]。 #### LEGO-LOAM 算法简介 LEGO-LOAM (Lightweight and Ground-based Lidar Odometry and Mapping) 是一种轻量级地面激光雷达里程计和建图方法。此算法通过提取特征点和平面来匹配连续两帧之间的变换关系从而完成定位功能;同时利用这些几何约束条件构建局部地图模型以提高精度稳定性。其主要优点在于计算效率高且易于实现实时应用,在资源受限设备上也能良好工作。 #### 实现教程概览 对于想要深入了解并实践 LEGO-LOAM 的开发者来说,可以从以下几个方面入手: 1. **环境搭建** - 安装 ROS(Robot Operating System),因为大多数开源 SLAMLOAM 库都是基于这个平台开发出来的。 - 获取最新版的 PCL(Point Cloud Library),这是处理三维点云的核心库之一。 2. **理解核心原理** - 掌握基本概念如 ICP(Iterative Closest Point), NDT(Normal Distributions Transform) 等配准技术。 - 学习如何从原始 LiDAR 扫描中抽取边缘特征(line feature extraction) 及平面要素(plane feature extraction). 3. **代码解析** 下载官方 GitHub 上发布的源码,并按照 README 文件指示编译安装依赖项。重点查看 `loam_velodyne` 节点内的几个重要函数: ```cpp void laserCloudHandler(const sensor_msgs::PointCloud2ConstPtr& scanMsg); void extractFeatures(); void associateWithMap(); ``` 4. **调试优化** 使用 rviz 工具加载 KITTI 提供的真实世界轨迹作为参考标准来进行对比分析。调整参数直至达到满意的效果为止。
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值