
先说一个我自己的判断在Ubuntu20.04上把VINS-Mono、VINS-Fusion、GVINS这一整套跑通算法层面的门槛真不高真正的拦路虎是版本生态的错位。这三个框架几乎都是基于Ubuntu16.04/18.04和ROS Melodic开发的而20.04默认带的是ROS Noetic、OpenCV 4.2、Ceres 1.18这一堆版本差直接把很多人卡在编译阶段。这篇文章就是我从零到一在20.04上把三套系统都搞定、并顺手摸清各种坑的记录适合正在部署VINS系列做毕设或科研项目的同学参考。我会按“准备环境、跑通Mono、理解Fusion、啃下GVINS、通用排障”这个顺序展开。全程用我实际验证过的方案凡是需要改代码的地方都会明确说凡是容易踩坑的地方都会反复强调。你不需要同时看完再动手跟着章节走就行。1. VINS系列在Ubuntu20.04上折腾的根因版本错位而不是算法难1.1 三个框架各自的定位和发布时间线VINS-Mono是香港科技大学2017年前后开源的视觉惯性里程计核心思路是把单目相机和IMU做紧耦合在滑动窗口里联合优化位姿和地图点。这个项目对单目SLAM的工程化推动很大很多后来者都参考过它的因子图结构和边缘化实现。VINS-Fusion是同一团队随后推出的多传感器融合框架它把VINS-Mono里的核心估计器抽象出来支持单目IMU、双目IMU、双目IMUGPS等多种配置还加入了全局的位姿图优化。它的改动不只是在Mono上加几个传感器选项而是把整个系统结构重新整理了一遍。GVINS则更进一步在VINS-Mono的基础上把GNSS原始观测值伪距、多普勒、载波相位作为新的因子塞进紧耦合框架和视觉、惯性一起做联合优化。这意味着它不像VINS-Fusion那样仅仅接收一个GPS位置解算结果而是要处理接收机输出的原始测量数据。GNSS观测量本身有噪声、有周跳、有粗差处理起来比单纯吃一个坐标要复杂得多。三套系统的时间线决定了它们的依赖习惯Mono时期大家还在用OpenCV 3.2和Ceres 1.13Fusion和GVINS虽然晚一些但官方文档里也只验证过Melodic。Noetic出来之后OpenCV从3跳到4一大堆C接口改名这些问题你迟早要面对。1.2 两个系统版本之间的具体差异组件Ubuntu18.04 MelodicUbuntu20.04 NoeticOpenCV3.24.2Eigen3.3.43.3.7Ceres1.13 / 1.141.18cv_bridge基于OpenCV 3.2构建基于OpenCV 4.2构建Python绑定Python2Python3直观来看Eigen从3.3.4到3.3.7几乎无缝Ceres从1.14到1.18的API也基本兼容这三个版本里真正伤筋动骨的是OpenCV的大版本升级。OpenCV 4把很多C接口的头文件去掉了一些枚举常量改了名部分函数的参数类型也变了。VINS系列的代码里大量使用cv::imread、cv::solvePnP这类API大部分在4.x下还能跑但像CV_LOAD_IMAGE_GRAYSCALE、CV_RGB2GRAY这种旧宏就直接不存在了。更隐蔽的是cv_bridge。ROS Noetic系统自带的cv_bridge链接的是系统OpenCV 4.2如果你的工作空间里又单独编译了一个OpenCV 3.4.x装到/usr/local并且某些第三方包的CMakeLists里find_package(OpenCV 3 REQUIRED)就可能出现一条编译链用OpenCV 3、另一条用OpenCV 4的情况。编译阶段通常不报错一跑起来就段错误或者图像全是黑的排查起来非常烦。1.3 三种路线怎么选我在20.04上试过三条路结论很明确。路线上比较省心的方案是直接修改VINS系列源码来适配Noetic自带的OpenCV 4.2。这是实际操作中最推荐的方式。缺点是要动几处代码但对理解和排错都有帮助。第二条路是装双版本OpenCV让老代码用3.xROS这边继续用4.x。这个方案看起来美实际维护成本极高find_package的OpenCV_DIR很容易指错你还要在源码编译时单独指定路径时间成本和心智负担都不低。第三条路是Docker。如果你只是想在某个固定数据集上复现结果Docker很合适但要接自己的相机、IMU、GNSS接收机需要把USB设备和GUI都透传到容器里折腾起来并不比改源码省事。所以我下面的所有内容都基于“直接用Noetic自带的OpenCV 4.2 顺手改几行代码”这条主路线。2. 基础环境准备Eigen、Ceres、OpenCV、cv_bridge的选型和验证2.1 Eigen和Ceres系统包能满足需求别乱动先说结论Ubuntu20.04上Eigen和Ceres直接用apt安装即可。sudo apt update sudo apt install libeigen3-dev libceres-devEigen是一个纯头文件库20.04源里的版本是3.3.7满足VINS-Mono、VINS-Fusion、GVINS三套代码的要求。Ceres的库文件稍晚一些apt源里大概是1.18.0也比老项目要求的1.13/1.14更安全。很多人有个误区觉得源码编译的Ceres一定比apt的好但其实这两个库只要版本匹配源码版和系统版对VINS系列来说没有本质区别。稳定性优先级高于“看起来新”。2.2 OpenCV版本统一是重中之重在开始编译前必须先确认系统OpenCV版本。pkg-config --modversion opencv4如果返回4.2.0说明Noetic自带版本正常。这里我建议不要为了适配老代码特意去安装OpenCV 3.x。原因是cv_bridge、image_pipeline这些ROS基础包都是针对OpenCV 4.2编译好的一旦你安装了一个OpenCV 3.x并配置了OpenCV_DIR整个工作空间会发生混乱。统一版本的另一个隐蔽点是编译顺序。如果你在一个catkin工作空间里同时放VINS源码和vision_opencv源码并且把cv_bridge也重新编译了一遍那你要保证所有package的find_package(OpenCV ...)都指向同一个路径。最稳的方式是不搞双版本直接用系统的4.2VINS代码里遇到旧API就改一行见一个改一个。2.3 cv_bridge是运行期崩溃的一个高发点cv_bridge是ROS里图像消息和OpenCV Mat之间的转换层。Noetic自带cv_bridge是用OpenCV 4.2编译出来的这和你的目标一致。很多同学编译VINS都能过但运行阶段一旦图像话题进来就崩溃十有八九是cv_bridge和某个自定义库链接的OpenCV版本不一致。判断方法很简单编译成功后在运行前执行rosversion cv_bridge然后看它的依赖ldd /opt/ros/noetic/lib/libcv_bridge.so | grep opencv正常情况下应该全部指向/usr/lib/x86_64-linux-gnu/下的OpenCV 4.2库文件。如果指向/usr/local/lib下某个3.x版本说明你之前手工装过OpenCV 3把系统链接顺序污染了。解决办法是把/usr/local/lib下旧OpenCV的软链接清掉或者在CMakeLists里明确指定find_package(OpenCV 4.2 REQUIRED)。这个坑我在Fusion上踩过一次症状很反直觉编译顺利通过跑起来两秒就死。2.4 环境检查清单和验证命令在开始编译任何VINS项目前建议先跑一遍下面的检查检查项命令期望结果ROS版本rosversion -dnoeticOpenCV版本pkg-config --modversion opencv44.2.0Eigen版本pkg-config --modversion eigen33.3.7Ceres版本dpkg -l | grep libcereslibceres-dev 已安装cv_bridge依赖ldd /opt/ros/noetic/lib/libcv_bridge.so | grep opencv全部指向4.2这套检查花不了两分钟但能避免后面编译失败后反复回头找原因。我见过不少人在GitHub issue里问编译报错一查环境问题根本不是编译而是Ceres没装或者Eigen版本不对。3. VINS-Mono完整编译与跑通官方EuRoC数据集3.1 创建独立工作空间并处理ar_demo的依赖VINS-Mono是老工程我强烈建议给它单独建一个workspace不要和Fusion、GVINS混在一起。原因是Mono和Fusion的package里有些节点重名混在一个工作空间里会互相覆盖。mkdir -p ~/vins_mono_ws/src cd ~/vins_mono_ws/src git clone https://github.com/HKUST-Aerial-Robotics/VINS-Mono.git cd ~/vins_mono_ws rosdep install --from-paths src --ignore-src -r -y这里有个官方README没提的坑VINS-Mono仓库里包含AR_Demo模块它依赖ar_track_alvar如果没装这个包catkin_make会在编译AR_Demo时报错。直接补上sudo apt install ros-noetic-ar-track-alvar如果你不想装这个包也可以把src/VINS-Mono/AR_Demo这个目录移出工作空间不影响主系统运行。但既然官方仓库整体编译更省心我建议直接装依赖。3.2 catkin_make中的OpenCV 4适配点接下来编译cd ~/vins_mono_ws catkin_makeNoetic环境下大概率会报几个OpenCV相关错误。最常见的两个第一个是CV_LOAD_IMAGE_GRAYSCALE未定义。OpenCV 4里这个宏已经被删掉改成cv::IMREAD_GRAYSCALE。报错位置通常在feature_tracker.cpp或camera_model相关文件里直接把旧宏替换成新宏即可。第二个是CV_RGB2GRAY未定义。类似的处理方式替换成cv::COLOR_RGB2GRAY。有时候头文件里的枚举名还带着CV_前缀但OpenCV 4已经把它们移到cv::命名空间下编译报错后看提示改就行。如果你的版本还遇到openCV2/xfeatures2d找不到的问题先检查是不是装了libopencv-contrib-dev。VINS-Mono早期代码里有人用到SIFT特征但官方分支其实不依赖contrib。实在遇到再装sudo apt install libopencv-contrib-dev3.3 官方E开源数据集下载和launch配置VINS-Mono官方推荐使用EuRoC MAV数据集典型文件是MH_01_easy.bag直接搜“EuRoC MAV 数据集下载”就能找到大小在几个GB左右。下载后不需要解压rosbag play直接播放。启动核心节点roslaunch vins_estimator euroc.launcheuroc.launch放在vins_estimator/launch目录下它内部通过config_file参数指定了euroc_config.yaml。这个yaml文件里定义了两个最重要的订阅话题imu_topic: /imu0和image_topic: /cam0/image_raw。EuRoC数据包里恰好也是这两个话题名所以能直接对得上。另一个重要的启动文件是rviz显示的配置。euroc.launch一般会顺带启动rviz如果没有自动弹出来手动执行rosrun rviz rviz -d ~/vins_mono_ws/src/VINS-Mono/vins_estimator/rviz/rviz_euroc.rviz3.4 播放bag后的初始化观察启动完launch后再打开一个终端播放bagrosbag play MH_01_easy.bag正常情况下终端会先打印等待IMU和图像的信息然后随着bag播放VINS经过一个短暂的初始化过程后开始输出位姿rviz里会逐渐画出绿色轨迹。这里有一个非常常见的误导性现象如果你在bag播放后十几秒里看不到轨迹不一定是系统卡了很可能是IMU初始化还没完成。EuRoC数据集的IMU数据比图像数据早很多而且初始化需要充分的加速度激励。如果等到bag播放了一半还是没有轨迹先检查终端的VINS日志。看到一个“Init finish”类似的输出就说明初始化已经过了这时候应该有轨迹。日志位置和字段在不同版本略有差异但核心意思是检查是否进入了正常估计状态。3.5 运行期故障图像话题频率和分辨率不匹配VINS-Mono的视觉前端对图像帧率并不敏感但对分辨率很敏感。euroc_config.yaml里写明了image_width: 752和image_height: 480如果你的bag是其他分辨率或者你是从自己的相机采集数据一定先把这两项改成实际分辨率。否则特征提取出来全部越界追踪框显示一片红位姿直接飞掉。还要注意图像编码。EuRoC数据包里的图像通常是mono8而VINS-Mono在getImage函数里读取时用CV_LOAD_IMAGE_GRAYSCALE默认会转成灰度。如果是彩色图像且编码是bgr8处理逻辑本身能扛得住但会多一次颜色转换。最让人困惑的是某些数据集的图像topic里同时发布了compressed和原始图像两种消息VINS订阅的是原始图像播放bag时要确认rosbag play没有把图像转成压缩格式。4. VINS-Fusion多传感器配置下的使用差异4.1 先搞清楚Fusion相对Mono改了什么VINS-Fusion不是简单地把Mono功能搬个家它的几个重要变化直接影响使用方式。第一传感器配置更灵活。Mono只做了单目IMUFusion把双目IMU和单目IMU都整合进了同一个vins_node通过yaml配置切换。第二增加了全球坐标融合模块也就是global_fusion节点。第三回环检测模块被拆得更清晰定位估计和位姿图优化可以分开跑。需要特别说明的是VINS-Fusion里的GPS融合它接收的GNSS数据通常是NavSatFix类型也就是已经解算出的经纬高坐标在优化里作为位置观测因子使用。这和GVINS直接消费GNSS原始观测值有本质区别。所以如果你手头只有普通的GPS模块输出NMEAVINS-Fusion这条链路还走得通GVINS那条路则基本走不通后面我会展开讲。4.2 编译VINS-Fusion最容易踩的坑和Mono共用工作空间给Fusion也单独建一个工作空间。不要图省事直接塞进Mono的src里重新catkin_make因为两者都有pose_graph这类同名节点放到一起后生成的devel目录会互相覆盖最后跑起来到底是什么版本你都搞不清。mkdir -p ~/vins_fusion_ws/src cd ~/vins_fusion_ws/src git clone https://github.com/HKUST-Aerial-Robotics/VINS-Fusion.git cd ~/vins_fusion_ws catkin_make编译时同样会遇到OpenCV 4的API问题处理方式和Mono一致。特别提醒一下VINS-Fusion里的global_fusion节点编译时会用到GeographicLib相关的坐标转换逻辑如果报找不到库先安装sudo apt install ros-noetic-geographic-msgs geographiclib-tools4.3 用EuRoC bag运行单目和双目两种模式先跑单目IMU模式roslaunch vins_fusion vins_rviz.launch rosrun vins_fusion vins_node ~/vins_fusion_ws/src/VINS-Fusion/config/euroc/euroc_mono_imu_config.yaml再开一个终端播放bag你会在rviz里看到和Mono类似的单目轨迹。要注意的是VINS-Fusion默认启动的vins_rviz.launch只负责加载rviz界面真正做估计的是你手动rosrun出来的vins_node。接着跑双目IMU模式。先把单目节点CtrlC停掉然后执行rosrun vins_fusion vins_node ~/vins_fusion_ws/src/VINS-Fusion/config/euroc/euroc_stereo_imu_config.yaml同时播放同一个bag可以看到双目模式在尺度估计和初始化速度上明显更稳。因为VINS-Mono在纯单目下会有尺度不可观的问题IMU的加速度计虽然能约束尺度但初始化阶段需要足够的运动激励双目则基本不存在这个问题。两条轨迹放在一起对比能明显感受到双目对Z轴方向漂移的抑制更强。4.4 GPS融合的正确打开方式跑双目GPS融合之前注意VINS-Fusion里对应的GPS topic默认是/gps消息类型是sensor_msgs/NavSatFix。如果你自己录数据需要把GPS接收机的NMEA输出转成NavSatFix消息再发布。在EuRoC数据集里并没有GPS数据所以想实际验证这一节得找VINS-Fusion官方提供的带GPS的公开bag或者在仿真里自己生成一个。启动顺序是这样的先启动vins_node读双目IMU配置再启动global_fusion节点rosrun global_fusion global_fusion_nodeglobal_fusion节点会在GPS数据可用时把GPS经纬高转换成局部坐标系下的位置约束和VINS输出做一个融合平滑。这里有个使用习惯问题如果你的GPS初始坐标给得很偏比如数据采集时接收机还没收敛融合结果会在一段时间内明显偏离纯VINS轨迹。官方代码里做的是WGS84到局部ENU的转换它依赖一个初始参考点这个参考点如果错了后面所有GPS观测都会出现系统性偏差。所以你第一次验证时最好播放官方提供的数据包直接用原始配置跑通。等确认整条链路没问题再换自己的数据去调初始坐标和噪声参数。5. GVINS加入GNSS原始观测后的部署复杂度5.1 GVINS在黑箱里到底多加了什么GVINS全称是“Tightly Coupled GNSS-Visual-Inertial Fusion”研究重点是让机器人在GNSS信号不全的环境里依然能稳定定位。它的底层逻辑我非常喜欢GNSS信号不是只有“收敛后的位置”这一种用法伪距、多普勒、载波相位这些原始观测量都可以直接进入优化。对比来看VINS-Fusion的GPS融合更像是在一个装好位置结果的服务器上二次加工GVINS则是把GNSS接收机当成另一个传感器在紧耦合框架里和视觉残差、IMU预积分残差一起做非线性优化。这带来两个直观结果第一GNSS可见卫星数很少时GVINS依然能利用单颗卫星的伪距约束不会因为位置解算失败就完全失去全局信息第二它对接收机硬件有硬性要求必须能输出原始观测量普通NMEA接收机喂不进去。5.2 环境准备里的特殊依赖RTKLIBGVINS的GNSS部分大量复用了RTKLIB的代码所以编译前必须先编译安装RTKLIB。这个步骤是整个GVINS部署里最容易出问题的地方。cd ~/gvins_ws/src git clone https://github.com/HKUST-Aerial-Robotics/GVINS.gitGVINS仓库里自带RTKLIB相关代码目录具体位置以你clone下来的版本为准通常在仓库根目录下进入目录后按README里的方式编译安装mkdir build cd build cmake .. sudo make install这里有两个注意事项。第一不是make完就结束必须sudo make install把生成的库安装到系统路径否则后面GVINS编译时找不到RTKLIB的头文件和动态库。第二不要用apt源里的RTKLIB替代版本和接口都可能对不上GVINS通常需要特定版本直接替换很可能让自定义消息的解析逻辑崩溃。如果你clone下来的仓库没有带RTKLIB目录就需要去RTKLIB官方仓库单独拉一份再按GVINS的README指引把源码放到指定位置。这个依赖关系不同分支会有些许差异以仓库文档为准。5.3 编译GVINS时的Noetic兼容点GVINS的代码相对新对OpenCV 4的适配比Mono和Fusion好一点但仍存在老API问题。编译命令仍然是标准的cd ~/gvins_ws catkin_make如果报错集中在camera_model相关文件处理方式参照Mono里的同名文件改动。如果报错集中在gnss_obs相关包多半是RTKLIB没装好或者自定义消息生成失败。gnss_obs包里定义了自己的ROS消息类型比如observation和ephemeris这些消息在catkin_make时自动生成。如果你改了消息定义一定要重新catkin_make并且播放bag的客户端也要同步编译否则会出现“消息类型不匹配”的运行时错误。GVINS编译时还有一个细节它的部分节点依赖gnss_msg里的服务定义在运行时如果找不到对应服务名会先打印一段错误然后再启动。这个不对系统运行造成致命影响但会让第一次跑的人误以为出了问题。正确做法是先不管等所有节点起来后看整体状态。5.4 用官方bag验证GVINSGVINS官方提供了配套的数据包里面不仅包含相机图像和IMU数据还包含GNSS原始观测和卫星星历话题名通常是/imu0、/cam0/image_raw、/gnss_obs、/gnss_eph这样的自定义类型。播放方式类似roslaunch gvins_estimator gvins.launch rosbag play gvins_dataset.bag如果launch文件名和你下载到的仓库不太一样去gvins_estimator/launch目录下看一眼用那个文件即可。第一次跑通的关键不是命令而是确认bag里确实有GNSS原始观测话题。你可以用下面的命令检查rosbag info gvins_dataset.bag如果输出里只有/gps/fix这种NavSatFix话题没有/gnss_obs和/gnss_eph那这个bag是喂不进去GVINS的。在rviz里GVINS会显示相机轨迹同时还有一个标志表示当前GNSS解算状态。判断系统是否正常不要只看轨迹画没画出来要看日志里卫星数是否大于0、伪距残差是否在合理范围。5.5 自己录GNSS数据时的三条血泪教训第一个教训是接收机必须有原始观测输出能力。普通几百块的GPS模块只有定位结果NMEA语句没有原始观测量。GVINS需要的是类似u-blox F9P、NovAtel、Septentrio这些支持输出原始观测数据的接收机。买硬件之前一定要确认规格参数里写了“raw observation output”。第二个教训是时间同步问题。GNSS观测值和图像、IMU必须在一个统一的时间基准下否则融合时会出现明显的时间偏差。最简单的方式是让所有传感器都用主机的ROS时间并在录制bag时把GNSS接收机的PPS脉冲一起采集进来做校时。第三个教训是初始位置。GVINS需要知道一个比较准确的初始经纬高用来把卫星位置和接收机位置放入同一个坐标系。如果初始位置偏出几十米到几百米伪距残差会从一开始就很大优化很难收敛到真实轨迹。官方代码里通常会在launch参数或配置文件中设置初始LLA你要根据实际测试场地修改。6. 三套系统通用的故障排查思路和调优经验6.1 编译期错误速查表我把自己在20.04上踩过的、以及平时在技术社区里频繁看到的编译错误整理成了一张对照表。遇到问题时先对号入座能少走非常多弯路。报错关键词大概率原因处理方式CV_LOAD_IMAGE_GRAYSCALE未声明OpenCV 4删除了旧宏替换为cv::IMREAD_GRAYSCALECV_RGB2GRAY未声明OpenCV 4枚举改名替换为cv::COLOR_RGB2GRAYar_track_alvar找不到VINS-Mono的AR_Demo依赖缺失sudo apt install ros-noetic-ar-track-alvarGeographicLib找不到VINS-Fusion的global_fusion依赖缺失安装ros-noetic-geographic-msgsCeresConfig.cmake找不到Ceres没装或路径不对sudo apt install libceres-devlibopencv_core.so.3.2找不到编译时找的OpenCV版本和运行时不一致统一使用系统OpenCV 4.2tf/transform_datatypes.h不存在老代码里包含旧版tf头文件把#include tf/transform_datatypes.h改成#include tf2_geometry_msgs/tf2_geometry_msgs.h并按需调整cv_bridge版本冲突手工安装的OpenCV污染了ROS库路径检查ldd /opt/ros/noetic/lib/libcv_bridge.so清理/usr/local下多余OpenCV6.2 运行期崩溃和卡顿的通用排查链路运行期问题比编译期更耗时。先说rviz崩溃。如果在20.04里打开rviz看轨迹时界面突然闪退先试试这个经典命令export QT_X11_NO_MITSHM1 rviz这个问题常见于VMware虚拟机或部分远程桌面环境VINS本身并没有崩溃。再说“节点开着、bag在播放、rviz里就是没有轨迹”。按下面顺序排查确认话题名对得上。rostopic list查看实际话题对照yaml里的imu_topic、image_topic和launch里的config_file路径。确认图像话题有数据。rostopic hz /cam0/image_raw如果输出频率为0说明bag没播放成功或话题名不对。确认IMU话题有数据。rostopic hz /imu0同理。确认config文件里的相机内参和实际数据集一致。EuRoC不同序列的外参和内参基本一致但如果你换到TUM或自采数据内参矩阵必须重新标定。查看VINS终端日志有没有输出“wait for image”或“wait for imu”。如果一直卡在这一步是数据没进来如果过了这一步又没位姿是初始化不成功或优化发散。运行很卡的问题则要看具体瓶颈。常用来定位的程序是htop。如果某个CPU核心已经打满而其他核心闲着说明系统并行性没利用起来VINS的滑动窗口优化主要在单线程里跑打满是正常的但如果是连续打满几秒且轨迹还完全不动可能是bag播放速度太快可以用慢速播放rosbag play --rate0.5 MH_01_easy.bag6.3 调参顺序先跑通再谈性能我见过太多人一上来就改process_frequency、调min_parallel_angle、改max_solver_time最后连系统能不能跑通都没确认直接在错误的方向上调参。正确顺序永远是先用官方数据集和官方配置跑通再改一个参数观察效果最后才考虑性能优化。几个关键的配置项值得记住。LOOP_CLOSURE控制回环检测如果数据集里没有回环场景开不开区别不大但开着会增加计算量。ESTIMATE_EXTRINSIC控制外参是否在线估计如果你用的是标定好的数据建议设为0直接固定外参否则初始化阶段会多出几个自由度容易导致漂移。process_frequency控制状态估计的频率降频能显著降低CPU占用但轨迹实时性会变差。如果你要在自己的机器人上跑实时系统我建议先录一段包含充分运动激励的数据离线跑通后再上真机。这样可以把算法问题和传感器硬件问题分开省掉很多同时排查多个变量的时间。最后再分享一个我实际使用中的习惯三套系统的不同版本会带来不同的消息格式和launch行为所以我会把每个workspace的devel/setup.bash路径写到自己的~/.bashrc注释里用哪个系统就source哪个。不要在一个终端里同时source两个workspace否则节点跑起来到底是哪套代码可能连自己都分辨不清。先按我说的把Mono跑通再对比Fusion最后啃GVINS这套顺序能让你对VINS系列的理解形成一个完整的链路。