LEGO-LOAM轨迹保存与evo评估

版本:Ubuntu20.04+ros-noetic

续上一篇博客lego-loam运行遇到的问题以及解决办法-CSDN博客

成功运行lego-loam之后,轨迹没有自己保存,所以需要我们手动改一下源码,话不多说直接上干货:

方法1.kitti格式的保存

首先按照kitti-lego-loam源码的readme文件,修改对应的代码,主要内容为:

(1)featureAssociation.cpp

将   float s 10 * (pi->intensity - int(pi->intensity)); 
改为 float s = 1;

// to delete all the code that corrects point cloud distortion
注释掉以下两行
TransformToEnd(&cornerPointsLessSharp->points[i], &cornerPointsLessSharp->points[i]); 
TransformToEnd(&surfPointsLessFlat->points[i], &surfPointsLessFlat->points[i]); 


记得把回环检测打开,设置 "loopClosureEnableFlag" 为 "true"  

(2)transformfusion.cpp

 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);

/added, cout results///

	Eigen::Quaterniond q;

	q.w()=laserOdometry2.pose.pose.orientation.w;
	q.x()=laserOdometry2.pose.pose.orientation.x;
	q.y()=laserOdometry2.pose.pose.orientation.y;
	q.z()=laserOdometry2.pose.pose.orientation.z;

	Eigen::Matrix3d R = q.toRotationMatrix();

	if (init_flag==true)	
	{
		
	H_init<< R.row(0)[0],R.row(0)[1],R.row(0)[2],transformMapped[3],
       	 	 R.row(1)[0],R.row(1)[1],R.row(1)[2],transformMapped[4],
       	 	 R.row(2)[0],R.row(2)[1],R.row(2)[2],transformMapped[5],
          	 0,0,0,1;  
	
	init_flag=false;

	std::cout<<"surf_th : "<<surfThreshold<<endl;

 	}

	H_rot<<	-1,0,0,0,
	    	 0,-1,0,0,
     	   	 0,0,1,0,	
     	    	 0,0,0,1; 
		
	H<<  R.row(0)[0],R.row(0)[1],R.row(0)[2],transformMapped[3],
	     R.row(1)[0],R.row(1)[1],R.row(1)[2],transformMapped[4],
     	     R.row(2)[0],R.row(2)[1],R.row(2)[2],transformMapped[5],
     	     0,0,0,1;  

	

	H = H_rot*H_init.inverse()*H; //to get H12 = H10*H02 , 180 rot according to z axis

	std::ofstream foutC(RESULT_PATH, std::ios::app);

	foutC.setf(std::ios::scientific, std::ios::floatfield);
        foutC.precision(6);
 
	//foutC << R[0] << " "<<transformMapped[3]<<" "<< R.row(1) <<" "<<transformMapped[4] <<" "<<  R.row(2) <<" "<< transformMapped[5] << endl;
	 for (int i = 0; i < 3; ++i)	
	{	 
		for (int j = 0; j < 4; ++j)
        	{
			if(i==2 && j==3)
			{
				foutC <<H.row(i)[j]<< endl ;	
			}
			else
			{
				foutC <<H.row(i)[j]<< " " ;
			}
			
		}
	}

	foutC.close();


//
        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);

    }

为方便我直接把整个修改后的函数放上来。

然后,在transformfusion.cpp的private中加上以下内容:

    int init_flag=true;

    Eigen::Matrix4f H;
    Eigen::Matrix4f H_init;
    Eigen::Matrix4f H_rot;

    //你的路径
    const string RESULT_PATH = "/media/cairui/Backup Plus/ubuntu20/KITTI/myRes.txt";

记得在对应路径创建你的  路径.txt  文件,之后保存编译即可得到kitti格式的轨迹,但是这个保存后的轨迹只能单个拎出来,我输出之后无法进行绝对误差对比,个人感觉是没有时间戳的问题,所以没法和kitti真值比,于是使用了方法2.

方法2.Tum格式的保存

以上的修改甚至可以不用动,直接去mapOptmization.cpp中,修改

void visualizeGlobalMapThread()这个函数,修改内容参考这位大佬

内容我再列一遍:

//保存轨迹信息(时间戳、xyz、旋转四元数q)
void visualizeGlobalMapThread(){
        ros::Rate rate(0.2);
        while (ros::ok()){
            rate.sleep();
            publishGlobalMap();
        }
        // save final point cloud
        std::cout << "start save final point cloud" << std::endl;
        std::cout << "======================================================" << std::endl;
 
        ofstream f;
        f.open("/home/nb/traj_slam/06_own_tum.txt");						
        f << fixed;
        //std::cout << "traj roll" << cloudKeyPoses6D->points[0].roll << std::endl;
        for(size_t i = 0;i < cloudKeyPoses3D->size();i++)
        {
            float cy = cos((cloudKeyPoses6D->points[i].yaw)*0.5);
            float sy = sin((cloudKeyPoses6D->points[i].yaw)*0.5);
            float cr = cos((cloudKeyPoses6D->points[i].roll)*0.5);
            float sr = sin((cloudKeyPoses6D->points[i].roll)*0.5);
            float cp = cos((cloudKeyPoses6D->points[i].pitch)*0.5);
            float sp = sin((cloudKeyPoses6D->points[i].pitch)*0.5);
 
            float w = cy * cp * cr + sy * sp * sr;
            float x = cy * cp * sr - sy * sp * cr;
            float y = sy * cp * sr + cy * sp * cr;
            float z = sy * cp * cr - cy * sp * sr;
            //save the traj  减掉第0个时间戳。cloudKeyPoses6D->points[0].time == 1317400962.039569
            f << setprecision(6) << (cloudKeyPoses6D->points[i].time-cloudKeyPoses6D->points[0].time) << " " << setprecision(9) << -1*(cloudKeyPoses6D->points[i].x) << " " << -1*(cloudKeyPoses6D->points[i].y) << " " << -1*(cloudKeyPoses6D->points[i].z) << " " << x << " " << y << " " << z << " " << w << endl;
        }
 
        f.close();
}

这位大佬对时间戳进行了修正,所以用这个代码可以完美解决问题,还有一篇用的同样的办法但是没有进行时间戳修正,导致输出的轨迹仍然无法进行对比评估,所以用这个比较好。

之后保存编译即可,记得修改路径。

完~~~~有问题欢迎交流!

2024/5/21补充:

今天在多次运行的时候,发现添加了IMU数据并且开启了回环检测之后,误差居然达到了不开启时的十倍之多,仔细检查发现是开头的几秒内y轴方向发生了极大的漂移,于是觉得是自己的轨迹保存有问题,又换了好几种办法,折腾了半天,最后得出结论,按本文的轨迹保存办法毫无问题,尤其是TUM那个方法,之所以我会出现极大误差,是因为,没有进行IMU和激光雷达的标定,所以使用IMU数据反而会使效果变差。

2024/5/22补充:

至于为什么同样的配置和参数,跑出来有时候效果很好有时候效果很差,我个人的理解是,跟系统运行偶然发生的卡顿(比如你的bag播放时会有某一小段时间因为系统卡顿导致那段bag数据卡没了,或者因为节点卡顿导致的那段接收或者发布有问题)有很大的关系。也是受到这篇博客的启发,发现这个问题也发生在自己身上了,虽然我没用他的那个包,但是原理一样,确实是和系统运行状态有一定的关系,多跑几次,你就会发现效果还是不错。

然后我想到,既然会因为卡顿丢数据导致产生大误差,那怎么才能防止卡顿丢数据呢,除了提高硬件性能,刚刚那位博主提出来压缩bag包,但是我的bag已经很小了,所以没必要,于是我觉得会不会让bag播放的慢一点,会防止卡顿丢太多数据,于是 -r 0.5试了一下,绝了!!!!!果然可以,太合理了哈哈。

  • 9
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值