萌新学VINS-Fusion(三)------双目和GPS融合

2023-05-16

转载自:https://blog.csdn.net/weixin_41843971/article/details/86748719

萌新学VINS-Fusion(三)------双目和GPS融合

slam萌新 2019-02-02 13:55:26 6057 收藏 26

文章标签: 视觉slam 计算机视觉 无人驾驶

版权

虽然要过年了,而且每天还要在家里小店打工,但是网红之路不能停对吧,这篇博客写关于VINS-Fusion和GPS的融合。其实我之前改出过一个加了GPS的VIO,并且也开源了,之前没有找到合适的数据集,自己造的数据,效果一般,近期我准备跑一下看看效果

最近我在之前代码基础上做了修改,还在测试效果,之后可能会开源,希望大家关注、点赞、收藏,素质三连。

我的开源代码地址
https://github.com/grn213331/remove_ros_VINS-position-constraint

Vins-Fusion源码:https://github.com/HKUST-Aerial-Robotics/VINS-Fusion

主函数文件

GPS融合的程序入口在KITTIGPSTest.cpp文件中,数据为KITTI数据集
数据集为 http://www.cvlibs.net/datasets/kitti/raw_data.php
以 [2011_10_03_drive_0027_synced]为例
https://s3.eu-central-1.amazonaws.com/avg-kitti/raw_data/2011_10_03_drive_0027/2011_10_03_drive_0027_sync.zip

main函数与之前的main函数相似,都要进行ros节点初始化,然后读取参数,区别在于该数据集的图像和gps数据均为文件读取方式,将gps数据封装进ros 的sensor_msgs::NavSatFix 数据类型里,以gps为topic播发出去,而双目图像则直接放到estimator进行vio,将vio得到的结果再播发出去,方便后面的订阅和与GPS的融合。

global_fusion

所有的与gps的融合在global_fusion文件夹中,该部分的文件入口是一个rosnode文件globalOptNode.cpp,主函数很短,如下

int main(int argc, char **argv)
{
    ros::init(argc, argv, "globalEstimator");
    ros::NodeHandle n("~");

    global_path = &globalEstimator.global_path;

    ros::Subscriber sub_GPS = n.subscribe("/gps", 100, GPS_callback);
    ros::Subscriber sub_vio = n.subscribe("/vins_estimator/odometry", 100, vio_callback);
    pub_global_path = n.advertise<nav_msgs::Path>("global_path", 100);
    pub_global_odometry = n.advertise<nav_msgs::Odometry>("global_odometry", 100);
    pub_car = n.advertise<visualization_msgs::MarkerArray>("car_model", 1000);
    ros::spin();
    return 0;
}

代码很简单,订阅topic(/gps)在GPS_callback回调函数中接收并处理gps数据,订阅topic(/vins_estimator/odometry)在vio_callback回调函数中接收并处理vio的定位数据。
并且生成了三个发布器,用于将结果展示在rviz上。

GlobalOptimization类

所有的融合算法都是在GlobalOptimization类中,对应的文件为globalOpt.h和globalOpt.cpp,并且ceres优化器的相关定义在Factors.h中。
GlobalOptimization类中的函数和变量如下

class GlobalOptimization
{
public:
	GlobalOptimization();
	~GlobalOptimization();
	void inputGPS(double t, double latitude, double longitude, double altitude, double posAccuracy);
	void inputOdom(double t, Eigen::Vector3d OdomP, Eigen::Quaterniond OdomQ);
	void getGlobalOdom(Eigen::Vector3d &odomP, Eigen::Quaterniond &odomQ);
	nav_msgs::Path global_path;

private:
	void GPS2XYZ(double latitude, double longitude, double altitude, double* xyz);
	void optimize();
	void updateGlobalPath();

	// format t, tx,ty,tz,qw,qx,qy,qz
	map<double, vector<double>> localPoseMap;
	map<double, vector<double>> globalPoseMap;
	map<double, vector<double>> GPSPositionMap;
	bool initGPS;
	bool newGPS;
	GeographicLib::LocalCartesian geoConverter;
	std::mutex mPoseMap;
	Eigen::Matrix4d WGPS_T_WVIO;
	Eigen::Vector3d lastP;
	Eigen::Quaterniond lastQ;
	std::thread threadOpt;

};

inputGPS和inputOdom两个函数将回调函数中的gps和vio数据导入,getGlobalOdom为获取融合后位姿函数。
GPS2XYZ函数是将GPS的经纬高坐标转换成当前的坐标系的函数,updateGlobalPath顾名思义更新全局位姿函数。
融合算法的实现主要就是在optimize函数中,接下来进行详细介绍。

注意其中几个变量localPoseMap中保存着vio的位姿,GPSPositionMap中保存着gps数据,globalPoseMap中保存着优化后的全局位姿。

融合算法(optimize函数)

void GlobalOptimization::optimize()
{
    while(true)
    {
        if(newGPS)
        {
            newGPS = false;
            printf("global optimization\n");
            TicToc globalOptimizationTime;

            ceres::Problem problem;
            ceres::Solver::Options options;
            options.linear_solver_type = ceres::SPARSE_NORMAL_CHOLESKY;
            //options.minimizer_progress_to_stdout = true;
            //options.max_solver_time_in_seconds = SOLVER_TIME * 3;
            options.max_num_iterations = 5;
            ceres::Solver::Summary summary;
            ceres::LossFunction *loss_function;
            loss_function = new ceres::HuberLoss(1.0);
            ceres::LocalParameterization* local_parameterization = new ceres::QuaternionParameterization();

            //add param
            mPoseMap.lock();
            int length = localPoseMap.size();
            // w^t_i   w^q_i
            double t_array[length][3];
            double q_array[length][4];
            map<double, vector<double>>::iterator iter;
            iter = globalPoseMap.begin();
            for (int i = 0; i < length; i++, iter++)
            {
                t_array[i][0] = iter->second[0];
                t_array[i][1] = iter->second[1];
                t_array[i][2] = iter->second[2];
                q_array[i][0] = iter->second[3];
                q_array[i][1] = iter->second[4];
                q_array[i][2] = iter->second[5];
                q_array[i][3] = iter->second[6];
                problem.AddParameterBlock(q_array[i], 4, local_parameterization);
                problem.AddParameterBlock(t_array[i], 3);
            }

            map<double, vector<double>>::iterator iterVIO, iterVIONext, iterGPS;
            int i = 0;
            for (iterVIO = localPoseMap.begin(); iterVIO != localPoseMap.end(); iterVIO++, i++)
            {
                //vio factor
                iterVIONext = iterVIO;
                iterVIONext++;
                if(iterVIONext != localPoseMap.end())
                {
                    Eigen::Matrix4d wTi = Eigen::Matrix4d::Identity();
                    Eigen::Matrix4d wTj = Eigen::Matrix4d::Identity();
                    wTi.block<3, 3>(0, 0) = Eigen::Quaterniond(iterVIO->second[3], iterVIO->second[4], 
                                                               iterVIO->second[5], iterVIO->second[6]).toRotationMatrix();
                    wTi.block<3, 1>(0, 3) = Eigen::Vector3d(iterVIO->second[0], iterVIO->second[1], iterVIO->second[2]);
                    wTj.block<3, 3>(0, 0) = Eigen::Quaterniond(iterVIONext->second[3], iterVIONext->second[4], 
                                                               iterVIONext->second[5], iterVIONext->second[6]).toRotationMatrix();
                    wTj.block<3, 1>(0, 3) = Eigen::Vector3d(iterVIONext->second[0], iterVIONext->second[1], iterVIONext->second[2]);
                    Eigen::Matrix4d iTj = wTi.inverse() * wTj;
                    Eigen::Quaterniond iQj;
                    iQj = iTj.block<3, 3>(0, 0);
                    Eigen::Vector3d iPj = iTj.block<3, 1>(0, 3);

                    ceres::CostFunction* vio_function = RelativeRTError::Create(iPj.x(), iPj.y(), iPj.z(),
                                                                                iQj.w(), iQj.x(), iQj.y(), iQj.z(),
                                                                                0.1, 0.01);
                    problem.AddResidualBlock(vio_function, NULL, q_array[i], t_array[i], q_array[i+1], t_array[i+1]);
                }
                //gps factor
                double t = iterVIO->first;
                iterGPS = GPSPositionMap.find(t);
                if (iterGPS != GPSPositionMap.end())
                {
                    ceres::CostFunction* gps_function = TError::Create(iterGPS->second[0], iterGPS->second[1], 
                                                                       iterGPS->second[2], iterGPS->second[3]);
                    //printf("inverse weight %f \n", iterGPS->second[3]);
                    problem.AddResidualBlock(gps_function, loss_function, t_array[i]);

                }

            }
            //mPoseMap.unlock();
            ceres::Solve(options, &problem, &summary);
            //std::cout << summary.BriefReport() << "\n";

            // update global pose
            //mPoseMap.lock();
            iter = globalPoseMap.begin();
            for (int i = 0; i < length; i++, iter++)
            {
            	vector<double> globalPose{t_array[i][0], t_array[i][1], t_array[i][2],
            							  q_array[i][0], q_array[i][1], q_array[i][2], q_array[i][3]};
            	iter->second = globalPose;
            	if(i == length - 1)
            	{
            	    Eigen::Matrix4d WVIO_T_body = Eigen::Matrix4d::Identity(); 
            	    Eigen::Matrix4d WGPS_T_body = Eigen::Matrix4d::Identity();
            	    double t = iter->first;
            	    WVIO_T_body.block<3, 3>(0, 0) = Eigen::Quaterniond(localPoseMap[t][3], localPoseMap[t][4], 
            	                                                       localPoseMap[t][5], localPoseMap[t][6]).toRotationMatrix();
            	    WVIO_T_body.block<3, 1>(0, 3) = Eigen::Vector3d(localPoseMap[t][0], localPoseMap[t][1], localPoseMap[t][2]);
            	    WGPS_T_body.block<3, 3>(0, 0) = Eigen::Quaterniond(globalPose[3], globalPose[4], 
            	                                                        globalPose[5], globalPose[6]).toRotationMatrix();
            	    WGPS_T_body.block<3, 1>(0, 3) = Eigen::Vector3d(globalPose[0], globalPose[1], globalPose[2]);
            	    WGPS_T_WVIO = WGPS_T_body * WVIO_T_body.inverse();
            	}
            }
            updateGlobalPath();
            //printf("global time %f \n", globalOptimizationTime.toc());
            mPoseMap.unlock();
        }
        std::chrono::milliseconds dura(2000);
        std::this_thread::sleep_for(dura);
    }
	return;
}

首先呢,判断是否有gps数据,整体的算法就是在ceres架构下的优化算法。
所以总体的步骤就是ceres优化的步骤,首先添加优化参数块(AddParameterBlock函数),参数为globalPoseMap中的6维位姿(代码中旋转用四元数表示,所以共7维)。
之后添加CostFunction,通过构建factor重载operator方法实现(具体实现需要学习ceres库)。该部分有两个factor,一个是位姿图优化,另一个则是利用gps进行位置约束。
将factor添加后,进行ceres求解,更新此时gps和vio间的坐标系转换参数,之后再利用updateGlobalPath函数更新位姿。

总而言之,VF的和GPS的融合也是一个优化框架下的松组合,利用GPS的位置约束,使得位姿图优化可以不依赖回环,这是一大优势。

谢谢大家,比心(有理解不到位或错误,欢迎指正,虚心学习)

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

萌新学VINS-Fusion(三)------双目和GPS融合 的相关文章

  • 如何停止位置管理器?

    不知道为什么 但有时 LocationManager 在关闭应用程序后仍然工作 我在一个 Activity 的 onCreate Methode 中调用 startGPS 只有一个 让我称之为 StartActivity protected
  • 如何在android中离线获取纬度和经度?

    我想在 WiFi 和 Gps 关闭时获取当前位置 纬度和经度 可以从移动 SIM 网络获取纬度和经度 我在谷歌上搜索了更多 但没有得到满意的答案 从我昨天的经验来看question https stackoverflow com q 220
  • GPS定位无服务

    我是一名新开发人员 有一个简单的问题 我已经四处搜索 但尚未找到明确的答案 简而言之 我正在开发一个需要能够使用 GPS 的应用程序 然而 诀窍是我想使用 GPS 来获取手机的位置 即使它们没有运营商服务 话虽如此 我有两个问题 是否可以通
  • 在带有校准点的地图上将经度和纬度转换为 X Y

    如果我有一张尺寸为 sizeX sizeY 的 jpeg 地图 以及地图上的一些校准点 X Y 经度 纬度 使用给定的经度 纬度对计算地图中相应 XY 点的算法是什么 这对我有用 没有那么多废话 int x int MAP WIDTH 36
  • GPS 坐标(以度为单位)来计算距离

    在iPhone上 我以十进制度数获取用户的位置 例如 纬度39 470920和经度 0 373192 也就是A点 我需要用另一个 GPS 坐标 同样以十进制表示 B 点创建一条线 然后 计算从 A 到 B 的线与另一个点 C 之间的距离 垂
  • 如何通过 GPRS 向 GPS 追踪器(TK103、GT02、GT06、TK102 等)发送命令

    这已经被问过这里https stackoverflow com questions 25460743 gps tracker tk103 how to send message through server https stackoverf
  • 如何使用卡尔曼滤波器预测测量之间的 GPS 位置

    我研究了OpenCV卡尔曼滤波器的实现 并做了一些基本的鼠标指针模拟并了解了基础 我似乎错过了在我的应用程序中使用它的一些关键点 并希望这里有人可以提供一个小例子 使用具有速度和位置的简单模型 KF statePre at
  • 根据 GPS 坐标计算平均速度的最佳实践

    我这里有一个可以给我 GPS 坐标的设备 我可以定义的时间间隔 我想用它来计算驾驶或驾车旅行时的平均速度 实际上 我使用了正交公式来计算两点之间的距离 然后将其除以给定的时间间隔 通过我遵循的实施这个词 http de wikipedia
  • Android GPS 的准确度如何? [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我好像在某处读过Android的GPS精度约为10厘米 任何人都可以验证或更正这个吗 原因是我正在尝试开发的应用程序会跟踪用户访问过的位置 这将极大地
  • Android 中如何在不使用 getLastKnownLocation 方法的情况下获取当前的纬度和经度?

    我正在尝试获取current手机的位置 为此我使用GPS追踪器教程 http www androidhive info 2012 07 android gps location manager tutorial 问题总是使用该方法getLa
  • 在不改变我的位置的情况下获取当前位置的经度和纬度

    我可以找到当前位置的纬度和经度 但是这些数据在更改我的当前位置之前不会显示 我想在不更改我的位置的情况下获取当前位置的经度和纬度 package com example gps import android app Activity imp
  • C# - LINQ - GPS 纬度和经度的最短距离

    我有数据库 其中有带有 GPS 坐标的一流酒店 我想获得距离我选择的坐标最近的地方 我认为它应该看起来像这样 我在这里找到了很多示例代码 就像这样 var coord new GeoCoordinate latitude longitude
  • 关闭应用程序后如何调试

    我正在尝试重现问题 这需要在特定位置关闭并重新打开我的应用程序 这是我的问题 1 如何查看我的日志 使用NSLog命令 当我的 iPhone 未连接到 XCode 时 2 是否可以将iPhone模拟器的特定位置 例如市中心 设置为默认位置
  • 在尝试使用 GPS 之前如何检查 GPS 是否已启用

    我有以下代码 但效果不好 因为有时 GPS 需要很长时间 我该如何执行以下操作 检查GPS是否启用 如果启用了 GPS 请使用 GPS 否则请使用网络提供商 如果 GPS 时间超过 30 秒 请使用网络 我可以使用时间或 Thread sl
  • python:查找围绕某个 GPS 位置的圆的 GPS 坐标的优雅方法

    我有一组以十进制表示的 GPS 坐标 并且我正在寻找一种方法来查找每个位置周围半径可变的圆中的坐标 这是一个例子 http green and energy com downloads test circle html我需要什么 这是一个圆
  • iOS:应用程序在安装应用程序时不会征求用户的许可。每次都获取 kCLAuthorizationStatusNotDetermined - Objective-c 和 Swift

    我正在尝试在我的 iOS 应用程序中获取用户位置 我首先在我的项目中包含了核心定位框架 然后单击按钮 我将调用核心位置 api 如下所示 当我尝试在设备中安装它时 核心位置从不询问用户许可 当我尝试获取单击按钮时的位置时 我得到 kCLAu
  • 是否可以自定义区域形状?核心位置

    例如 至少我想要一个正方形 矩形 道路的形状作为我的区域 不它不是 根据文档 目前唯一的区域类是 CLCircularRegion 显然是圆形 和 CLBeaconRegion 基于与 iBeacon 的接近度 未来苹果可能会添加对自定义形
  • 检查用户设备的 GPS 是否开启

    我正在使用 jQuery Mobile 和 PHP 开发一个应用程序 我没有使用 Phonegap 或其他框架 我需要找到用户的geolocation 如果用户设备的 GPS 关闭 那么我无法获取位置 现在我需要查找用户设备的 GPS 是否
  • 如何在android中以编程方式启用位置访问?

    我正在开发与地图相关的 Android 应用程序 如果位置服务未启用显示对话框提示 我需要在客户端开发中检查位置访问是否启用 如何在android中以编程方式启用 位置访问 使用下面的代码进行检查 如果禁用 将生成对话框 public vo
  • 以编程方式激活 GPS

    我的应用程序需要打开 GPS 有什么方法可以检查 GPS 当前是否启用 如果没有 那么如何启用 我使用的是安卓2 3 Android 不允许你这样做 您能做的最好的事情就是检查 GPS 是否已启用 如果未启用 请要求用户激活它 您可以在此处

随机推荐