萌新学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融合 的相关文章

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

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

    我正在使用平板电脑 正在处理 html 应用程序 希望在不使用任何网络连接的情况下获取 GPS 位置 请建议我简单的方法 使用JS你可以这样得到它
  • 在 Iphone SDK 中显示 GPS 可用性和准确性

    如何编程以在 iPhone 中显示 GPS 可用性和准确度级别 并且它必须擦除标签中先前的纬度 经度信息 iOS sdk 中有一个类叫做 CLLocationManager 浏览 XCode 中的文档或查找一些示例 http mobileo
  • 谷歌地图可以根据小时分钟秒绘制点吗

    我正在尝试绘制以时分秒秒格式提供给我的 GPS 数据 GLatLng 会采用这种形式吗 还是我需要先转换它 很难在互联网上找到与此相关的任何内容 如果可以采用这种格式 我们将不胜感激 据我所知它不接受这种格式 但转换它真的很容易 只需计算一
  • 通过js获取WebView中的位置

    我正在尝试创建 WebView 它将通过 js 获取 GPS 本地化 但是当我单击应该显示本地化的按钮时 在android 4 1 1 模拟器 中 错误代码2 无法启动地理定位服务 在 android 4 1 2 phone 中什么也没有发
  • 位置侦听器从服务工作,但不是 IntentService

    我有一个应用程序 我试图定期获取用户位置并将其发送到服务器 我有一项服务附加到AlarmManager每分钟执行一次 用于测试 该服务正确找到用户位置并注销 GPS 坐标 一旦出现 GPS 锁定 我就会取消位置请求并停止服务 当我请求位置更
  • Android GPS 路由系统

    我正在开发一个 Android 应用程序 它可以定位用户 假设用户在路上 并且该应用程序将为用户创建最短路线 以便能够到达用户选择的目的地 定位用户不是问题 因为这里有一个 API http www vogella com articles
  • GPS坐标:一个点周围1平方公里

    我希望有人能给我提供一个方程来计算给定点周围 1 公里的平方 X 从 a aaa 到 b bbb Y 从 c ccc 到 c ccc 例如lat 53 38292839 and lon 6 1843984 我还需要围绕一个点 2 公里 5
  • 在带有校准点的地图上将经度和纬度转换为 X Y

    如果我有一张尺寸为 sizeX sizeY 的 jpeg 地图 以及地图上的一些校准点 X Y 经度 纬度 使用给定的经度 纬度对计算地图中相应 XY 点的算法是什么 这对我有用 没有那么多废话 int x int MAP WIDTH 36
  • Android GPS 的准确度如何? [关闭]

    Closed 这个问题是无关 help closed questions 目前不接受答案 我好像在某处读过Android的GPS精度约为10厘米 任何人都可以验证或更正这个吗 原因是我正在尝试开发的应用程序会跟踪用户访问过的位置 这将极大地
  • 寻找另一部智能手机的笛卡尔坐标?

    考虑到我有两部智能手机 A 和 B 如果我拿着智能手机 A 有没有办法确定 B 相对于我自己的位置 所以如果我们有这张图片的情况 它会告诉我 B 位于位置 2 1 利用 WiFi 信号强度来获取位置等创造性方法更受欢迎 我还可以确定两部手机
  • Android 中如何在不使用 getLastKnownLocation 方法的情况下获取当前的纬度和经度?

    我正在尝试获取current手机的位置 为此我使用GPS追踪器教程 http www androidhive info 2012 07 android gps location manager tutorial 问题总是使用该方法getLa
  • 如何将timestamp_t转换为实际时间?

    我见过很多使用 time t 的例子 但 timestamp t 让我感到困惑 我正在做一个作业 我们需要打印出 GPS 数据 并且 GPS 设备返回一个类型 timestamp t 来表示它的时间戳和纪元时间 我尝试过使用 gmtime
  • 移动应用程序在后台时的 GPS 位置(使用 ionicframework)

    我需要实现一个应用程序来存储用户从 A 移动到 B 时的旅程 路径 现在 我知道 ionicframework 可以使用 GPS 但是当我的应用程序转到后台时会发生什么 我的应用程序如何继续存储用户位置 这可能吗 有没有我可以使用的插件 请
  • 如何将 GPS 数据从 Android 发送到网站?

    我是 Android 和 Web 服务开发新手 目前我正在开发Android程序 该程序将发送经度和纬度信息到asp net网站 以显示位置更改网站地图 问题是 如何将此数据发送到网站 最佳实践 对合适框架的任何建议 从Android应用程
  • 使用 Google 电子表格中的脚本从手机获取我的当前位置

    有没有办法使用 Google Apps 脚本从手机的 GPS 数据中获取我的当前位置 纬度和经度 最好是十进制形式 另外 是否可以打开和关闭 GPS 或者至少检测它是否打开或关闭 这是我尝试做的 我带着电动助力车去一些地方 在每个地方我都会
  • iPhone 网络应用程序可以获取 GPS 位置吗?

    有没有一种简单的方法来设计一个网站来促进iphone用户提供gps网站坐标 我想知道表单字段是否有命名约定 例如 让用户以自动方式输入 我正在考虑建立一个基于位置的网站 并希望为 iPhone 和其他移动用户 量身定制 我意识到 iPhon
  • 关闭应用程序后如何调试

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

    考虑点 P1 60 N 20 E 0 和 P2 60 N 22 E 0 地球表面 当形状为 P1 和 P2 时 点 P1 和 P2 之间的最短距离是多少 地球是使用 WGS 84 椭球体建模的吗 不幸的是 文森蒂算法对于某些输入无法收敛 地
  • 如何创建在 React-Native 中检测自动位置的地图

    我已经在react native中创建了地图 参考https github com lelandrichardson react native maps https github com lelandrichardson react nat

随机推荐