ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Gazebo仿真VINS-MONO:D435i传感器建模与VIO入门实践

Gazebo仿真VINS-MONO:D435i传感器建模与VIO入门实践 1. 思路别扭却也实用为什么这套组合是VIO入门的“最低成本快车道”1.1 先想清楚你到底在为什么折腾做VIO SLAM这件事最劝退人的不是算法本身而是“没有数据”。实机上跑一套VINS-MONO你得有一台带IMU的相机、校准好的内外参、能对齐时间戳的采集系统、还得给机器人设计运动轨迹。折腾一周可能还没把驱动装明白。仿真最大的价值就是把这些外设成本、调试成本、甚至返工成本全部压缩到一台普通电脑里让你把注意力集中在算法本身。我接触过不少刚开始学视觉SLAM的朋友一上来就拿着《视觉SLAM十四讲》里的数据集跑跑完感觉“会了”但换个传感器、换台机器人就完全懵。原因很简单数据集是别人采集的你不知道标定参数怎么来的不知道IMU和图像时间戳怎么对齐的更不知道一个带噪声的相机模型对结果影响有多大。而在Gazebo里这一切都摊开在你面前可以随时改参数、随时看效果。所以这篇东西不是教你怎么用现成数据集跑个demo而是教你自己“造”一份VIO数据完整过一遍从仿真模型到VINS-MONO闭环的流程。它能解决三件事第一让你在没有D435i实机的情况下把VINS-MONO的完整链路跑通第二让你搞清楚相机内参、IMU频率、外参标定这些硬件概念在代码里到底长什么样第三给你一套可复现的实验环境以后想验证自己的算法改进改改仿真参数就能出对比结果。1.2 我为什么坚持Gazebo VINS-MONO D435i这个组合这套组合放在2024年来看软件栈确实有点“old school”VINS-MONO还是基于ROS 1的代码仓库几年没大更新Gazebo也有了新版Ignition/ Harmonic这样的迭代。但恰恰是这种“老”让它成为教学和算法验证最稳的选择。先说Gazebo。ROS 1生态里的SLAM仿真教程十篇有九篇是Gazebo Classic资料多、坑少、踩过的人多。你在网上搜到的问题基本都是有人回答过的这对新手极其重要。用新版Gazebo不是不行但很多老插件不兼容教程参考价值直接打骨折。做算法验证环境稳定比环境新更重要。再说VINS-MONO。它是单目VIO里最经典的基线之一代码结构清晰论文和文档齐全。虽然VINS-Fusion支持双目/鱼眼/纯视觉但对入门来说单目IMU已经足够理解VIO的核心思想——视觉提供几何约束、IMU提供运动先验、两者紧耦合优化。VINS-MONO的代码量不算大读起来不吃力而且它的配置文件格式非常直白适合用来练习“标定参数和内参对齐”这项核心技能。最后说D435i。为什么要选它做仿真对象因为D435i是目前入门级视觉传感器里最“标准”的选项彩色相机单目视觉200Hz IMU硬件规格和VINS-MONO的realsense配置完美对应。VINS-MONO官方仓库里甚至直接给了config/realsense/realsense_d435i.yaml这个配置文件这意味着你只需要把仿真的话题和参数对齐到这份配置上就能少写一堆代码。仿真里用D435i的模型还有一个好处以后你买了真机从仿真迁移到实机的代码改动非常小基本只需要改话题名和标定参数。2. 环境准备与依赖部署把坑提前踩平2.1 Ubuntu/ROS/Gazebo版本怎么选这是整套流程里最容易被忽视、也最容易翻车的一步。VINS-MONO是ROS 1时代的项目官方测试环境是Ubuntu 16.04/18.04 ROS Kinetic/Melodic。如果你现在手头是Ubuntu 22.04想在原生环境装ROS 1的Noetic对不起Noetic官方只支持到Ubuntu 20.0422.04上需要自己编译或者用容器这个折腾成本太高。我的建议非常直接如果你是第一次跑这套流程用Ubuntu 20.04 ROS Noetic Gazebo 11。这是兼容性最好的组合。Gazebo 11是经典版的最后一个大版本和gazebo_ros_pkgs插件配合得最默契。Ubuntu 22.04当然能跑ROS 2但VINS-MONO原版没有ROS 2版本需要找移植分支这又多一层变量没必要。如果你只有Ubuntu 22.04的机器我建议装个虚拟机跑Ubuntu 20.04或者用Docker拉一个ros:noetic镜像。不要硬刚宿主机环境时间成本太高。我见过太多人在环境上耗掉两三天最后发现是OpenCV版本冲突这种亏吃过一次就够了。安装命令其实没什么悬念按官方文档走就行。Ubuntu 20.04下ROS Noetic的安装核心就几步设置sources.list、添加ROS源、apt install ros-noetic-desktop-full、初始化rosdep。desktop-full会自带Gazebo 11省得再单独装。装完后验证一下source /opt/ros/noetic/setup.bash roscore另外开一个终端gazebo --version rosversion gazebo_ros能正常输出版本号说明OK。如果gazebo_ros没有随desktop-full装进来单独装一下sudo apt install ros-noetic-gazebo-ros-pkgs ros-noetic-gazebo-ros这一步很关键后面URDF里的gazebo标签和插件都要依赖它。2.2 VINS-MONO编译踩坑实录Ceres/OpenCVVINS-MONO的编译依赖主要是Ceres Solver、OpenCV、Eigen。这几个库的版本搭配很讲究我在这里把踩过的坑一次说清。先说Ceres Solver。VINS-MONO官方文档给的是Ceres 1.13或1.14。如果你直接apt install libceres-devUbuntu 20.04上装的是Ceres 2.0编译VINS-MONO时会报一堆函数签名不匹配的错误具体报错类似no matching function for call to Solver::Options::SetNumThreads(int)。很多人卡在这里不知道怎么处理。我的做法是源码编译Ceres 1.14。但要注意Ceres 1.14依赖Eigen 3.3而Ubuntu 20.04源里的Eigen默认是3.3.7没问题。编译Ceres之前先保证依赖齐全sudo apt install libgoogle-glog-dev libgflags-dev libatlas-base-dev libeigen3-dev然后从GitHub拉Ceres Solver 1.14源码进入目录mkdir build cd build cmake .. make -j8 sudo make installOpenCV这边也要注意。VINS-MONO的cv_bridge是编译期依赖ROS里的OpenCV版本。Ubuntu 20.04的Noetic里cv_bridge默认绑定OpenCV 4.2而VINS-MONO的代码里有很多OpenCV 3风格的API比如CV_GRAY2BGR直接编译会报错。解决办法是编译时加一个编译选项把cv_bridge指向OpenCV 4兼容模式或者直接把代码里的CV_GRAY2BGR改成COLOR_GRAY2BGR、CV_FONT_HERSHEY_SIMPLEX改成FONT_HERSHEY_SIMPLEX。我当时懒得改代码直接在编译VINS-MONO前用了这个技巧cd ~/catkin_ws/src/vins-mono sed -i s/CV_GRAY2BGR/COLOR_GRAY2BGR/g src/utility/visualization.cpp sed -i s/CV_FONT_HERSHEY_SIMPLEX/FONT_HERSHEY_SIMPLEX/g src/utility/visualization.cpp实测改成OpenCV 4的命名后VINS-MONO在Noetic下能正常编译运行。如果你运气好遇到的报错不止这两处就搜一下报错里的CV_前缀同类问题统一替换。编译流程按官方README走就行cd ~/catkin_ws/src git clone https://github.com/HKUST-Aerial-Robotics/VINS-Mono.git cd ../catkin_ws catkin_make source devel/setup.bash如果编译过程中报找不到ceres/ceres.h记得在CMakeLists.txt里检查Ceres的路径或者把/usr/local/lib/cmake/Ceres加进CMAKE_PREFIX_PATH。这一步很多人忽略。2.3 验证工具与数据依赖除了VINS-MONO本体我还强烈建议装一个evo这是评估SLAM轨迹精度的神器后面对比仿真groundtruth会用到。安装很简单pip install evo --upgrade --no-binary evo另外需要装一下ros-noetic-rosbag、ros-noetic-tf2这些基础工具desktop-full一般都有了。还有一个容易漏的是ros-noetic-teleop-twist-keyboard如果你想让机器人在Gazebo里动起来这个包能让你用键盘发速度指令后面录bag用得上。没有的话sudo apt install ros-noetic-teleop-twist-keyboard即可。额外提一句网上很多人推荐的realsense_gazebo_pluginIntel官方出的一款在Gazebo里模拟D435i的插件在Noetic下编译要小心它依赖librealsense2和opencv的版本匹配编译报错概率不低。如果不想折腾完全可以用gazebo_ros自带的camera和imu插件搭一个“精神D435i”话题名和参数对齐到VINS-MONO的配置就行。我后面会给两种方案你先跑通简单版再考虑要不要上完整版。3. 仿真D435i的模型构建与VINS参数对齐3.1 用URDF搭出“带眼睛和耳朵”的机器人仿真里的机器人不需要多复杂一个底盘、一个相机、一个IMU就够。关键是这三者之间的坐标变换关系要和真实硬件一致因为VINS-MONO会用外参IMU和相机之间的位姿变换做姿态初始化错了整个系统都是歪的。我的URDF思路很简单base_link作为根节点下面挂两个子linkcamera_link和imu_link。相机和IMU的相对位置故意设成一个不太规整的数值比如相机在IMU前方10厘米、下方2厘米。这样做的目的是验证你对body_T_cam外参的理解——如果全都设成0偏移反而看不出你是不是真的理解了外参的作用。先定义base_link和imu_linklink namebase_link visual geometry box size0.2 0.15 0.08/ /geometry /visual collision geometry box size0.2 0.15 0.08/ /geometry /collision inertial mass value1.0/ inertia ixx0.01 ixy0.0 ixz0.0 iyy0.01 iyz0.0 izz0.01/ /inertial /link link nameimu_link/ joint namebase_imu_joint typefixed origin xyz0 0 0.05 rpy0 0 0/ parent linkbase_link/ child linkimu_link/ /joint这里把imu_link放在base_link上方5厘米。然后定义camera_link相对imu_link再做一个偏移link namecamera_link/ joint nameimu_camera_joint typefixed origin xyz0.1 0 -0.02 rpy0 0 0/ parent linkimu_link/ child linkcamera_link/ /joint这样一个简单的“头朝前、眼朝前”的机器人就出来了。rpy0 0 0表示相机光轴和IMU的Z轴方向对齐这也是最常见的安装方式。3.2 两种D435i仿真插件选择简单版和完整版简单版用gazebo_ros自带插件这是我最推荐新手先跑通的方案。不用装任何额外插件只需要在URDF里给camera_link和imu_link分别添加gazebo插件标签。相机的gazebo插件配置如下gazebo referencecamera_link sensor typecamera namecamera_color update_rate30.0/update_rate camera namecamera horizontal_fov1.21/horizontal_fov image width640/width height480/height formatR8G8B8/format /image clip near0.05/near far20/far /clip /camera plugin namecamera_plugin filenamelibgazebo_ros_camera.so ros namespace/camera/color/namespace remappingimage_raw:image_raw/remapping /ros camera_namecamera/camera_name image_topic_nameimage_raw/image_topic_name camera_info_topic_namecamera_info/camera_info_topic_name frame_namecamera_link/frame_name hack_baseline0.0/hack_baseline /plugin /sensor /gazebo这样默认会生成/camera/color/image_raw和/camera/color/camera_info两个话题正好对应VINS-MONO里realsense配置的image_topic。IMU的插件配置gazebo referenceimu_link sensor typeimu nameimu_sensor update_rate200.0/update_rate always_ontrue/always_on imu angular_velocity xnoise typegaussianmean0/meanstddev0.001/stddev/noise/x ynoise typegaussianmean0/meanstddev0.001/stddev/noise/y znoise typegaussianmean0/meanstddev0.001/stddev/noise/z /angular_velocity linear_acceleration xnoise typegaussianmean0/meanstddev0.01/stddev/noise/x ynoise typegaussianmean0/meanstddev0.01/stddev/noise/y znoise typegaussianmean0/meanstddev0.01/stddev/noise/z /linear_acceleration /imu plugin nameimu_plugin filenamelibgazebo_ros_imu.so ros namespace/camera/namespace remappingimu:imu/remapping /ros topic_nameimu/topic_name frame_nameimu_link/frame_name /plugin /sensor /gazebo这样会生成/camera/imu话题发布频率200Hz带高斯噪声。注意deg2rad的问题stddev0.001/stddev在角速度里单位是rad/s换算成度每秒约0.057度/s这个噪声水平比较接近真实D435i。完整版用realsense_gazebo_plugin如果你想要更真实的D435i仿真比如同时出深度图、红外图、自动发布相机内参那就用Intel的realsense_gazebo_plugin。这个插件的话题命名规范、参数模型都和真实D435i对齐直接跑roslaunch realsense2_camera rs_camera.launch风格的launch都能通。但它的坑在于源码编译依赖librealsense2。你得先装librealsense2的开发库再拉realsense-ros仓库编译。Noetic下我试过编译过程中如果遇到opencv4的C标准问题需要在CMakeLists.txt里加set(CMAKE_CXX_STANDARD 14)。插件编译完成后有一个示例launch会生成一台完整的D435i模型包含camera_link、camera_color_frame等坐标系话题也直接是/camera/color/image_raw、/camera/imu。我个人的建议是新手阶段先用简单版跑通闭环后再换完整版不然一次铺太多未知变量出了问题很难定位。3.3 核心VINS的realsense_d435i.yaml与内参计算VINS-MONO用一份YAML配置文件描述相机和IMU的全部参数。官方仓库里有现成的realsense_d435i.yaml你需要在它基础上改成和你仿真模型一致的值。先看相机内参怎么算。在Gazebo的camera插件里我用horizontal_fov1.21/horizontal_fov也就是水平视场角1.21弧度约69.4度。图像分辨率设的是640x480。内参焦距fx和fy可以用这个公式算fx width / (2 * tan(hfov / 2))代入数值hfov1.21tan(1.21/2) tan(0.605) ≈ 0.6927所以fx ≈ 640 / (2 * 0.6927) ≈ 461.9。由于像素是正方形的fy也约等于461.9。光心cx默认取图像中心320cy取240。在realsense_d435i.yaml里这么填imu_topic: /camera/imu image_topic: /camera/color/image_raw output_path: ~/output/ cam0: camera_model: pinhole dist_coeff: [0.0, 0.0, 0.0, 0.0] distortion_model: radtan intrinsics: [461.9, 461.9, 320, 240] resolution: [640, 480] fisheye: false这里dist_coeff全为0是因为仿真里我设置了无畸变镜头。现实中的D435i有轻微径向畸变但仿真中加畸变对算法验证没有额外价值反而会引入不必要的变量所以保持0即可。接着是IMU到相机的外参body_T_cam。这个参数表示的是从IMU坐标系到相机坐标系的变换。在URDF里camera_link相对imu_link的位置是xyz0.1 0 -0.02rpy为0所以平移部分就是[0.1, 0.0, -0.02]旋转是单位矩阵。在VINS里这样写body_T_cam: x: 0.1 y: 0.0 z: -0.02 q_w: 1.0 q_x: 0.0 q_y: 0.0 q_z: 0.0注意VINS-MONO的外参定义是T_body_cam表示的是相机坐标系下的坐标要变换到IMU坐标系。这里我URDF里camera在imu前方0.1米那相机光心在IMU坐标系的坐标是(0.1, 0, -0.02)和上面填的完全一致。如果填反了初始化阶段就会出现严重的尺度错误。3.4 TF树与body_T_cam必须一致的逻辑VINS-MONO在跑起来之前会订阅TF尤其是camera_link到imu_link的变换然后和配置里的body_T_cam做比对不一致会直接warning严重的会在初始化时产生野值。所以你的URDF里必须发布对应的静态TF。一种方式是写一个static_transform_publisher节点rosrun tf2_ros static_transform_publisher 0.1 0 -0.02 0 0 0 imu_link camera_link另一种是直接写进launch文件。我推荐后者因为启动时不用额外开终端。在launch文件的node段里加node pkgtf2_ros typestatic_transform_publisher nameimu_camera_tf args0.1 0 -0.02 0 0 0 imu_link camera_link/这里的平移量和yaml里的body_T_cam必须对应。这是整套系统里最容易“看起来没问题但实际全错”的地方。你如果发现VINS跑起来后轨迹整体往一边偏第一反应就是检查TF和外参是否一致。除了相机到IMU的TF机器人还需要base_link到imu_link的TF。这个可以用robot_state_publisher自动从URDF发布node pkgrobot_state_publisher typerobot_state_publisher namerobot_state_publisher param namepublish_frequency value50.0/ /node加上这个节点后TF树就是base_link - imu_link - camera_link层次清晰VINS需要的帧都能找到。4. 仿真实操从模型启动到bag回放再到轨迹评估4.1 启动Gazebo与模型加载模型文件准备好之后写一个launch把Gazebo和URDF一次性拉起来。我习惯把launch文件放在自己的功能包里但刚开始你也可以直接用urdf文件夹下的xacro/urdf文件跑。一个最简launch长这样launch param namerobot_description textfile$(find your_pkg)/urdf/vio_bot.urdf/ include file$(find gazebo_ros)/launch/empty_world.launch arg namepaused valuetrue/ arg nameuse_sim_time valuetrue/ arg namegui valuetrue/ arg nameheadless valuefalse/ arg namedebug valuefalse/ /include node pkggazebo_ros typespawn_model namespawn_model args-urdf -param robot_description -model vio_bot -z 0.01/ node pkgrobot_state_publisher typerobot_state_publisher namerobot_state_publisher param namepublish_frequency value50.0/ /node node pkgtf2_ros typestatic_transform_publisher nameimu_camera_tf args0.1 0 -0.02 0 0 0 imu_link camera_link/ /launch注意paused设成true这样Gazebo启动后世界是暂停的你可以先检查各模块是否都正常再按空格键开始仿真。这个习惯能省很多时间不然模型一加载就开始跑有问题你根本来不及看。启动后用rostopic list检查话题rostopic list | grep camera rostopic list | grep imu正常情况下至少能看到/camera/color/image_raw、/camera/color/camera_info、/camera/imu。再检查一下图像rqt_image_view /camera/color/image_raw如果能看到画面说明相机在正常工作。4.2 数据录制一份能直接被VINS吃掉的bag录bag是整套流程里最关键的一步。VINS-MONO对输入数据有几个硬性要求图像和IMU的时间戳要对得齐IMU频率要足够高至少100Hz200Hz更稳机器人启动时要有一段静止时间让IMU初始化。这些都要在录制阶段就提前规划好。我的录制流程是这样先在Gazebo里让模型静止1~2秒再启动录制。录制时同时录图像、IMU、camera_info和TFrosbag record -O vio_data.bag \ /camera/color/image_raw \ /camera/color/camera_info \ /camera/imu \ /tf \ /tf_static录制的运动时长建议30~60秒太短VINS来不及收敛太长后期处理麻烦。运动过程中尽量让机器人有平移、旋转、转弯、加减速不要一直沿直线匀速走否则VIO的尺度可观性会变差。怎么让机器人动起来最简单的办法是键盘遥控。在Gazebo模型里加一个差速驱动器插件然后终端跑roslaunch teleop_twist_keyboard teleop_twist_keyboard.launch按键控制/cmd_vel话题再让Gazebo里的差速插件读取这个速度。如果你不想给模型加差速插件还有一个更暴力的方法直接让模型在世界里做匀速直线运动的同时手动在Gazebo界面里拖拽模型。但拖拽的轨迹不平滑VINS很难跑好不推荐。录完bag后先回放一遍验证数据完整性rosbag info vio_data.bag重点看/camera/imu的消息频率和总帧数、/camera/color/image_raw的总帧数。如果IMU消息只有几千条而图像有几千帧频率比例不对VINS初始化会异常。4.3 跑通VINS-MONO并可视化运行VINS-MONO处理bag离线方式比实时跑要稳定得多推荐这种方式。第一步启动VINSroslaunch vins_estimator realsense_live.launch如果你的VINS-MONO仓库里realsense_live.launch加载的是realsense_d435i.yaml那直接跑就行。如果launch里写的是别的配置文件临时改一下或者直接在你的launch里指定rosparam file$(find vins_estimator)/../config/realsense/realsense_d435i.yaml commandload/第二步启动RViz可视化roslaunch vins_estimator vins_rviz.launchRViz打开后你会看到一条轨迹在慢慢延伸。如果轨迹没有出现检查RViz里的Fixed Frame是不是设置为world或者imu_link这个很多新手会卡住。RViz里的视图可以按住鼠标中键旋转视角、右键平移别傻盯着一个角度以为它没在动。第三步回放bag。在VINS和RViz都启动后另开终端rosbag play --clock vio_data.bag注意这里的--clock参数。由于Gazebo里录的bag用的是仿真时间回放时必须把仿真时间作为ROS的时间源不然VINS的时间戳全乱套。同时建议加上-r 0.5或-r 1.0控制播放速度如果机器性能一般-r 0.5能减少丢帧。回放结束后VINS会保存轨迹到output_path指定的目录默认是~/output/。里面会有vins_result_odom.csv和vins_result_pose.csv前者是里程计轨迹局部坐标后者是优化后的全局姿态。4.4 用evo对比groundtruth评估精度仿真最大的优势就是有groundtruth。Gazebo里模型的真实位姿可以通过/gazebo/model_states或者/gazebo/link_states拿到。录bag的时候建议把/gazebo/model_states也录进去。评估时先用evo把VINS轨迹和groundtruth转成TUM格式再做APE绝对位姿误差或RPE相对位姿误差分析。假设VINS输出的是vins_result_odom.csv转成TUMevo_traj tum ~/output/vins_result_odom.csv -pgroundtruth如果是从/gazebo/model_states里提取的格式通常是time x y z qx qy qz qw稍微处理一下就能用。如果懒得写提取脚本可以用evo的bag格式直接读evo_traj bag vio_data.bag /gazebo/model_states --save_as_tum然后做APE对比evo_ape tum gt_tum.txt vins_tum.txt -va --plot跑完会输出RMSE、mean、max等误差指标同时生成轨迹对比图。我第一次跑完看到RMSE在0.05米左右说明整个仿真链路是通的。如果你的RMSE动辄好几十别急着怀疑算法先检查外参、TF、时间戳这三样八成问题出在其中一个。5. 踩坑清单与排查速查5.1 时间戳错乱90%问题的源头在Gazebo仿真里时间戳错乱太常见了。现象就是VINS启动后一直waiting for image and imu或者跑起来轨迹乱飞。根源一般是两个一是回放bag时没用--clock导致ROS的use_sim_time和bag里的仿真时间对不上二是录bag时没有在launch里设置use_sim_time为true。Gazebo的launch必须指定arg nameuse_sim_time valuetrue/否则相机话题的时间戳是仿真时间而其他节点用的是墙钟时间两者完全不在一个坐标系里。排查时先打印一下话题时间和系统时间rostopic echo /camera/color/image_raw/header/stamp date %s.%N如果两个时间差着好几个数量级先统一时间源再往下查。5.2 VINS初始化失败/轨迹漂移严重VINS初始化失败最常见的提示是initialization failed或者no enough features to initialize。原因基本是这几类第一相机画面纹理太少。Gazebo默认的空世界是一个纯灰色地面没有特征点VINS根本找不到角点。解决办法是给世界加纹理或者放几个有图案的物体。最简单的是在Gazebo里放几个带纹理的方盒子或者给地面模型添加一张棋盘格贴图。我在空世界里放了几个彩色积木VINS初始化一下就成功了。第二robot启动时没有静止。VINS需要最开始的一段静止数据来估计IMU bias。如果你一启动Gazebo就开始录bag或者录bag时直接让机器人动起来了初始化多半失败。录bag前先暂停仿真让模型静置1~2秒再开始运动这是最稳的。第三相机频率太低。VINS-MONO虽然支持低频相机但20Hz以下明显吃力。Gazebo默认camera的update_rate如果没设置默认只有10Hz左右一定要手动设到30Hz。5.3 IMU噪声与相机频率的设计权衡Gazebo里的IMU插件默认是不带噪声的。如果直接跑VINS可能会因为IMU“太完美”而过于信任IMU一旦视觉短暂丢失轨迹瞬间飞掉。所以IMU的噪声参数务必要按3.2节那样设置。但噪声也不能设太大。stddev如果超过0.1VINS的初始化会变得很慢甚至失败。我实测下来角速度噪声0.001~0.005、加速度噪声0.01~0.05这个区间比较合适既接近真实传感器又不至于让VINS崩溃。相机的update_rate不建议超过30Hz。Gazebo里高帧率相机非常吃CPU你会发现录bag时CPU飙到100%、掉帧严重、时间戳对不齐。640x48030Hz对VINS来说完全够用再多是浪费。5.4 常见问题速查表问题现象可能原因解决办法VINS一直waiting for image and imu图像/IMU时间戳与系统时间不同步rosbag play加--clockGazebo launch设use_sim_timetrue初始化失败启动时无静止、画面无纹理、相机频率过低先静止2秒再运动场景加纹理相机update_rate设30Hz轨迹整体向一侧飘移TF与body_T_cam外参不一致检查static_transform_publisher和yaml的xyz/q保持一致轨迹尺度严重错误外参定义反了或IMU噪声过大核对body_T_cam变换方向IMU stddev调小回放bag时VINS跑得极慢播放速度太快或CPU不够rosbag play加-r 0.5降速仿真里相机画面全黑模型视角遮挡或clip范围太近检查camera_link位置clip near设0.05远设20编译VINS报Ceres错误Ceres 2.0不兼容源码装Ceres 1.145.5 最后分享几点我个人的经验整套流程跑下来最深的体会是仿真和实机的差距往往不在算法而在“数据质量”。Gazebo里造出来的数据如果时间戳乱、频率不对、外参错误VINS照样跑不起来——这一点和实机几乎没有区别。所以仿真不是“随便弄弄就行”你越把它当成一套真实的传感器系统来对待后面迁移到实机上就越顺利。另外一个经验是调参要有锚点。我先用无噪声IMU、无畸变相机、理想外参跑通一遍记录下轨迹RMSE作为基线然后逐步加噪声、加畸变、加外参误差观察每一项对结果的影响。这样做的好处是每次只引入一个变量问题定位非常快。很多人一上来就全部设成真实参数结果跑飞了也不知道是哪个环节出了问题。最后说一句关于机器性能的事。Gazebo本身是CPU密集型的仿真画质再高也对SLAM没什么帮助。跑这套流程四代以上i58GB内存基本够用。如果录bag时卡顿严重把Gazebo的GUI关掉只用headless模式录数据性能能提升不少。等数据录完再打开RViz回放体验会顺滑很多。这套仿真流程可以做的事情还有很多。后面你可以在URDF里加入双目相机两个模型做双目VIO对比也可以把Gazebo的IMU噪声模型换成Allan方差曲线驱动的方式更接近真实传感器特性。改动都不大但每一步都能帮你更深入地理解VIO系统里每个环节到底在扮演什么角色。
返回列表