VINS-Mono代码解读——启动文件launch与参数配置文件yaml介绍

2023-05-16

前言

一般我们通过以下命令运行VINS-Mono跑MH_01数据集。

roslaunch vins_estimator euroc.launch 
roslaunch vins_estimator vins_rviz.launch
rosbag play YOUR_PATH_TO_DATASET/MH_01_easy.bag 

那么,VINS的启动和运行需要提供哪些参数,若是想用自己的传感器运行VINS,又需要修改哪些参数?本文将以euroc.launch和euroc_config.yaml为例对VINS中的启动文件launch和参数配置文件yaml进行详细介绍,并讨论自己在实验中调参的感受。欢迎大家一起讨论。

启动文件launch

VINS在正常工作时一般存在三个节点:“/fature_tracker”、“/vins_estimator”、“/pose_graph”,而VINS的启动文件launch在文件夹VINS-Mono/vins_estimator/launch中,启动时直接读取euroc.launch同时打开三个节点。

首先介绍一下ROS中的launch文件——通过XML文件实现多节点的配置和启动(可自动启动ROS Master)。以及会用到的几个关键字:

  • <launch>:launch文件中的根元素采用标签定义
  • <node>:启动节点
    比如:<node pkg=“package-name” type=“executable-name” name=“node-name”>
  • <param>:设置ROS系统运行的参数,存储在参数服务器中
    比如:<param name=“output_farme” value=“odem”/>
  • <rosparam>:加载参数文件中的多个参数
    比如:<rosparam file=“params.yaml” command=“load” ns=“params”/>
  • <arg>:launch文件内部的局部变量,仅限于launch文件使用
    比如<arg name=“arg-name” default=“arg-value”/>
    参数调用:<param name=“foo” value="$(arg arg-name)"/>

euroc.launch文件的内容很少:
1、设置局部变量"config_path",表示euroc_config.yaml的具体地址;

<arg name="config_path" default = "$(find feature_tracker)/../config/euroc/euroc_config.yaml" />
	  <arg name="vins_path" default = "$(find feature_tracker)/../config/../" />

设置局部变量"vins_path",在parameters.cpp中使用鱼眼相机mask中用到:

std::string VINS_FOLDER_PATH = readParam<std::string>(n, "vins_folder");
if (FISHEYE == 1)
        FISHEYE_MASK = VINS_FOLDER_PATH + "config/fisheye_mask.jpg";

2、启动"feature_tracker"节点,在该节点中需要读取参数文件,地址为config_file,即config_path;

	<node name="feature_tracker" pkg="feature_tracker" type="feature_tracker" output="log">
        <param name="config_file" type="string" value="$(arg config_path)" />
        <param name="vins_folder" type="string" value="$(arg vins_path)" />
    </node>

3、启动"vins_estimator"节点,内容同上;

	<node name="vins_estimator" pkg="vins_estimator" type="vins_estimator" output="screen">
       <param name="config_file" type="string" value="$(arg config_path)" />
       <param name="vins_folder" type="string" value="$(arg vins_path)" />
    </node>

4、启动"pose_graph"节点,除了参数配置文件的地址外还设置了4个参数:

    <node name="pose_graph" pkg="pose_graph" type="pose_graph" output="screen">
        <param name="config_file" type="string" value="$(arg config_path)" />
        <param name="visualization_shift_x" type="int" value="0" />
        <param name="visualization_shift_y" type="int" value="0" />
        <param name="skip_cnt" type="int" value="0" />
        <param name="skip_dis" type="double" value="0" />
    </node>

visualization_shift_x和visualization_shift_y表示在进行位姿图优化后,对得到的位姿在x坐标和y坐标的偏移量(一般都设为0);

geometry_msgs::PoseStamped pose_stamped;
pose_stamped.header.stamp = ros::Time(cur_kf->time_stamp);
pose_stamped.header.frame_id = "world";
pose_stamped.pose.position.x = P.x() + VISUALIZATION_SHIFT_X;
pose_stamped.pose.position.y = P.y() + VISUALIZATION_SHIFT_Y;
pose_stamped.pose.position.z = P.z();

skip_cnt在pose_graph_node的process()中,表示每隔skip_cnt个图像帧才进行一次处理;
skip_dis也在pose_graph_node的process()中,目的是将距上一帧的时间间隔超过SKIP_DIS的图像创建为位姿图中的关键帧。

至此launch文件的内容就结束了。


参数配置文件yaml

从launch启动文件中可以看到,每个节点都会读取参数,例如在feature_traker_node.cpp中的main()通过以下函数实现参数读取:

void readParameters(ros::NodeHandle &n)
{
    std::string config_file;
    config_file = readParam<std::string>(n, "config_file");
    cv::FileStorage fsSettings(config_file, cv::FileStorage::READ);
    if(!fsSettings.isOpened())
    {
        std::cerr << "ERROR: Wrong path to settings" << std::endl;
    }
    //。。。
}

下面将具体介绍euroc_config.yaml每个参数的具体意义。

1、通用参数

1)接收IMU和图像的topic,其中image_topic在节点/fature_tracker中被订阅,以进行角点的光流跟踪;imu_topic在节点/vins_estimator中被订阅,以进行IMU预积分。

2)output_path为输出文件的地址,输出以下内容:VINS的运行轨迹"/vins_result_no_loop.csv"与"/vins_result_loop.csv",相机与IMU的外参估计 “/extrinsic_parameter.csv”(如果estimate_extrinsic不为0即需要对外参进行估计的话)。注意如果该文件夹不存在则不输出

imu_topic: "/imu0"
image_topic: "/cam0/image_raw"
output_path: "/home/tony-ws1/output/"

2、相机的基础信息

包括:
相机模型:PINHOLE(针孔相机)、KANNALA_BRANDT(一种常用的鱼眼相机模型)等。
图像的宽和高、相机的畸变系数(如果是鱼眼相机还要求mu、mv、u0、v0)、相机的内参。
相机的内参数据建议进行标定以获得较准确结果,以降低之后调参的难度。

model_type: PINHOLE
camera_name: camera
image_width: 752
image_height: 480
distortion_parameters:
   k1: -2.917e-01
   k2: 8.228e-02
   p1: 5.333e-05
   p2: -1.578e-04
projection_parameters:
   fx: 4.616e+02
   fy: 4.603e+02
   cx: 3.630e+02
   cy: 2.481e+02

3、imu和相机之间的外参

这里需要注意的是其旋转矩阵ric、平移向量tic都是表示从camera坐标系到IMU坐标系的变换

estimate_extrinsic:=0表示这外参已经是准确的了,之后不需要优化;=1表示外参只是一个估计值,后续还需要将其作为初始值放入非线性优化中;=2表示不知道外参,需要进行标定,在estimator.cpp的函数processImage()中调用了CalibrationExRotation()进行外参标定。

个人在实验时最直观的感受是:这个外参对VINS输出的精度和鲁棒性具有非常大的影响!尤其是初始化阶段,如果外参不准会对IMU的预积分和图像的SFM对齐以得到的尺度有很大偏差。强烈建议进行手眼标定,具体可以使用Kalibr工具进行IMU和相机的离线外参标定。

# Extrinsic parameter between IMU and Camera.
estimate_extrinsic: 0   # 0  Have an accurate extrinsic parameters. We will trust the following imu^R_cam, imu^T_cam, don't change it.
                        # 1  Have an initial guess about extrinsic parameters. We will optimize around your initial guess.
                        # 2  Don't know anything about extrinsic parameters. You don't need to give R,T. We will try to calibrate it. Do some rotation movement at beginning.                        
#If you choose 0 or 1, you should write down the following matrix.
#Rotation from camera frame to imu frame, imu^R_cam
extrinsicRotation: !!opencv-matrix
   rows: 3
   cols: 3
   dt: d
   data: [0.0148655429818, -0.999880929698, 0.00414029679422,
           0.999557249008, 0.0149672133247, 0.025715529948, 
           -0.0257744366974, 0.00375618835797, 0.999660727178]
#Translation from camera frame to imu frame, imu^T_cam
extrinsicTranslation: !!opencv-matrix
   rows: 3
   cols: 1
   dt: d
   data: [-0.0216401454975,-0.064676986768, 0.00981073058949]

4、在节点/feature_traker中需要用到的参数

#feature traker paprameters
max_cnt: 150            # max feature number in feature tracking
min_dist: 30            # min distance between two features 
freq: 10                # frequence (Hz) of publish tracking result. At least 10Hz for good estimation. If set 0, the frequence will be same as raw image 
F_threshold: 1.0        # ransac threshold (pixel)
show_track: 1           # publish tracking image as topic
equalize: 1             # if image is too dark or light, trun on equalize to find enough features
fisheye: 0              # if using fisheye, trun on it. A circle mask will be loaded to remove edge noisy points

1)max_cnt为进行特征光流跟踪时保持的特征点数量,具体在FeatureTracker::readImage(),通过当前帧成功跟踪的特征点数,计算是否需要提取新的特征点,如果需要则用过goodFeaturesToTrack()提取。

max_cnt值增大在一定条件下会提高跟踪的鲁棒性(但在环境特征本来就不丰富的地方反而会提取不够鲁棒的特征点),但是会增加之后所有算法的运算时间,例如在我调试时取250已经无法达到实时性。

int n_max_cnt = MAX_CNT - static_cast<int>(forw_pts.size());
if (n_max_cnt > 0)
        {
            //...
            cv::goodFeaturesToTrack(forw_img, n_pts, MAX_CNT - forw_pts.size(), 0.01, MIN_DIST, mask);
        }

2)min_dist为两个相邻特征之间像素的最小间隔,目的是保证图像中均匀的特征分布。在FeatureTracker::setMask()中应用,该函数的作用是对跟踪点进行排序并去除密集点。
min_dist的实现原理是在mask中将当前特征点周围半径为MIN_DIST的区域设置为0,后面便不再选取该区域内的点。

cv::circle(mask, it.second.first, MIN_DIST, 0, -1);

这个参数取大一些,比如30,可以保证图像的特征点分布非常均匀,有利于图像全局的光流跟踪;如果在特征明显的场合下可以适当取小一些,保证跟踪的特征都聚集在特征明显的地方。

3)freq控制图像跟踪的发布频率。在回调函数img_callback()中应用,通过判断判断间隔时间内的发布次数控制发布频率。一般根据相机的运行速度以及其他参数调完后的实时运行情况进行调整。

if (round(1.0 * pub_count / (img_msg->header.stamp.toSec() - first_image_time)) <= FREQ)
    {
        PUB_THIS_FRAME = true;
        if (abs(1.0 * pub_count / (img_msg->header.stamp.toSec() - first_image_time) - FREQ) < 0.01 * FREQ)
        {
            first_image_time = img_msg->header.stamp.toSec();
            pub_count = 0;
        }
    }
    else
        PUB_THIS_FRAME = false;

4)F_threshold为ransac算法的门限值,在FeatureTracker::rejectWithF()通过计算基本矩阵去除图像特征跟踪的外点时使用,一般不修改。

cv::findFundamentalMat(un_cur_pts, un_forw_pts, cv::FM_RANSAC, F_THRESHOLD, 0.99, status);

5)show_track:将经过特征跟踪的图像进行发布,需要。

6)equalize: 如果图像整体太暗或者太亮则需要进行直方图均衡化,在FeatureTracker::readImage()中进行自适应直方图均衡化,需要。

if (EQUALIZE)
    {
        cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE(3.0, cv::Size(8, 8));
        TicToc t_c;
        clahe->apply(_img, img);
        ROS_DEBUG("CLAHE costs: %fms", t_c.toc());
    }
    else
        img = _img;

7)fisheye:鱼眼相机一般需要圆形的mask,以去除外部噪声点。mask图在config文件夹中。

5、在节点/vins_estimator中需要用到的参数

#optimization parameters
max_solver_time: 0.04  # max solver itration time (ms), to guarantee real time
max_num_iterations: 8   # max solver itrations, to guarantee real time
keyframe_parallax: 10.0 # keyframe selection threshold (pixel)

max_solver_time和max_num_iterations分别定义了ceres优化器的最大迭代时间和最大迭代次数,以保证实时性。在Estimator::optimization()中使用,并根据不同的边缘化方案而有改变。

options.linear_solver_type = ceres::DENSE_SCHUR;
options.trust_region_strategy_type = ceres::DOGLEG;
options.max_num_iterations = NUM_ITERATIONS;
if (marginalization_flag == MARGIN_OLD)
	options.max_solver_time_in_seconds = SOLVER_TIME * 4.0 / 5.0;
else
	options.max_solver_time_in_seconds = SOLVER_TIME;

keyframe_parallax定义了关键帧的选择阈值。在FeatureManager::addFeatureCheckParallax()中通过计算每一个点跟踪次数和它在次新帧和次次新帧间的视差确定是否是关键帧。这个参数影响着算法中关键帧的个数。
其中keyframe_parallax为像素坐标系,MIN_PARALLAX为归一化相机坐标系。

MIN_PARALLAX = fsSettings["keyframe_parallax"];
MIN_PARALLAX = MIN_PARALLAX / FOCAL_LENGTH;

    for (auto &it_per_id : feature)
    {
        if (it_per_id.start_frame <= frame_count - 2 &&
            it_per_id.start_frame + int(it_per_id.feature_per_frame.size()) - 1 >= frame_count - 1)
        {
            parallax_sum += compensatedParallax2(it_per_id, frame_count);
            parallax_num++;
        }
    }
    if (parallax_num == 0)
    {
        return true;
    }
    else
    {
        return parallax_sum / parallax_num >= MIN_PARALLAX;
    }

6、IMU参数

#imu parameters       The more accurate parameters you provide, the better performance
acc_n: 0.08          # accelerometer measurement noise standard deviation. #0.2   0.04
gyr_n: 0.004         # gyroscope measurement noise standard deviation.     #0.05  0.004
acc_w: 0.00004         # accelerometer bias random work noise standard deviation.  #0.02
gyr_w: 2.0e-6       # gyroscope bias random work noise standard deviation.     #4.0e-5
g_norm: 9.81007     # gravity magnitude

包括加速度计和陀螺仪测量值的噪声标准差和随机偏置的导数标准差,以及重力加速度大小。因为在进行IMU预积分时我们假设传感器的噪声noise服从高斯分布,偏置bias的导数服从高斯分布。
这部分的参数对结果的精度有一定影响,建议读取IMU的datasheet中具体参数或者进行IMU标定直接确定,以降低之后调参的难度。

7、闭环用到的参数

#loop closure parameters
loop_closure: 1                    # start loop closure
load_previous_pose_graph: 0        # load and reuse previous pose graph; load from 'pose_graph_save_path'
fast_relocalization: 0             # useful in real-time and large project
pose_graph_save_path: "/home/tony-ws1/output/pose_graph/" # save and load path

load_previous_pose_graph 为新功能:地图重用,通过载入先前的位姿图文件实现。
fast_relocalization常用于高实时性或者地图非常大、持续时间长的地方,得到的结果精度会降低。一般实验时先不打开。

8、在线时差校准

这是VINS的新功能:因为大多数相机和IMU不是时间同步的,所以将estimate_td设置为1可以在线估计相机和IMU之间的时间差。
参数td在Estimator::optimization()里放在视觉残差函数中进行非线性优化。

#unsynchronization parameters
estimate_td: 0                      # online estimate time offset between camera and imu
td: 0.0                             # initial value of time offset. unit: s. readed image clock + td = real image clock (IMU clock)

9、支持卷帘相机。

这也是VINS的新功能:将rolling_shutter设置为0表示全局曝光相机;设置为1表示卷帘曝光相机,此时需要从传感器的datasheet中得到rolling_shutter_tr的值。不要使用网络摄像头webcam,不适合用。

#rolling shutter parameters
rolling_shutter: 0                  # 0: global shutter camera, 1: rolling shutter camera
rolling_shutter_tr: 0               # unit: s. rolling shutter read out time per frame (from data sheet). 

以上两个功能具体在以下代码中实现:
pts_i_td表示处理时间同步误差和Rolling shutter时间后,角点在归一化平面的坐标。
TR / ROW * row_i就是相机 rolling 到这一行时所用的时间

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;

10、RVIZ可视化参数

#visualization parameters
save_image: 1                   # 保存在位姿图中的图像,为0则关闭
visualize_imu_forward: 0        # 输出IMU前向递推的角度预测值,一般用于低延迟和高频率的应用要求下
visualize_camera_size: 0.4      # 在RVIZ显示中相机模型的大小

其中visualize_imu_forward在pose_graph_node中的imu_forward_callback()即imu前向递推的回调函数中用到,如果为1则接收IMU前向递推的角度预测值,经回环的偏移矫正并转换为世界坐标系下的相机姿态,发布;为0则什么都不做,不发布。

总结

拿到一个新的相机-IMU组件,在安装对应的驱动和ROS包后,首先需要对yaml文件的传感器信息部分进行以下修改(这部分信息尽可能准确):
1、确定相机和IMU各自发布的topic;
2、标定相机、IMU的内参,从相机到IMU的外参;
3、是否是硬件时间同步,如果不是的话需要进行在线同步时差估计;
4、相机是卷帘曝光还是全局曝光。
之后根据应用场景的要求,确定是否需要进行回环检测、快速重定位或是读取之前位姿图等功能,以及用于RVIZ可视化的参数。根据在实际场景运行后的情况再对/feature_traker和/vins_estimator中的参数进行调整,以获得较好的结果。当然这只是在实验阶段,要使其能真正落地应用,还需要进行不断的测试和优化。

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

VINS-Mono代码解读——启动文件launch与参数配置文件yaml介绍 的相关文章

随机推荐

  • 【论文写作】Word中公式快捷输入方式

    环境 Win10 64位 用到软件 Mirsoft Word MathType Mathpix snipping tool Quicker 说明 xff1a 点击链接可以直达官网 一 前言 针对Word中公式输入效率低的问题 xff0c 本
  • 练习7-10 查找指定字符 (15分)

    本题要求编写程序 xff0c 从给定字符串中查找某指定的字符 输入格式 xff1a 输入的第一行是一个待查找的字符 第二行是一个以回车结束的非空字符串 xff08 不超过80个字符 xff09 输出格式 xff1a 如果找到 xff0c 在
  • 用cropper.js裁剪图片并上传到服务器,解析base64转存图片到本地

    今天要写上传图片功能 xff0c 研究了一下cropper 将图片上传服务器并保存到本地 html lt html gt lt head gt lt title gt 基于cropper js的图片裁剪 lt title gt lt met
  • 通讯协议详解

    1 xff0c 概念 网络协议指的是计算机网络中互相通信的对等实体之间交换信息时所必须遵守的规则的集合 网络上的计算机之间是如何交换信息的呢 xff1f 就像我们说话用某种语言一样 xff0c 在网络上的各台计算机之间也有一种语言 xff0
  • 自动识别击打控制系统

    目录 摘 要 关键词 一 系统方案 1 1 系统基本方案 1 2 程序算法的具体流程 二 视觉程序识别框架 2 1多线程 2 2 opencv配置文件 2 3 主函数 三 装甲板识别算法 3 1 装甲板识别 3 2 识别函数介绍 四 目标位
  • 基于stm32风力摆控制系统(电赛获得省一)

    目录 需要源文档及程序进入主页 一 系统方案 完整文档以及代码可主页私 1 1 系统基本方案 1 1 1 控制方案设计 1 1 2 机械结构方案设计
  • 基于stm32的所有嵌入式项目代码

    nbsp nbsp nbsp nbsp nbsp nbsp nbsp nbsp 本人本科和硕士阶段的专业都是嵌入式方向 做了许许多多的项目 包括51 stm32 freeRTOS linux操作系统 多进程线程实现功能 包括裸机开发 驱动开
  • 基于图像处理的水果自助售卖系统(自助水果售卖机)

    目录 第一章 nbsp 概述 1 1 发展概要 1 2 国内外研究现状 1 3 研究目的和意义 1 4 方案介绍
  • 基于stm32的无人机控制系统设计

    基于stm32的无人机控制系统设计 整篇文章有两万字左右 字数太多了 实在是懒得全部放在这上面来 太废时间了 需要完整论文可主页联系 第一章 前言 1 1项目背景和意义 1 2国内外发展现状 1 3本文研究的主要内容 第二章 设计方案论证与
  • 基于Robot Studio的工业机器人汽车喷涂仿真设计

    基于Robot Studio的工业机器人汽车喷涂仿真设计 整篇文章字数有一万四左右 图片太多了 实在是懒得全部放在这上面来 太废时间了 获得完整论文关注可查看主页私信我 摘要 关键词 1 绪论 1 1研究背景与意义 1 2国内外研究现状 2
  • 基于单片机的压力流量报警器(附代码+仿真+论文)

    基于单片机的压力流量报警器 附代码 仿真 论文 完整论文 代码 仿真可关注我在主页私我 摘要 关键字 第一章绪论 1 1课题背景及其意义 1 2 国内外的研究状况 1 3本文的主要研究内容及论文结构安排 第二章 方案的设计与论证 2 1控制
  • 基于STM32的微型电子琴设计

    基于STM32的微型电子琴设计 第一章 总体设计 1 1 系统功能 1 2 主要技术性能指标 第二章硬件设计 2 1 整体硬件图 2 2 按键模块 2 3 扬声器模块 2 4 显示模块 2 5 主控模块 第三章 软件设计 3 1 主要工作原
  • 百度2015校园招聘软件开发笔试题及答案

    简单题 xff08 本题共30分 xff09 请简述Tcp ip的3次握手以及4次挥手过程 xff1f 并解释为何关闭连接需要4次挥手 10分 详细答案参见TCP IP协议三次握手与四次握手流程解析 TCP三次握手 四次挥手过程如下 通常情
  • 智能算法实现PID智能车控制系统

    智能算法实现PID智能车控制系统 TOC 智能算法实现PID智能车控制系统 摘要 关键词 第一章绪论 1 1智能车概述 1 2智能PID研究现状 1 3本文工作 第二章 PID控制简介 第三章 内模PID简介 3 1 内模PID控制 第四章
  • esp8266WiFi模块通过MQTT连接华为云

    esp8266WiFi模块通过MQTT连接华为云 总结 xff1a 一 MQTT透传AT固件烧录二 串口调试2 1 设置模块为STA模式2 2 连接WiFi2 3 设置MQTT的登陆用户名与密码2 4 设置MQTT的ClientID2 5
  • tx2性能不够怎么办

    关闭pycharm xff0c 使用终端直接Python3 5 加路径脚本名运行
  • 瑞泰烧录捞取

    关于将pc主机上的镜像文件拷贝到tx2上的方法 一 给Linux主机搭建环境 2 2 解压 Linux Driver Package tar vxjf Tegra lt t arch ver gt Linux R aarch64 tbz2
  • Realsense D435i 在ubuntu上安装SDK与ROS Wrapper 运行ORB-SLAM2、RTAB和VINS-Mono

    前言 等了一个月的realsense d435i终于发货了 xff01 这款D435i xff08 见下图 xff09 在D435的基础上 xff0c 另外搭载了博世的惯性测量单元 xff08 IMU xff09 xff0c 可以作为研究V
  • 如何用Realsense D435i运行VINS-Mono等VIO算法 获取IMU同步数据

    前言 Intel Realsense D435i在D435的基础上硬件融合了IMU xff0c 然而目前网上关于这款摄像头的资料非常少 xff0c 本文主要介绍自己拿着d435i历经曲折最后成功运行VINS Mono的过程 重要 最近官方更
  • VINS-Mono代码解读——启动文件launch与参数配置文件yaml介绍

    前言 一般我们通过以下命令运行VINS Mono跑MH 01数据集 roslaunch vins estimator euroc launch roslaunch vins estimator vins rviz launch rosbag