VINS - Fusion GPS/INS/视觉 融合 0、 Kitti数据测试

2023-05-16

 放两张图片,至于为什么?后面会解释!

 

 

 

程序下载:https://github.com/HKUST-Aerial-Robotics/VINS-Fusion

数据集制作:https://zhuanlan.zhihu.com/p/115562083

测试:https://blog.csdn.net/weixin_39702448/article/details/107545488

数据评估:https://blog.csdn.net/weixin_47074246/article/details/109134740

KITTI数据集00序列times.txt文件 https://download.csdn.net/download/haolele3587/12262651

KITTI 数据跑 双目+IMU的问题 https://zhuanlan.zhihu.com/p/75672946

                                                        https://zhuanlan.zhihu.com/p/115562083

                                                       https://www.it610.com/article/1282169330733170688.htm

一、准备

步骤一、指定输出路径:打开vins-fusion/config/kitti_raw/kitti_10_03_config.yaml  或  kitti_raw/kitti_09_30_config.yaml

(根据数据集选择具体参数文件),第十行 output_path: "/home/tony-ws1/output/"
这里指明自己需要保存到的地址,本人:output_path: "/home/hltt3838/GPS_Stereo_Ins/output/"

步骤二、修改代码使其输出轨迹文件,原本的vins_fusion是无轨迹文件输出的 globalOptNode.cpp中vio_callback函数

    std::ofstream foutC("/home/tony-ws1/output/vio_global.csv", ios::app);//这里还是文件输出位置
   foutC.setf(ios::fixed, ios::floatfield);
    foutC.precision(0);
    foutC << pose_msg->header.stamp.toSec() * 1e9 << ",";
    foutC.precision(5);
    foutC << global_t.x() << ","
            << global_t.y() << ","
            << global_t.z() << ","
            << global_q.w() << ","
            << global_q.x() << ","
            << global_q.y() << ","
            << global_q.z() << endl;
    foutC.close(); 

这部分改成如下:

     //这里还是文件输出位置,最好和前面位置一样
    std::ofstream foutC("/home/hltt3838/GPS_Stereo_Ins/output/vio_GPS_global.txt", ios::app);

   foutC.setf(ios::fixed, ios::floatfield);
    foutC.precision(0);
    foutC << pose_msg->header.stamp.toSec() << " ";
    foutC.precision(5);
    foutC << global_t.x() << " "
            << global_t.y() << " "
            << global_t.z() << " "
            << global_q.x() << " "
            << global_q.y() << " "
            << global_q.z() << " "
            << global_q.w() << endl;
    foutC.close(); 

注意:

这里不仅把数据的保存地址改了,而且把数据的顺序也改了! 1e9 “ ,”也改了

 

二、运行

 

打开第一个终端

roscore    

 

打开第二个终端

进入工作区间内,分别输入:

cd  GPS_Stereo_Ins/catkin_ws

catkin_make     //单独一个端口,编译后关闭,没有修改程序不用编译,可以用于检查程序问题

source  devel/setup.bash      

roslaunch vins vins_rviz.launch

 

打开第三个终端

进入工作区间内,分别输入:

cd  GPS_Stereo_Ins/catkin_ws

source  devel/setup.bash  

rosrun   vins   kitti_gps_test  src/VINS-Fusion/config/kitti_raw/kitti_10_03_config.yaml   /home/hltt3838/kitti_data/2011_10_03_drive_0027_sync/

//rosun  包名   执行文件              argv[1]                                                                                                                 argv[2]

%     /home/hltt3838/ kitti_data/2011_10_03_drive_0027_sync/       是数据的位置

 

打开第四个终端

进入工作区间内,分别输入:

cd  GPS_Stereo_Ins/catkin_ws

source  devel/setup.bash  

rosrun global_fusion global_fusion_node

 

三、处理结果

(1) 进入输出结果的文件夹:

cd  GPS_Stereo_Ins/output

(2) 使用evo分析结果,这里是tum数据格式,故使用

evo_traj tum vio_GPS_global.txt -p

绘图结果如下:

(3)对比真值

真值是12列的kitti轨迹格式,所以要将真值转换成8列格式的tum轨迹格式

python kitti_poses_and_timestamps_to_trajectory.py  00.txt times.txt  kitti_00_gt.txt

转换得到tum格式的真值后,我们可以进行评定,将我们得到的vio_GPS_global.txt 与这里的真值进行对比

evo_ape tum vio_GPS_global.txt   kitti_00_gt.txt -a  -p

注意:右图点击上面的map才可以出来这个对比图!

 

四、出现的问题

 

问题1:

真值 kitti_00_gt.txt 怎么生成的?

答:

将KITTI的 pose 里面的 00.txt 加上时间戳 times.txt,转换成TUM格式的; 需要注意的是:pose 是个单独的文件,

不在 2011_10_03_drive_0042_sync 数据里面,自己从网上下载吧!

在evo文件夹下有一个contrib文件夹,里面有一个kitti_poses_and_timestamps_to_trajectory.py文件。

把KITTI数据集下的 00.txttimes.txt 文件拷贝到该目录,运行如下命令:

cd   evo-master/contrib

python kitti_poses_and_timestamps_to_trajectory.py  00.txt  times.txt  kitti_00_gt.txt

通过该指令完成转换, 转换得到tum格式的真值后 kitti_00_gt.txt

我们可以进行评定,将我们得到的 vio_GPS_global.txt 与这里的真值进行对比

evo_ape tum vio_GPS_global.txt   kitti_00_gt  -a  -p

 

问题2:

rviz  显示 小车的轨迹和GPS数据垂直!

答:

虽然,轨迹和GPS数据垂直!但在 (3)对比真值 时,两个轨迹是对齐的!

而且去看看程序你就会发现,两条线垂直,一条是 vio的结果,一条是vio转换到世界坐标系下的结果,

转换矩阵 是根据每次的优化值重新求得的结果,本来人家就不应该一样,为啥非让人家重合呢!

 

问题3:

配置文件里面的IMU 变成1 , rosrun global_fusion global_fusion_node 运行不了!为什么?

答:

需要改程序!2011_10_03_drive_0027_sync 文件里面虽然有IMU数据,但是我们仅仅是读取出来了,

并没有用它!GPS和IMU数据是放在一起的,具体的意思如下:

问题4:

 为什么很少见 “视觉+IMU+GPS的组合”呢?是因为他们没有必要嘛?

答:

其实VINS-fusion已经实现了,只是需要进行一下组合罢了!也可能做这方面的人少,个人感觉还是有价值的,

对于大场景来说很有必要的!后面自己会尝试组合一下,感觉更多是数据的处理!

 

 

五、视觉 + IMU + GPS

 

前面我们跑的程序其实是:双目+GPS; VINS-Fusion 里面并没有   双目+IMU+GPS!

但是本人想把这个组合跑起来,所以自己动手写了一下,具体步骤如下,如果效果好,会公开细节!

 

数据预处理

2011_10_03_drive_0042_sync 为例,这个数据是图片和激光雷达对齐后的数据;

此数据中GPS和IMU数据在一起,但是IMU的时间是和图片的时间一样的,10HZ!

因此我们如果想实现 IMU+图像+GPS的数据,必须把100HZ的IMU数据和时间提取出来;

还有对应的 2011_10_03_drive_0042_extract, 这是没有对齐的数据,其中IMU的时间为100HZ,因此

我们要从这个文件里面把IMU数据提取出来!值的注意的是,KITTI数据里面的图像、激光雷达、GPS的数据是10HZ !

 下面是我提取数据的程序!

#include <iostream>
#include <stdio.h>
#include <cmath>
#include <string>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <ros/ros.h>
#include "estimator/estimator.h"
 

int main(int argc, char** argv)
{
	ros::init(argc, argv, "vins_estimator");
	ros::NodeHandle n("~");
    
	
    string sequence1 = "/home/hltt3838/kitti_data/2011_10_03_drive_0042_extract/";
	string dataPath1 = sequence1 + "/";
   
    string sequence2 = "/home/hltt3838/kitti_data/2011_10_03_drive_0042_sync/";
	string dataPath2 = sequence2 + "/";
	
     /*----------------------------IMU读取数据----------------------------------*/    
    //读取 100HZ的IMU时间
	FILE* file1;
	file1 = std::fopen((dataPath1 + "oxts/timestamps.txt").c_str() , "r");
	if(file1 == NULL){
	    printf("cannot find file: %soxts/timestamps.txt \n", dataPath1.c_str());
	    return 0;          
	}
	vector<double> imuTimeList;
	int year1, month1, day1;
	int hour1, minute1;
	double second1;
   while (fscanf(file1, "%d-%d-%d %d:%d:%lf", &year1, &month1, &day1, &hour1, &minute1, &second1) != EOF)
	{
	    imuTimeList.push_back(hour1 * 60 * 60 + minute1 * 60 + second1);
	}
	std::fclose(file1);
    /*------------------------------IMU读取数据-------------------------------*/
     
    
    /*----------------------------GPS读取数据----------------------------------*/    
    //读取 100HZ的IMU时间
	FILE* file2;
	file2 = std::fopen((dataPath2 + "oxts/timestamps.txt").c_str() , "r");
	if(file2 == NULL){
	    printf("cannot find file: %soxts/timestamps.txt \n", dataPath2.c_str());
	    return 0;          
	}
	vector<double> gpsTimeList;
	int year2, month2, day2;
	int hour2, minute2;
	double second2;
   while (fscanf(file2, "%d-%d-%d %d:%d:%lf", &year2, &month2, &day2, &hour2, &minute2, &second2) != EOF)
	{
	    gpsTimeList.push_back(hour2 * 60 * 60 + minute2 * 60 + second2);
	}
	std::fclose(file2);
    /*------------------------------GPS读取数据-------------------------------*/
    
    string OUTPUT_imu = "/home/hltt3838/kitti_data/imu_data_100hz/"; //不能有空格
    FILE* outFile_imu;
	outFile_imu = fopen((OUTPUT_imu + "/imu.txt").c_str(),"w");
 
    string OUTPUT_gps = "/home/hltt3838/kitti_data/gps_data_10hz/"; //不能有空格
    FILE* outFile_gps;
	outFile_gps = fopen((OUTPUT_gps + "/gps.txt").c_str(),"w");
    
    
    for (size_t i = 0; i < imuTimeList.size(); i++)
	{	
            stringstream ss;
			ss << setfill('0') << setw(10) << i;
        
            //读取GPS信息
			FILE* imuFile;
			string imuFilePath = dataPath1 + "oxts/data/" + ss.str() + ".txt";
			imuFile = std::fopen(imuFilePath.c_str() , "r");
			if(imuFile == NULL){
			    printf("cannot find file: %s\n", imuFilePath.c_str());
			    return 0;          
			}
			double lat, lon, alt, roll, pitch, yaw;
			double vn, ve, vf, vl, vu;
			double ax, ay, az, af, al, au;
			double wx, wy, wz, wf, wl, wu;
			double pos_accuracy, vel_accuracy;
			double navstat, numsats;
			double velmode, orimode;
			
			fscanf(imuFile, "%lf %lf %lf %lf %lf %lf ", &lat, &lon, &alt, &roll, &pitch, &yaw);
			fscanf(imuFile, "%lf %lf %lf %lf %lf ", &vn, &ve, &vf, &vl, &vu);
			fscanf(imuFile, "%lf %lf %lf %lf %lf %lf ", &ax, &ay, &az, &af, &al, &au);
			fscanf(imuFile, "%lf %lf %lf %lf %lf %lf ", &wx, &wy, &wz, &wf, &wl, &wu);
			fscanf(imuFile, "%lf %lf %lf %lf %lf %lf ", &pos_accuracy, &vel_accuracy, &navstat, &numsats, &velmode, &orimode);

			std::fclose(imuFile);
        
        fprintf (outFile_imu, "%f %f %f %f %f %f %f \n",imuTimeList[i],ax,ay,az,wx,wy,wz);
       
    }
    
    for (size_t i = 0; i < gpsTimeList.size(); i++)
	{	
            stringstream ss;
			ss << setfill('0') << setw(10) << i;
        
            //读取GPS 信息
			FILE* gpsFile;
			string gpsFilePath = dataPath2 + "oxts/data/" + ss.str() + ".txt";
			gpsFile = std::fopen(gpsFilePath.c_str() , "r");
			if(gpsFile == NULL){
			    printf("cannot find file: %s\n", gpsFilePath.c_str());
			    return 0;          
			}
			double lat, lon, alt, roll, pitch, yaw;
			double vn, ve, vf, vl, vu;
			double ax, ay, az, af, al, au;
			double wx, wy, wz, wf, wl, wu;
			double pos_accuracy, vel_accuracy;
			double navstat, numsats;
			double velmode, orimode;
			
			fscanf(gpsFile, "%lf %lf %lf %lf %lf %lf ", &lat, &lon, &alt, &roll, &pitch, &yaw);
			fscanf(gpsFile, "%lf %lf %lf %lf %lf ", &vn, &ve, &vf, &vl, &vu);
			fscanf(gpsFile, "%lf %lf %lf %lf %lf %lf ", &ax, &ay, &az, &af, &al, &au);
			fscanf(gpsFile, "%lf %lf %lf %lf %lf %lf ", &wx, &wy, &wz, &wf, &wl, &wu);
			fscanf(gpsFile, "%lf %lf %lf %lf %lf %lf ", &pos_accuracy, &vel_accuracy, &navstat, &numsats, &velmode, &orimode);

			std::fclose(gpsFile);
        
        fprintf (outFile_gps, "%f %f %f %f %f \n",gpsTimeList[i],lat,lon,alt,pos_accuracy);
       
    }
    
	if(outFile_imu != NULL)
		fclose (outFile_imu);
    
    if(outFile_gps != NULL)
		fclose (outFile_gps);
    
	return 0;
}

提取数据

cd  GPS_Stereo_Ins/catkin_ws

catkin_make     

source  devel/setup.bash      

rosrun vins change_data

 

获得数据后,需要计算IMU和相机之间的外参!具体的参数介绍看下面的连接!

https://blog.csdn.net/cuichuanchen3307/article/details/80596689

代码如下:

import numpy as np;
from numpy import *
  

IMU_2_V =np.mat([[9.999976e-01, 7.553071e-04, -2.035826e-03,-8.086759e-01],
                   [-7.854027e-04, 9.998898e-01, -1.482298e-02, 3.195559e-01],
                   [2.024406e-03, 1.482454e-02, 9.998881e-01,-7.997231e-01],
                   [0,0,0,1]])

V_2_C = np.mat([[7.967514e-03, -9.999679e-01, -8.462264e-04, -1.377769e-02],
                    [-2.771053e-03, 8.241710e-04, -9.999958e-01, -5.542117e-02],
                    [9.999644e-01, 7.969825e-03, -2.764397e-03, -2.918589e-01],
                    [0,0,0,1]])

  

C_2_C1 = np.mat([[9.993440e-01, 1.814887e-02, -3.134011e-02, -5.370000e-01],
                    [-1.842595e-02, 9.997935e-01, -8.575221e-03, 5.964270e-03],
                    [3.117801e-02, 9.147067e-03, 9.994720e-01, -1.274584e-02],
                    [0,0,0,1]])


C_2_C1_ = np.mat([[1, 0, 0, 0.537150653267924],
                   [0, 1, 0, 0,],
                   [0, 0, 1, 0,],
                   [0, 0, 0, 1]])



IMU_2_C0 = V_2_C*IMU_2_V
IMU_2_C0 = IMU_2_C0.I

#####################################

IMU_2_C1 = C_2_C1_.I*V_2_C*IMU_2_V
IMU_2_C1 = IMU_2_C1.I


print("Tb_2_c0:")
print(mat(IMU_2_C0))
 
print("Tb_2_c1:")
print(mat(IMU_2_C1))


 


可能有人对公式有点迷茫!这里说一下转换矩阵的  Ra_2_b

Ra_2_b 可以是 a坐标系到b坐标系之间的转换;也是 b坐标系上的点,经过 Ra_2_b矩阵 投影到 a 坐标系上的点;

还可以是 a 坐标系下, b坐标系的姿态!

外参定义:b坐标系下的点 经过 T 后,转换到 C坐标系 下的矩阵!外参 = Tc_2_b (这个写法可能每个人不一样!)

 

运行程序:

cd  kitti_data/2011_10_03_calib

python maxtrix_4_4.py

结果如下:

body_T_cam0: !!opencv-matrix
   rows: 4
   cols: 4
   dt: d
   data: [ 0.00875116, -0.00479609,  0.99995027,  1.10224312,
          -0.99986428, -0.01400249,  0.00868325, -0.31907194,
           0.01396015, -0.99989044, -0.00491798,  0.74606588,
           0, 0, 0, 1]
 
 
body_T_cam1: !!opencv-matrix
   rows: 4
   cols: 4
   dt: d
   data: [ 0.00875116, -0.00479609,  0.99995027,  1.10694381,
          -0.99986428, -0.01400249,  0.00868325, -0.8561497 ,
           0.01396015, -0.99989044, -0.00491798,  0.75356458,
           0, 0, 0, 1]

得到外参后,我们把参数放在自己写的配置文件中即可运行程序

注意啦、注意啦!注意啦!

程序中有两个C0到_C1 的转换矩阵, 其中,C_2_C1是下面这个文件给的,但是这个是不准确的,不要相信呀,我被坑残了!

C_2_C1_ 是 VINS-fusion 跑纯双目时给的 矩阵 body_T_cam1因为没有IMU的时候,body = C0

这个才是对的,不然的话你们跑 IMU+双目+GPS  用 KITTI数据效果特别差的!自己可以体验一下!

其实我们也可以分析出C_2_C1是有问题的,你看看平移量t就明白了,再看看最前面我们放的两张图片中相机之间的位置,只有x方向上有区别!

我看了博客上也有人遇到这个问题,和他们交流他们也不知道问题所在,好在还是弄出来了!对后面的同学一定很有帮助!

 

 

运行程序

打开第一个终端

roscore    

 

打开第二个终端

进入工作区间内,分别输入:

cd  GPS_Stereo_Ins/catkin_ws

catkin_make     //单独一个端口,编译后关闭,没有修改程序不用编译,可以用于检查程序问题

source  devel/setup.bash      

roslaunch vins vins_rviz.launch

 

打开第三个终端

进入工作区间内,分别输入:

cd  GPS_Stereo_Ins/catkin_ws

source  devel/setup.bash  

rosrun   vins   camera_IMU_GPS_test  src/VINS-Fusion/config/test_data/stereo_imu_gps_config.yaml   /home/hltt3838/kitti_data/2011_10_03_drive_0042_sync/

单目

rosrun   vins   camera_IMU_GPS_test  src/VINS-Fusion/config/test_data/mono_imu_gps_config.yaml   /home/hltt3838/kitti_data/2011_10_03_drive_0042_sync/

 

打开第四个终端

进入工作区间内,分别输入:

cd  GPS_Stereo_Ins/catkin_ws

source  devel/setup.bash  

rosrun global_fusion global_fusion_node

 

 

情况一、单目+IMU

个人感觉效果还是可以的!我们再来看看 双目+IMU

 

情况二、双目+IMU

评价:一个字,惨不忍睹!

我有点想不明白了,单目+IMU 跑kitti数据可以,为什么吗 双目+IMU 就不行?

你要是说是程序有问题,但是 程序跑RUROC的双目+IMU时,也是好的呀!

而且跑kitti数据的双目程序也是好的呀,这样一排除,个人感觉还是出在了外参上面,如果发现我错误的小伙伴别忘了留言提醒我!

对了,我看了相关数据介绍的论文了,好像GPS/IMU是与相机不同步,可是不同步为什么 单目+IMU效果是好的?

要么都不同步呗, 这个我无法理解!注意咱的思路,后面验证我是对的!

上面问题已经解决了!过程很艰辛,但是我想说的是我的思路很好,不然估计还是解决不了!处理的方式上面已经给了!

修正后,双目+IMU+GPS 的效果如下:

 完美!

 

 

对应的程序如下:

添加的主程序: camera_IMU_GPS_test.cpp

/*
说明:
本程序尝试:相机+IMU+GPS, 其实VINS-fusion 已经具备这个条件了,主要在于结合;
本次程序是rosNodeTest.cpp 和 KITTIGPS.cpp 的结合;
通过读取不同的配置文件,可以决定是单目相机还是双目相机;
先尝试用Kitti的数据,在尝试用自己采集的数据!
*/
#include <iomanip>
#include <fstream>
#include <iostream>
#include <stdio.h>
#include <map>
#include <thread>
#include <mutex>
#include <cmath>
#include <string>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <ros/ros.h>
#include <sensor_msgs/NavSatFix.h>
#include "estimator/estimator.h"
#include "utility/visualization.h"
#include "camera_imu_gps.h"
 

using namespace std;
using namespace Eigen;

Estimator estimator;
ros::Publisher pubGPS;

std::mutex m_buf;
 

void readIMUdata(const std::string &line, IMU_MSG &imuObs);
void readGPSdata(const std::string &line, GPS_MSG &gpsObs);



void feature_callback(const sensor_msgs::PointCloudConstPtr &feature_msg)
{
    map<int, vector<pair<int, Eigen::Matrix<double, 7, 1>>>> featureFrame;
    for (unsigned int i = 0; i < feature_msg->points.size(); i++)
    {
        int feature_id = feature_msg->channels[0].values[i];
        int camera_id = feature_msg->channels[1].values[i];
        double x = feature_msg->points[i].x;
        double y = feature_msg->points[i].y;
        double z = feature_msg->points[i].z;
        double p_u = feature_msg->channels[2].values[i];
        double p_v = feature_msg->channels[3].values[i];
        double velocity_x = feature_msg->channels[4].values[i];
        double velocity_y = feature_msg->channels[5].values[i];
        if(feature_msg->channels.size() > 5)
        {
            double gx = feature_msg->channels[6].values[i];
            double gy = feature_msg->channels[7].values[i];
            double gz = feature_msg->channels[8].values[i];
            pts_gt[feature_id] = Eigen::Vector3d(gx, gy, gz);
            //printf("receive pts gt %d %f %f %f\n", feature_id, gx, gy, gz);
        }
        ROS_ASSERT(z == 1);
        Eigen::Matrix<double, 7, 1> xyz_uv_velocity;
        xyz_uv_velocity << x, y, z, p_u, p_v, velocity_x, velocity_y;
        featureFrame[feature_id].emplace_back(camera_id,  xyz_uv_velocity);
    }
    double t = feature_msg->header.stamp.toSec();
    estimator.inputFeature(t, featureFrame);
    return;
}


void restart_callback(const std_msgs::BoolConstPtr &restart_msg)
{
    if (restart_msg->data == true)
    {
        ROS_WARN("restart the estimator!");
        estimator.clearState();
        estimator.setParameter();
    }
    return;
}

void imu_switch_callback(const std_msgs::BoolConstPtr &switch_msg)
{
    if (switch_msg->data == true)
    {
        ROS_WARN("use IMU!");
        estimator.changeSensorType(1, STEREO);
    }
    else
    {
        ROS_WARN("disable IMU!");
        estimator.changeSensorType(0, STEREO);
    }
    return;
}

void cam_switch_callback(const std_msgs::BoolConstPtr &switch_msg)
{
    if (switch_msg->data == true)
    {
        ROS_WARN("use stereo!");
        estimator.changeSensorType(USE_IMU, 1);
    }
    else
    {
        ROS_WARN("use mono camera (left)!");
        estimator.changeSensorType(USE_IMU, 0);
    }
    return;
}



int main(int argc, char** argv)
{
  	ros::init(argc, argv, "vins_estimator");
	ros::NodeHandle n("~");
	ros::console::set_logger_level(ROSCONSOLE_DEFAULT_NAME, ros::console::levels::Info);

	pubGPS = n.advertise<sensor_msgs::NavSatFix>("/gps", 1000);
    ros::Subscriber sub_feature = n.subscribe("/feature_tracker/feature", 2000, feature_callback);
    ros::Subscriber sub_restart = n.subscribe("/vins_restart", 100, restart_callback);
    ros::Subscriber sub_imu_switch = n.subscribe("/vins_imu_switch", 100, imu_switch_callback);
    ros::Subscriber sub_cam_switch = n.subscribe("/vins_cam_switch", 100, cam_switch_callback);

    
	if(argc != 3)
	{
		printf("please intput: rosrun vins camera_IMU_GPS_test [config file] [data folder] \n"
			   "for example: rosrun vins camera_IMU_GPS_test "
			   "~/catkin_ws/src/VINS-Fusion/config/test_data/stereo_imu_gps_config.yaml "
			   "/home/hltt3838/kitti_data/2011_10_03_drive_0042_sync/ \n");
		return 1;
	}
    
	string config_file = argv[1];//stereo_imu_gps_config.yaml
	printf("config_file: %s\n", argv[1]);
    
	string sequence = argv[2];   //---/home/hltt3838/kitti_data/2011_10_03_drive_0042_sync/
	printf("read sequence: %s\n", argv[2]);
	string dataPath = sequence + "/";  
    
    //1、读取imu的 txt 文件,一行一行读取
    double init_imu_time;
    IMU_MSG imuObs;
    std::string line_imu;
    std::string imuPath = dataPath + "imu_data_100hz/imu.txt";
    std::ifstream  csv_IMUfile(imuPath); 
    if (!csv_IMUfile)
    {
	    printf("cannot find imu Path \n" );
	    return 0;          
	}
    std::getline(csv_IMUfile, line_imu); //header, 获得的第一个IMU数据
    
    readIMUdata(line_imu, imuObs);
    init_imu_time = imuObs.time;
    printf("init_imu_time: %10.5f \n", init_imu_time);
	
  
    //2、读取GPS的 txt 文件,一行一行读取
    double init_gps_time;
    GPS_MSG gpsObs;
    std::string line_gps;
    std::string gpsPath = dataPath + "gps_data_10hz/gps.txt";
    std::ifstream  csv_GPSfile(gpsPath);
    if (!csv_GPSfile)
    {
	    printf("cannot find gps Path \n" );
	    return 0;          
	}
    std::getline(csv_GPSfile, line_gps); //header, 获得的第一个gps数据
    readGPSdata(line_gps, gpsObs);
    init_gps_time = gpsObs.time;
    printf("init_gps_time: %10.5f \n", init_gps_time); 
    
    
    //3、读取图像时间,整个文件读取,存放到 imageTimeList,两个相机对齐了,没有进行判断
    //Cam0
    double init_cam_time;
	FILE* file;
	file = std::fopen((dataPath + "image_00/timestamps.txt").c_str() , "r");
	if(file == NULL)
    {
	    printf("cannot find file: %simage_00/timestamps.txt \n", dataPath.c_str());
	    ROS_BREAK();
	    return 0;          
	}
	vector<double> image0TimeList;
	int year, month, day;
	int hour, minute;
	double second;
	while (fscanf(file, "%d-%d-%d %d:%d:%lf", &year, &month, &day, &hour, &minute, &second) != EOF)
	{
	    image0TimeList.push_back(hour * 60 * 60 + minute * 60 + second);
	}
	std::fclose(file);
    
    
    init_cam_time = image0TimeList[0]; 
    printf("init_cam_time: %10.5f \n", init_cam_time);
    
    double baseTime;
    baseTime = min(init_imu_time,init_gps_time,init_cam_time);
    printf("baseTime: %10.5f \n", baseTime);
    
    //4、读取配置参数和发布主题
    readParameters(config_file);
	estimator.setParameter();
	registerPub(n);
    
    //5、VIO的结果输出保存文件
    FILE* outFile;
	outFile = fopen((OUTPUT_FOLDER + "/vio.txt").c_str(),"w");
	if(outFile == NULL)
    printf("Output vio path dosen't exist: %s\n", OUTPUT_FOLDER.c_str());
	string leftImagePath, rightImagePath;
	cv::Mat imLeft, imRight;
    
    
    //6、遍历整个图像
    for (size_t i = 0; i < image0TimeList.size(); i++)
	{	
        int num_imu = 0;
		if(ros::ok())
		{
			printf("process image %d\n", (int)i);
			stringstream ss;
			ss << setfill('0') << setw(10) << i;
			leftImagePath = dataPath + "image_00/data/" + ss.str() + ".png";
			rightImagePath = dataPath + "image_01/data/" + ss.str() + ".png";
            
			printf("%s\n", leftImagePath.c_str() );
			printf("%s\n", rightImagePath.c_str() );
            double imgTime = 0; 
           
            imLeft  = cv::imread(leftImagePath, CV_LOAD_IMAGE_GRAYSCALE );
            imRight = cv::imread(rightImagePath, CV_LOAD_IMAGE_GRAYSCALE );
            
            imgTime = image0TimeList[i] - baseTime;
            printf("image time: %10.5f \n", imgTime);
           
            
			//读取GPS信息
            std::getline(csv_GPSfile, line_gps);  
            readGPSdata(line_gps, gpsObs);
            
            sensor_msgs::NavSatFix gps_position;
			gps_position.header.frame_id = "NED";
			gps_position.header.stamp = ros::Time(imgTime);
			gps_position.latitude  = gpsObs.position[0];
			gps_position.longitude = gpsObs.position[1];
			gps_position.altitude  = gpsObs.position[2];
			gps_position.position_covariance[0] = gpsObs.pos_accuracy;
    
			pubGPS.publish(gps_position);
            
   //---------------------加上IMU-------------------------//       
            //读取imu的信息
            while (std::getline(csv_IMUfile, line_imu))
            {
               num_imu++;
               printf("process imu %d\n",num_imu);
               readIMUdata(line_imu, imuObs);
               double imuTime = imuObs.time - baseTime;
               printf("imu time: %10.5f \n", imuTime);
                
               Vector3d acc = imuObs.acc;
               Vector3d gyr = imuObs.gyr;
                   
               estimator.inputIMU(imuTime, acc, gyr);
                   
               if (imuTime >= imgTime) //简单的时间同步,IMU的时间戳是不大于图像的
                {
                    break;
                }
            }
     //---------------------加上IMU-------------------------//     
     
            if(STEREO)//双目为1,否则为0
            {
              estimator.inputImage(imgTime,imLeft, imRight);
            }
            else
              estimator.inputImage(imgTime, imLeft);
 
        
			Eigen::Matrix<double, 4, 4> pose;
			estimator.getPoseInWorldFrame(pose);
			if(outFile != NULL)
				fprintf (outFile, "%f %f %f %f %f %f %f %f %f %f %f %f \n",pose(0,0), pose(0,1), pose(0,2),pose(0,3),
																	       pose(1,0), pose(1,1), pose(1,2),pose(1,3),
																	       pose(2,0), pose(2,1), pose(2,2),pose(2,3));
			
			 //cv::imshow("leftImage", imLeft);
			 //cv::imshow("rightImage", imRight);
			 //cv::waitKey(2);
		}
		else
			break;
	}
	
	if(outFile != NULL)
		fclose (outFile);
    
    
    return 0;
}   






void readIMUdata(const std::string &line, IMU_MSG &imuObs)
{
    std::stringstream  lineStream(line);
    std::string        dataRecord[7];
    std::getline(lineStream, dataRecord[0], ' ');//这里的数据间是空格, 如果有逗号,用','
    std::getline(lineStream, dataRecord[1], ' ');
    std::getline(lineStream, dataRecord[2], ' ');
    std::getline(lineStream, dataRecord[3], ' ');
    std::getline(lineStream, dataRecord[4], ' ');
    std::getline(lineStream, dataRecord[5], ' ');
    std::getline(lineStream, dataRecord[6], ' ');
    
    imuObs.time = std::stod(dataRecord[0]); //时间:s;
             
    imuObs.acc[0] = std::stod(dataRecord[1]);
    imuObs.acc[1] = std::stod(dataRecord[2]);
    imuObs.acc[2] = std::stod(dataRecord[3]);

    imuObs.gyr[0] = std::stod(dataRecord[4]);
    imuObs.gyr[1] = std::stod(dataRecord[5]);
    imuObs.gyr[2] = std::stod(dataRecord[6]);
}


void readGPSdata(const std::string &line, GPS_MSG &gpsObs)
{
    std::stringstream  lineStream(line);
    std::string        dataRecord[7];
    std::getline(lineStream, dataRecord[0], ' ');//这里的数据间是空格, 如果有逗号,用','
    std::getline(lineStream, dataRecord[1], ' ');
    std::getline(lineStream, dataRecord[2], ' ');
    std::getline(lineStream, dataRecord[3], ' ');
    std::getline(lineStream, dataRecord[4], ' ');
 
    gpsObs.time = std::stod(dataRecord[0]); //时间:s;
             
    gpsObs.position[0] = std::stod(dataRecord[1]);
    gpsObs.position[1] = std::stod(dataRecord[2]);
    gpsObs.position[2] = std::stod(dataRecord[3]);

    gpsObs.pos_accuracy = std::stod(dataRecord[4]);
   
}

 

camera_imu_gps.h

#pragma once
#include<chrono>
#include <Eigen/Dense>
#include <opencv2/opencv.hpp>


struct IMU_MSG
{
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW
    double time;
    Eigen::Vector3d acc;
    Eigen::Vector3d gyr;
    IMU_MSG &operator =(const IMU_MSG &other)
    {
        time = other.time;
        acc = other.acc;
        gyr = other.gyr;
        return *this;
    }
};


struct GPS_MSG
{
    EIGEN_MAKE_ALIGNED_OPERATOR_NEW
    double time;
    Eigen::Vector3d position;
    double pos_accuracy;
    GPS_MSG &operator =(const GPS_MSG &other)
    {
        time         = other.time;
        position     = other.position;
        pos_accuracy = other.pos_accuracy;
        return *this;
    }
};

 
double min(double x,double y,double z )
{
    return x < y ? (x < z ? x : z) : (y < z ? y : z);
}

 

CMakeLists.txt   中加如下两行

#######################-----自己加的程序-----#############################
add_executable(change_data src/change_data.cpp)
target_link_libraries(change_data vins_lib) 


add_executable(camera_IMU_GPS_test src/camera_IMU_GPS_test.cpp)
target_link_libraries(camera_IMU_GPS_test vins_lib) 

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

VINS - Fusion GPS/INS/视觉 融合 0、 Kitti数据测试 的相关文章

  • 传递给 onLocationChanged 的​​位置对象是否为 null?

    我有一个在我的应用程序中实现 LocationListener 的活动 并且我的 onLocationChanged 方法直到最近为止一直运行良好 由于某种原因 传递给该方法的 Location 对象为 null 我的问题是 为什么它是空的
  • 使用 JavaScript 获取 GPS 位置

    我正在使用平板电脑 正在处理 html 应用程序 希望在不使用任何网络连接的情况下获取 GPS 位置 请建议我简单的方法 使用JS你可以这样得到它
  • 将纬度和经度转换为十进制值

    我的 GPS 信息以以下形式呈现 北纬 36 57 9 西经 110 4 21 我可以使用Chris Veness 的 javascript 函数 http www movable type co uk scripts latlong ht
  • 从 .Net v4.0 程序集链接到 .Net v2.0 程序集似乎也链接(和别名)mscorlib v2.0。为什么?

    我有一个 Net 程序集 它导入与 v2 0 运行时链接的程序集 我遇到的问题是 当我尝试在程序集上运行一些测试时 Fusion 尝试加载依赖程序集的错误版本 查看程序集清单后 我明白了原因 错误的版本FSharp Core已连接 在我的构
  • 计算小距离用什么公式

    Hy 我需要计算 2 个 GPS 点之间的距离 我读了这个问题计算地理邻近度的公式 https stackoverflow com questions 2096385 formulas to calculate geo proximity但
  • 同时有多个位置提供商

    我的定位系统有一些问题 我有一个实现位置侦听器的服务 我希望尽可能使用网络获得最佳位置 如果网络不够准确 精度大于 300mt 则使用 GPS 问题是这样的 我每 5 分钟需要一次位置信息 如果可能的话准确 否则不准确 我从一个开始 Loc
  • GPS 转换 - 像素坐标到 GPS 坐标

    我正在根据视频数据进行一些运动跟踪 使用一些视频处理 即转换为自上而下的视图 我获得了移动路径 我现在需要将路径的像素坐标 x y 转换为世界坐标 纬度 经度 我在图像中有四个参考点及其相关的纬度和经度点 纬度 经度 gt 像素坐标 51
  • 如何在用户行走时跟踪 GPS 坐标,来自 iOS 平台的 xamarin.forms

    我刚刚经历过这个link http developer xamarin com recipes ios multitasking track significant location change 当用户使用 xamarin forms 应
  • Android 将阿拉伯数字转换为英文数字

    我从 GPS 收到以下错误 Fatal Exception java lang NumberFormatException Invalid double 现在 这是我通过 Fabric 从用户处收到的错误 它看起来像阿拉伯语 所以我猜只有当
  • GPS定位无服务

    我是一名新开发人员 有一个简单的问题 我已经四处搜索 但尚未找到明确的答案 简而言之 我正在开发一个需要能够使用 GPS 的应用程序 然而 诀窍是我想使用 GPS 来获取手机的位置 即使它们没有运营商服务 话虽如此 我有两个问题 是否可以通
  • 设置模拟位置时 GPS 提供商未知错误?

    我正在尝试设置我的模拟位置 但是 我收到以下错误 提供商 gps 未知 并且不确定出了什么问题 我已经获得了在manifest xml 中声明的所有权限以及所有参数 模拟定位法 Initiates the method to set the
  • GMSPolyline 非常大的内存峰值

    在允许用户在各种不同类型的地图上显示我们称之为轨迹的复杂位置点列表的 GPS 应用程序中 每个轨迹可以包含 2k 到 10k 个位置点 当轨迹在非 Google 地图类型上呈现时 它们会被大量剪切 修剪和路径简化 这是为了降低内存使用量并提
  • 使用 LocationManager 时,为什么打开 Wifi 但未连接有助于网络定位?

    这可能是偏离主题的 如果是这样 我道歉 并很高兴接受关闭标志 但我在弄清楚为什么 WIFI 打开但未连接到任何接入点 在我的 Android 设备上 时遇到问题 它vastly提高网络提供商使用时的准确性LocationManager 如果
  • 在设备所有者应用程序中启用 GPS

    根据API文档 https developer android com reference android app admin DevicePolicyManager html setSecureSetting android conten
  • 移动应用程序在后台时的 GPS 位置(使用 ionicframework)

    我需要实现一个应用程序来存储用户从 A 移动到 B 时的旅程 路径 现在 我知道 ionicframework 可以使用 GPS 但是当我的应用程序转到后台时会发生什么 我的应用程序如何继续存储用户位置 这可能吗 有没有我可以使用的插件 请
  • Android:计算两个位置之间距离的最佳方法

    我在这个主题上做了一些研究 但有很多观点并没有给出一个清晰的图像 我的问题是这样的 我正在为 Android 开发一个基于 GPS 的应用程序 在其中我想实时了解 Android LocationManager 指定的当前位置与其他位置之间
  • 如何知道jar文件是否已经在运行?

    经过谷歌研究后 我找到了很好的答案 例如 1 using jps or jps l让 jars 在 JVM 下运行 这个答案可以 但是如果用户根本没有安装java并且我使用例如 bat文件和带有java JRE的文件夹运行我的jar 另外
  • 使用 iPhone 版 gmap 中的经纬度计算两个地点之间的距离 [重复]

    这个问题在这里已经有答案了 可能的重复 GPS 坐标 以度为单位 来计算距离 https stackoverflow com questions 6994101 gps coordinates in degrees to calculate
  • 检测wifi是否启用(无论是否连接)

    对于 GPS 跟踪应用程序来说 在打开 WIFI 的情况下记录位置信号会导致数据非常不精确或存在间隙 在开始跟踪之前 我已使用可达性查询来检测 wifi 是否可用 问题是 如果进行该查询时 wifi 已启用但未连接到网络 则表明无法通过 w
  • 如何找到特定路线上两点之间的距离?

    我正在为我的大学开发一个 Android 应用程序 可以帮助学生跟踪大学巴士的当前位置 并为他们提供巴士到达他们的预计时间 截至目前 我获取了公交车的当前位置 通过公交车上的设备 和学生的位置 我陷入了必须找到两个 GPS 坐标之间的距离的

随机推荐

  • m基于模糊控制与遗传优化的自适应ADRC双闭环控制策略matlab仿真

    目录 1 算法仿真效果 2 MATLAB核心程序 3 算法涉及理论知识概要 4 完整MATLAB 1 算法仿真效果 matlab2013b仿真结果如下 xff1a 遗传优化的优化迭代过程仿真图 xff1a 这个是我们采用的优化算法的有过过程
  • VINS-mono在Ubuntu20.04上从零开始安装运行和环境配置(尝试)

    最近尝试在Ubuntu 20 04上安装运行港科大的VINS mono算法 详细记录一下安装过程以及遇到的问题 先记录一下结果 ROS opencv Eigen Ceres以及VINS mono都编译并安装成功了 但是用euroc数据集跑V
  • 数据结构-C++实现

    之前的2周一直在学数据结构 xff0c 头都大了 我是之前对数据结构一点认识都没有 xff0c 我是直接看书怼的 xff0c 我看的是 大话数据结构 xff0c 前面的讲解还不错 xff0c 到了树 图后 xff0c 就有点看不懂了 xff
  • 几款好看的css表格

    表格一 xff1a 代码 xff1a html代码段 xff1a 是用vs写的 表头 lt th gt 那是从数据库读取的数据段 lt td gt 那是我为测试效果加的代码 xff0c 大家可以自行更改 lt h1 gt 待处理订单 lt
  • 非线性优化 (曲线拟合) 问题:高斯牛顿、g2o 方法总结

    其实还有一个Ceres库可以进行优化 xff0c 但是之前的博客已经具体分析了 xff0c 所以这里就对其余两个进行了介绍 xff0c 相关的内容是SLAM14讲里面的知识 一 理论部分 我们先用一个简单的例子来说明如何求解最小二乘问题 x
  • VINS-Fusion : EUROC、TUM、KITTI测试成功 + 程序进程详细梳理

    完成以下任务的前提是系统安装了必备的库 xff0c 比如cere Eigen3 3等 提前下载好了数据集EUROC xff0c KITTI等 一 相关论文 T Qin J Pan S Cao and S Shen A General Opt
  • ROS 简单理解

    https download csdn net download qq 30022867 11120759 utm medium 61 distribute pc relevant download none task download b
  • ROS系列:七、熟练使用rviz

    7 熟练使用rviz xff08 1 xff09 rviz整体界面 rviz是ROS自带的图形化工具 xff0c 可以很方便的让用户通过图形界面开发调试ROS 操作界面也十分简洁 xff0c 如图29 xff0c 界面主要分为上侧菜单区 左
  • ROS系列:八、图像消息和OpenCV图像之间进行转换-cv_bridge

    cv bridge是在ROS图像消息和OpenCV图像之间进行转换的一个功能包 一 xff09 在ROS图像和OpenCV图像之间转换 xff08 C 43 43 xff09 xff11 xff0e Concepts xff08 概念 xf
  • ROS系列:九、rosbag使用

    文章目录 解析rosbag中的 bag文件 xff0c 得到 jpg图片数据和 pcd点云数据 https blog csdn net weixin 40000540 article details 83859694 1 rosbag写入文
  • 三、松灵课堂 | SCOUT的仿真使用

    仿真环境的介绍 Gazebo Gazebo是一款3D动态模拟器 xff0c 能够在复杂的室内和室外环境中准确有效地模拟机器人群 与游戏引擎提供高保真度的视觉模拟类似 xff0c Gazebo提供高保真度的物理模拟 xff0c 其提供一整套传
  • 1PPS:秒脉冲 相关概念理解

    时钟模块上的GPS接收机负责接收GPS天线传输的射频信号 xff0c 然后进行变频解调等信号处理 xff0c 向基站提供1pps信号 xff0c 进行同步 GPS使用原子钟 xff08 原子钟 xff0c 是一种计时装置 xff0c 精度可
  • opencv GStreamer-CRITICAL

    使用openvino中的opencv跑之前的代码 碰到个问题 span class token punctuation span myProg span class token operator span span class token
  • 激光雷达 LOAM 论文 解析

    注意 xff1a 本人实验室买的是Velodyne VLP 16激光雷和 LOAM 论文中作者用的不一样 xff0c 在介绍论文之前先介绍一下激光雷达的工作原路 xff0c 这样更容易理解激光雷达的工作过程 xff0c 其实物图如下图1所示
  • VINS 细节系列 - 坐标转换关系

    前言 在学习VINS Mono过程中 xff0c 对初始化代码中的坐标转换关系做出了一些推导 xff0c 特意写了博客记录一下 xff0c 主要记录大体的变量转换关系 相机和IMU的外参 若需要VINS标定旋转外参 xff0c 则进入以下代
  • VINS 细节系列 - 光束法平差法(BA)Ceres 求解

    一 理论部分 学习过VINS的小伙伴应该知道 xff0c 在SFM xff08 structure from motion xff09 的计算中 光束法平差法 BA xff08 Bundle Adjustment xff09 的重要性 xf
  • Ceres 详解(一) Problem类

    引言 Ceres 是由Google开发的开源C 43 43 通用非线性优化库 xff08 项目主页 xff09 xff0c 与g2o并列为目前视觉SLAM中应用最广泛的优化算法库 xff08 VINS Mono中的大部分优化工作均基于Cer
  • VINS - Fusion GPS/VIO 融合 一、数据读取

    目录 一 相关概念 二 程序解读 2 1 参数读取 解析 xff1a 2 2 获取图像时间信息 解析 xff1a 2 3 获取图像时间信息 解析 xff1a 2 4 定义VIO结果输出路径和读取图像信息 解析 xff1a 2 5 读取GPS
  • VINS - Fusion GPS/VIO 融合 二、数据融合

    https zhuanlan zhihu com p 75492883 一 简介 源代码 xff1a VINS Fusion 数据集 xff1a KITTI 数据 程序入口 xff1a globalOptNode cpp 二 程序解读 2
  • VINS - Fusion GPS/INS/视觉 融合 0、 Kitti数据测试

    放两张图片 至于为什么 xff1f 后面会解释 xff01 程序下载 xff1a https github com HKUST Aerial Robotics VINS Fusion 数据集制作 xff1a https zhuanlan z