VINS-mono 解析 新特征

2023-05-16

在17.12.29,VINS更新了代码加入了新的特征,包括map merge( 地图合并), pose-graph reuse(位姿图重利用), online temporal calibration function(在线时间校准函数), and support rolling shutter camera(支持卷帘快门相机)。

论文见https://arxiv.org/abs/1803.01549

map merge( 地图合并)

map merge 最初是MapLab中出现的特征,VINS 将这个特征功能合并过来,并使用CLA数据集来测试。除了介绍页给出的ETH CLA 数据集下载外,MapLab的数据介绍详见Github网址。

在播放完MH_01_easy.bag后,继续播放MH_02_easy.bag和MH_03_medium.bag, RVIZ可以得到如下合并的地图。左侧中间添加了回环检测匹配的图像。

图中有三个颜色不同的轨迹线绿色的是MH_01, 红色轨迹是MH_02, 蓝色轨迹是MH_03。MH_02和MH_01轨迹位置相近,因此回环检测比较多。这些地图序列拼接,初始点的拼接输出

[ WARN] [1520921503.762849522]: restart the estimator!
[ WARN] [1520921503.777266208]: image discontinue! detect a new sequence!
new sequence
sequence cnt 2 
    // detect unstable camera stream
    if (img_msg->header.stamp.toSec() - last_image_time > 1.0 || img_msg->header.stamp.toSec() < last_image_time)
    {
        ROS_WARN("image discontinue! reset the feature tracker!");
        first_image_flag = true; 
        last_image_time = 0;
        pub_count = 1;
        std_msgs::Bool restart_flag;
        restart_flag.data = true;
        pub_restart.publish(restart_flag);
        return;
    }
void image_callback(const sensor_msgs::ImageConstPtr &image_msg)
{
    //ROS_INFO("image_callback!");
    if(!LOOP_CLOSURE)
        return;
    m_buf.lock();
    image_buf.push(image_msg);
    m_buf.unlock();
    //printf(" image time %f \n", image_msg->header.stamp.toSec());

    // detect unstable camera stream
    if (last_image_time == -1)
        last_image_time = image_msg->header.stamp.toSec();
    else if (image_msg->header.stamp.toSec() - last_image_time > 1.0 || image_msg->header.stamp.toSec() < last_image_time)
    {
        ROS_WARN("image discontinue! detect a new sequence!");
        new_sequence();
    }
    last_image_time = image_msg->header.stamp.toSec();
}

从代码上看,新的序列就是检测新到达的图像时间是否已经超过上一帧图像时间1s,如果时间太长则重新初始化,重新构建地图。

2 pose-graph reuse(位姿图重利用)

首先修改对应的config.yaml,设置路径 pose_graph_save_path 后,播放需要建图的bag文件,播放完成在vins_estimator控制台键入‘s’,当前包的所有位姿图会存储下来


代码

void PoseGraph::savePoseGraph()
{
    m_keyframelist.lock();
    TicToc tmp_t;
    FILE *pFile;
    printf("pose graph path: %s\n",POSE_GRAPH_SAVE_PATH.c_str());
    printf("pose graph saving... \n");
    string file_path = POSE_GRAPH_SAVE_PATH + "pose_graph.txt";
    pFile = fopen (file_path.c_str(),"w");
    //fprintf(pFile, "index time_stamp Tx Ty Tz Qw Qx Qy Qz loop_index loop_info\n");
    list<KeyFrame*>::iterator it;
    for (it = keyframelist.begin(); it != keyframelist.end(); it++)
    {
        std::string image_path, descriptor_path, brief_path, keypoints_path;
        if (DEBUG_IMAGE)
        {
            image_path = POSE_GRAPH_SAVE_PATH + to_string((*it)->index) + "_image.png";
            imwrite(image_path.c_str(), (*it)->image);
        }
        Quaterniond VIO_tmp_Q{(*it)->vio_R_w_i};
        Quaterniond PG_tmp_Q{(*it)->R_w_i};
        Vector3d VIO_tmp_T = (*it)->vio_T_w_i;
        Vector3d PG_tmp_T = (*it)->T_w_i;

        fprintf (pFile, " %d %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %d %f %f %f %f %f %f %f %f %d\n",(*it)->index, (*it)->time_stamp, 
                                    VIO_tmp_T.x(), VIO_tmp_T.y(), VIO_tmp_T.z(), 
                                    PG_tmp_T.x(), PG_tmp_T.y(), PG_tmp_T.z(), 
                                    VIO_tmp_Q.w(), VIO_tmp_Q.x(), VIO_tmp_Q.y(), VIO_tmp_Q.z(), 
                                    PG_tmp_Q.w(), PG_tmp_Q.x(), PG_tmp_Q.y(), PG_tmp_Q.z(), 
                                    (*it)->loop_index, 
                                    (*it)->loop_info(0), (*it)->loop_info(1), (*it)->loop_info(2), (*it)->loop_info(3),
                                    (*it)->loop_info(4), (*it)->loop_info(5), (*it)->loop_info(6), (*it)->loop_info(7),
                                    (int)(*it)->keypoints.size());

        // write keypoints, brief_descriptors   vector<cv::KeyPoint> keypoints vector<BRIEF::bitset> brief_descriptors;
        assert((*it)->keypoints.size() == (*it)->brief_descriptors.size());
        brief_path = POSE_GRAPH_SAVE_PATH + to_string((*it)->index) + "_briefdes.dat";
        std::ofstream brief_file(brief_path, std::ios::binary);
        keypoints_path = POSE_GRAPH_SAVE_PATH + to_string((*it)->index) + "_keypoints.txt";
        FILE *keypoints_file;
        keypoints_file = fopen(keypoints_path.c_str(), "w");
        for (int i = 0; i < (int)(*it)->keypoints.size(); i++)
        {
            brief_file << (*it)->brief_descriptors[i] << endl;
            fprintf(keypoints_file, "%f %f %f %f\n", (*it)->keypoints[i].pt.x, (*it)->keypoints[i].pt.y, 
                                                     (*it)->keypoints_norm[i].pt.x, (*it)->keypoints_norm[i].pt.y);
        }
        brief_file.close();
        fclose(keypoints_file);
    }
    fclose(pFile);

    printf("save pose graph time: %f s\n", tmp_t.toc() / 1000);
    m_keyframelist.unlock();
}

从代码中可见,存储的是关键帧、关键帧上的特征点,特征点的brief描述子(二进制dat文件)。

config.yaml中的load_previous_pose_graph修改为1,然后重新运行vins_estimator,系统则会加载 result/pose_graph下的位姿图, 新的序列会和之前的位姿图相重合。

Terminal输出的加载信息

load pose graph
lode pose graph from: /home/.../src/vins_mono/result/pose_graph/pose_graph.txt 
pose graph loading...
load pose graph time: 33.301555 s
load pose graph finish

pose_graph.txt 每一行读取

    int index;
    double time_stamp;
    double VIO_Tx, VIO_Ty, VIO_Tz;
    double PG_Tx, PG_Ty, PG_Tz;
    double VIO_Qw, VIO_Qx, VIO_Qy, VIO_Qz;
    double PG_Qw, PG_Qx, PG_Qy, PG_Qz;
    double loop_info_0, loop_info_1, loop_info_2, loop_info_3;
    double loop_info_4, loop_info_5, loop_info_6, loop_info_7;
    int loop_index;
    int keypoints_num;

加载的位姿图是黄色轨迹线


在重新播放数据包之后与地图对准的结果如下图


save_image选项设置为0最好,节省内存。

3 online temporal calibration function(在线时间校准)

这项功能的目的是因为大多数VI传感器两部分不是时间同步的,所以将estimate_td设置为1可以在线估计摄像头和惯性单元之间的时间差。

这项参数td在Estimator::optimization()里放在图像残差函数中进行非线性优化。

            if (ESTIMATE_TD)
            {
                    ProjectionTdFactor *f_td = new ProjectionTdFactor(pts_i, pts_j, it_per_id.feature_per_frame[0].velocity, it_per_frame.velocity, it_per_id.feature_per_frame[0].cur_td, it_per_frame.cur_td, it_per_id.feature_per_frame[0].uv.y(), it_per_frame.uv.y());
                    problem.AddResidualBlock(f_td, loss_function, para_Pose[imu_i], para_Pose[imu_j], para_Ex_Pose[0], para_Feature[feature_index], para_Td[0]);
                    /*
                    double **para = new double *[5];
                    para[0] = para_Pose[imu_i];
                    para[1] = para_Pose[imu_j];
                    para[2] = para_Ex_Pose[0];
                    para[3] = para_Feature[feature_index];
                    para[4] = para_Td[0];
                    f_td->check(para);
                    */
            }
            else
            {
                ProjectionFactor *f = new ProjectionFactor(pts_i, pts_j);
                problem.AddResidualBlock(f, loss_function, para_Pose[imu_i], para_Pose[imu_j], para_Ex_Pose[0], para_Feature[feature_index]);
            }

将特征点的速度和这个时间偏差考虑到视觉残差函数即重投影误差中

    pts_i_td = pts_i - (td - td_i + TR / ROW * row_i) * velocity_i;
    pts_j_td = pts_j - (td - td_j + TR / ROW * row_j) * velocity_j;

4 supporting rolling shutter (卷帘相机)

大部分单反相机都是卷帘相机,其拍摄视频采用卷帘快门方式。这里将rolling_shutter设置为1,同样需要从传感器表得到读取rolling_shutter_tr的值。不要使用网络摄像头webcam,不适合用。


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

VINS-mono 解析 新特征 的相关文章

  • 如何在 Mono 中运行 MVC3 或更新的应用程序

    默认 ASP NET MVC 3 应用程序是使用 Microsoft Web Developer Express 2010 创建的 应用程序发布到文件系统并复制到安装了 mono 2 10 8 Apache 和 mod mono 的 Deb
  • .NET 开源后,MS 运行时可以在 Linux 和 Mac 上使用吗? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我读过很多有关 MS 开源 NET 的新闻 例如http blogs msdn com b dotnet archive 2014 1
  • 如何为 Debian/Ubuntu 打包 Mono 应用程序

    是否有任何用于为 Debian Ubuntu 打包 Mono 应用程序的指南或工具 比如将应用程序附带的程序集放在哪里等 Mono 有一些关于打包的一般准则 但这些准则并非特定于 Debian Ubuntu 它们的做法可能有所不同 http
  • mkbundle 和 GTK#

    我正在尝试使用 mkbundle 以便我可以分发 GTK 应用程序 而无需用户安装 NET Mono 或 GTK 我已经成功捆绑了一个使用 winforms 的应用程序 但由于某种原因 当我对 GTK 应用程序执行相同操作时 它无法工作 这
  • 平台调用 F# 回调函数

    我在 Raspberry Pi 2 ARM 7 和单声道 上使用 F 我目前正在尝试使用用 C 编写的 WiringPi 库 我已经成功地使用 P Invoke 来使用一些函数 现在我尝试使用中断 参见http wiringpi com r
  • 在 Mac 上开发 .Net 应用程序? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我是 Net 开发人员 开始使用 Mac OS 我在这个系统上唯一怀念的是 VISUAL STUDIO 我不想使用两个系统 你认为如何开发 Ne
  • Directory.GetCurrentDirectory() 在 Linux 上不起作用?

    因此 我尝试创建一个需要读取名为 scripts 的子文件夹中的脚本的应用程序 我的代码有问题 string script Console ReadLine string path Directory GetCurrentDirectory
  • Mono.Math.BigInteger 由于其保护级别而无法访问

    我正在使用 ideone 编写 C 程序 这是我第一次使用 Mono 我正在尝试使用 BigInteger 类 Mono Math BigInteger 但我不断收到错误 下面是我的代码 这是怎么回事 我该如何解决 谢谢 using Sys
  • 服务堆栈上的 SSL

    Mono 上的服务堆栈是否支持 SSL 我只能访问 Mac 我在这里找到的说明要求您使用 Windows 工具创建 pvk 文件 http joshua perina com geo post using ssl https with mo
  • 使用 android ndk 独立工具链构建 mono (android ndk r8e)

    我正在尝试使用 android ndk 版本 r8e 中的 ndk 独立工具链构建 mono 但我无法完成构建 我像这样设置我的独立环境 export SYSROOT home jeremybell Desktop android ndk
  • .NET csc 和 Mono mcs 的兼容性

    我知道 NET 和 Mono 是二进制兼容的 但给定一组源代码 csc 和 mcs 会生成完全相同的 100 相同的二进制 CLI 可执行文件吗 人们能够判断可执行文件是用 csc 还是 mcs 编译的吗 很多东西在规范中没有完全定义 或者
  • nginx/mono 2.8 上的 ASP.Net MVC 2

    我正在尝试在 Linux 环境上设置 ASP Net MVC 2 应用程序 我在 VirtualBox 上安装了 Ubuntu 10 10 然后从源安装了 Mono 2 8 之后我安装了 nginx 并按照建议进行配置here http w
  • 命名互斥体的 Mono 替代方案

    在 Windows NET 上 命名的互斥体可用于同步多个进程 不幸的是 Mono 在 Linux 上不太支持这一点 他们的发行说明 http www mono project com Release Notes Mono 2 8 Shar
  • 如何在android上使用xamarin表单执行脚本

    我正在尝试在 Android Mono 上使用 Xamarin Forms 运行 C 脚本 当我运行脚本时 我收到错误 System IO FileNotFoundException 找不到文件 mscorlib dll 这是我试图执行的代
  • nuget.exe 安装不更新packages.config(或.csproj)?

    在尝试在 Linux mono 上运行 nuget 构建工作流程时 我注意到一件奇怪的事情 在 Linux 上 我无法使用 nuget Visual Studio 插件或 Powershell 控制台 但我有 nuget exe 命令行实用
  • CSharpRepl emacs 集成?

    我碰巧知道莫诺CSharpRepl http www mono project com CsharpRepl 是否有 emacs csharp 模式使用它在一个窗口中运行 REPL 并像 python 模式一样在另一个窗口中编译 运行 C
  • 在控制器构造函数中访问 GUI 组件时出现 NullReferenceException

    在 Mono 中 我有一个带有控制器的简单 NSWindow 我放置了一个 NSSplitView 和一个 NSButton 如果我尝试从构造函数中访问 NSSplitView 或Initialize 方法我得到一个 nullReferen
  • Mac 上使用 Mono 的 mkbundle:找不到“mono/metadata/mono-config.h”文件

    我正在尝试使用 Mono 创建 Mac 捆绑包 当我执行时 mkbundle file exe deps o FILE 我在编译过程中得到这个 fatal error mono metadata mono config h file not
  • GTK+ (GTKSharp) 在 Windows 中性能不佳

    在我的跨平台 Mono C 项目中 我使用 GTK 作为 UI 然而我注意到的一件事是 在我的 Archlinux 上网本上 性能非常快 因此诸如鼠标悬停和重新绘制小部件等事件都非常快 与双核CPU上的Windows 7 相比 性能确实很弱
  • MonoMac 窗口关闭时没有错误

    我刚刚开始在 Xamarin Studio 中使用 MonoMac 并且遇到了最奇怪的问题 我有一个带有 NSButton 和 NSTextField 的窗口 至此 我已经删除了按钮上的事件处理程序 因此它不会执行任何操作 除了在单击它时突

随机推荐

  • 关于结构体成员变量用 . 还是 ->

    之前一直认为引用结构体成员 xff0c 指针的话用 gt xff0c 成员变量的话用 但是一直都没去深究过 xff0c 今天遇到一个复杂的 xff0c 决心去了解一下 typedef struct IPC ISP CFG DATA IPC
  • 顺序表的建立 基本输入输出

    输入数据的个数n 输入n个数 然后输出 input 5 1 2 3 4 5 output 1 2 3 4 5 以下是代码 xff1a include lt stdio h gt include lt stdlib h gt define l
  • 离散题目18--求传递闭包

    离散题目18 Time Limit 1000MS Memory Limit 65536KB Submit Statistic Problem Description 给出一个集合A和A上的关系R xff0c 求关系R的传递闭包 例如 xff
  • 基于MSP430红外循迹小车

    2021 个人公众号 高瞻猿瞩 xff0c 会在其中发布一些有趣或是实用的编程内容 xff0c 大部分都是些轻松加愉快的内容 xff0c 欢迎大家前来看看 xff01 可在公众号恢复关键词 430 51 树莓派 循迹小车测试视频 可以获取相
  • 基于51单片机的简单方波发生器

    一个按键可以调整频率的简易方波信号发生器 xff0c 当频率超出范围时LED亮 xff0c 频率范围是100 1000hz include lt reg52 h gt sbit PWMOUT 61 P1 0 sbit LED1 61 P2
  • matlab绘制垂线(x轴或y轴)

    使用line函数就可以绘制垂线 1 绘制垂直于x轴的垂线 line xvalue xvalue y1 y2 xff1b 比如绘制x 61 5 y取值为 0 10 xff1b line 5 5 0 10 2 绘制垂直于y轴的垂线 line x
  • ubuntu解决中文乱码

    1 查看当前系统使用的字符编码 locale LANG 61 en US LANGUAGE 61 en US LC CTYPE 61 34 en US 34 LC NUMERIC 61 34 en US 34 LC TIME 61 34 e
  • ROS 在工作空间中创建python程序

    ROS 在工作空间中创建python程序 基于ros xff0c 在工作空间catkin ws中创建pkg和python程序 xff0c 并进行编译使其可以用rosrun进行运行 xff0c 参考 xff1a 参考 默认前面已经创建了cat
  • 关于AD15铺铜的注意事项

    1 在铺好信号线和电源线后再考虑是否在铺地之前先手动连接地线 因为在铺地时有一个间距问题 xff0c 如果有限地线的间距太小 xff0c 那么在铺地时就会不成功 xff0c 导致墨迹个地没有被接进去 还有就是要考虑敷铜时的间距 xff0c
  • AD15 建立铺铜间距规则

    系统默认的普通间距就是系统的clearance 10mil xff0c 可是默认普通出来的话间距太小了 xff0c 于是乎可以建立一个普通规则 xff0c 但是要注意你所建立的铺铜规则优先级永远在默认优先级之前 xff08 比如你的poly
  • AD15 修改铺铜(去除自己不想要的铺铜区域)

    1 点击place gt polygon pour cutout 2 出现光标 xff0c 然后把你想要去除的那个区域选中 xff0c 如图一所示 xff0c 单击右键退出选择模式 3 双击没有被选中的区域 xff0c 软件提示重新铺铜 x
  • 串口缓冲区管理分析

    一 概述 xff1a 串口使用时一般包含两个缓冲区 xff0c 即发送缓冲区和接收缓冲区 发送数据时 xff0c 先将数据存在发送缓冲区 xff0c 然后通过串口发送 xff1b 接收数据时 xff0c 先将接收的数据存在接收缓冲区 xff
  • JLINK给STM32下载的两种模式--jtag & sw连线及配置

    jtag线就不说了 xff0c 将jlink的Vref GND TMS TCK分别接至SW接口 对于STM32F103RCT6来说 xff1a TMS PA12 xff0c TCK PA14 关于KEIL MDK中的设置如下图所示就可以了
  • 3.3V过压保护电路

    好久没写了 xff0c 今天就写一些工作中用到的一个电路 3 3V过压保护电路 通常一个电路中给单片机等对电压信息敏感的器件供电时都会小心翼翼 xff0c 严防前级降压电路出问题 xff0c 我就碰到过12V转5V的1117奔溃记过加在ST
  • eagle使用注意点

    使用eagle也有快一年时间了 xff0c 刚开始很不习惯 xff0c 后来习惯了也还可以 xff0c 这里我举出几个设计中经常出错的地方 xff1a 1 PCB翻转问题 xff1a 在翻转PCB文件时一定要打开torigin borigi
  • 自制pixhawk电脑不识别com口

    在原版pix上面进行改版很方便 xff0c 可以去除很多不必要的电路 笔者将电源管理芯片去除 xff0c 5V来源于变压器输出或者是连接电脑时的USB供电 xff0c 并将它们并联起来 xff0c 但是板子做回来焊接后发现问题如下 xff1
  • eagle pcb v8.2 便捷性大大提升

    eagle pcb在被Autodesk收购之前是7 x版本 xff0c 但是却有一些一直被吐槽的东西 xff0c 说实话这些东西确实增加了布线难度 xff0c 增加了布板时间 xff1a 1 real time DRC xff1a 在7 x
  • Ubuntu firefox 显示在运行无法打开,如何在终端关闭进程

    用top命令找不到firfox的进程 xff0c 查看某个用户运行的进程 xff1a ps u username grep eclipse 查看用户名为 xff1a username 的用户是否运行了eclipse 查看用户当前运行fire
  • 【万字详解】cJSON解析

    目录 1 通过README文件 xff0c 初步了解cJSON xff1a 1 1 头文件的开头和结尾 xff1a 1 2 头文件关于cJSON类型的宏定义 1 3 头文件中的extern 2 阅读并且分析cJSON源码 2 1 结构体st
  • VINS-mono 解析 新特征

    在17 12 29 xff0c VINS更新了代码加入了新的特征 xff0c 包括map merge 地图合并 pose graph reuse 位姿图重利用 online temporal calibration function 在线时