使用D435i+Avia跑Fast-LIVO

news2025/1/25 9:02:13

前言

最近Fast-LIVO开源了,之前看它的论文的时候发现效果很优秀,于是用实验室现有的设备尝试一下。这里主要记录一下使用不带外触发功能的D435i + Avia跑Fast-LIVO的过程,为了适配代码,主要修改了雷达的驱动、相机的launch文件、以及使用了一个外部的rospkg对相机的IMU坐标系做了转换。

Fast-LIVO源码仓库:https://github.com/hku-mars/FAST-LIVO

自己搭建的设备如下:
f21db741cdd16c395bb19e5f49a9ecf

文章目录

  • 前言
  • 编译Fast-LIVO
    • 安装Sophus库
    • 安装fmt库
    • 安装Vikit库
    • 下载Fast-LIVO源码
  • 连接实物
    • livox驱动修改
    • IMU坐标系转换
    • D435i launch文件修改
  • 运行

编译Fast-LIVO

安装Sophus库

git clone https://github.com/strasdat/Sophus.git
cd Sophus
git checkout a621ff

在make之前,先修改一个东西,因为这个版本的Sophus是有bug的,解决方法如下:

打开Sophus/sophus/so2.cpp文件,将代码修改如下

// SO2::SO2()
// {
//   unit_complex_.real() = 1.;
//   unit_complex_.imag() = 0.;
// }
 SO2::SO2() 
{ 
   unit_complex_.real(1.); 
   unit_complex_.imag(0.); 
 }

修改好之后再make

mkdir build && cd build && cmake ..
make
sudo make install

安装fmt库

git clone  https://github.com/fmtlib/fmt.git
cd fmt
mkdir build
cd build
cmake ..
sudo make install

安装Vikit库

mkdir fast-livo_ws
cd fast-livo_ws & mkdir src & cd src
git clone https://github.com/uzh-rpg/rpg_vikit.git

/src/rpg_vikit/vikit_common/CMakeLists.txt中添加

SET(Sophus_LIBRARIES libSophus.so)

否则待会编译的时候会报找不到一些库的错误

下载Fast-LIVO源码

git clone https://github.com/hku-mars/FAST-LIVO
cd ../
catkin_make

到这里就可以跑作者提供的数据集了,数据集下载可以在这里找到FAST-LIVO-Datasets

连接实物

这里我们使用自己的设备跑Fast-LIVO,我们的设备是realsense D435i + Livox Avia ,因为Fast-LIVO要求相机和IMU时钟同步,所以针对我们自己的设备需要做一些调整

image-20221127112950195

可以看到作者提供的数据集里面的各个传感器是严格时钟同步的

image-20221127113030400

livox驱动修改

livox原驱动中设置lidar、imu数据的时间戳均为基于雷达启动的时间开始的,而非基于系统的时间,而摄像头(包括本例中的RealSense)数据的时间戳通常是基于系统时间的。如果只是跑作者的数据集,便不需要改livox的ROS驱动;如果要跑自己的数据,就需要参考作者提供的修改方式进行处理。

  • livox官方驱动: https://github.com/Livox-SDK/livox_ros_driver
  • r3live作者提供的修改方案:https://github.com/ziv-lin/livox_ros_driver_for_R2LIVE

实际上我们可以直接使用r3live作者提供的修改方案,但是为了学习,我这里参考作者的方法自己下载了官方的驱动进行修改,我这里修改的这个版本和r3live作者提供的主要有如下区别:

  • 设置了宏定义编译,在CMakeLists.txt中通过应该宏定义开关可以选择编译官方原生的,还是我们自己修改过后的版本的
  • 仅修改雷达点云的时间戳。因为r3live作者他使用的是雷达内置的IMU,所以他把雷达的时间戳也改了,我这里没有使用雷达自带的IMU,所以没有改雷达IMU的时间戳以及它的重力尺度

其实主要是修改了livox_ros_driver中的lddc.cpp文件,修改方法如下:

1、在lddc.cpp文件开头,加入用于记录起始时间的相关变量

image-20221127125435256

2、在点云消息发布之前把时间戳修改

  • livox自定义消息类型

修改lddc.cpp中的PublishCustomPointcloud函数,在消息Publish之前加入如下片段

image-20221127130013126

  • PointCloud2消息类型

修改lddc.cpp中的PublishPointcloud2函数,在消息Publish之前加入如下片段

image-20221127125943787

  • CMakeLists.txt设置宏定义

添加宏定义变量如下:

image-20221127132344312

修改完成之后重新编译,之后启动我们自己修改的livox_ros_driver 即可

IMU坐标系转换

由于 Avia 雷达内置IMU,如果使用它自带的IMU,那么就不需要进行坐标调整,因为雷达内置的IMU的坐标系和雷达坐标系是一致的。

因为我们这里没有使用外部的时钟触发设备,所以我们这里选择使用相机内置的IMU,在相机的ros_warp中我们可以设置图像和IMU时钟同步,这样就可以免去使用一个外部时钟触发设备。但是,如果我们使用外部的IMU(如:D435i内置的IMU),相机中内置的IMU的坐标系是在相机坐标系下的,和雷达坐标系不一样,我们需要把IMU的坐标系转换到雷达坐标系下。

这里我们通过ROS中的imu_transformer功能包进行修改,这个包需要自行下载编译

  • imu_pipeline功能包集:https://github.com/ros-perception/imu_pipeline

对于imu_transformer功能包,注意修改启动文件ned_to_enu.launch中的静态变换target_frame字段。

image-20221127123410617

修改完成之后,重新编译即可。使用时,先启动imu_transformer的转换程序,再启动相机的ros_warp

image-20221127123943208

可以看到它把相机的IMU话题订阅了并重新转发了一次,转成了/trans/data,这个话题下的IMU数据和雷达坐标系是一致的

image-20221127124417913

后面在我们程序中可以直接订阅这个/trans/data话题即可

D435i launch文件修改

这里我自定义了一个launch文件如下:

<launch>

  <rosparam>
      /camera/motion_module/global_time_enabled: true
      /camera/rgb_camera/global_time_enabled: true
  </rosparam>

  <arg name="serial_no"           default=""/>
  <arg name="usb_port_id"         default=""/>
  <arg name="device_type"         default=""/>
  <arg name="json_file_path"      default=""/>
  <arg name="camera"              default="camera"/>
  <arg name="tf_prefix"           default="$(arg camera)"/>
  <arg name="external_manager"    default="false"/>
  <arg name="manager"             default="realsense2_camera_manager"/>
  <arg name="output"              default="screen"/>
  <arg name="respawn"              default="false"/>

  <arg name="fisheye_width"       default="-1"/>
  <arg name="fisheye_height"      default="-1"/>
  <arg name="enable_fisheye"      default="false"/>

  <arg name="depth_width"         default="640"/>
  <arg name="depth_height"        default="480"/>
  <arg name="enable_depth"        default="false"/>

  <arg name="confidence_width"    default="-1"/>
  <arg name="confidence_height"   default="-1"/>
  <arg name="enable_confidence"   default="false"/>
  <arg name="confidence_fps"      default="-1"/>

  <!-- 红外摄像头 -->
  <arg name="infra_width"         default="640"/>
  <arg name="infra_height"        default="480"/>
  <arg name="enable_infra"        default="false"/>
  <arg name="enable_infra1"       default="false"/>
  <arg name="enable_infra2"       default="false"/>
  <arg name="infra_rgb"           default="false"/>

  <!-- RGB摄像头 -->
  <arg name="color_width"         default="640"/>
  <arg name="color_height"        default="480"/>
  <arg name="enable_color"        default="true"/>

  <arg name="fisheye_fps"         default="-1"/>
  <arg name="depth_fps"           default="30"/>
  <arg name="infra_fps"           default="30"/>
  <arg name="color_fps"           default="30"/>

  <!-- 开启IMU -->
  <arg name="gyro_fps"            default="200"/>
  <arg name="accel_fps"           default="200"/>
  <arg name="enable_gyro"         default="true"/>
  <arg name="enable_accel"        default="true"/>

  <arg name="enable_pointcloud"         default="false"/>
  <arg name="pointcloud_texture_stream" default="RS2_STREAM_COLOR"/>
  <arg name="pointcloud_texture_index"  default="0"/>
  <arg name="allow_no_texture_points"   default="false"/>
  <arg name="ordered_pc"                default="false"/>

  <!-- 开启时间戳同步 -->
  <arg name="enable_sync"               default="true"/>
  <arg name="align_depth"               default="false"/>

  <arg name="publish_tf"                default="true"/>
  <arg name="tf_publish_rate"           default="0"/>

  <arg name="filters"                   default=""/>
  <arg name="clip_distance"             default="-2"/>
  <arg name="linear_accel_cov"          default="0.01"/>
  <arg name="initial_reset"             default="false"/>
  <arg name="reconnect_timeout"         default="6.0"/>
  <arg name="wait_for_device_timeout"   default="-1.0"/>

  <!-- 陀螺仪与加速度联合发布的时候的对齐方式,这里采用了线性插值的方式 -->
  <arg name="unite_imu_method"          default="linear_interpolation"/>
  <!-- <arg name="unite_imu_method"          default="copy"/> -->
  <arg name="topic_odom_in"             default="odom_in"/>
  <arg name="calib_odom_file"           default=""/>
  <arg name="publish_odom_tf"           default="true"/>

  <arg name="stereo_module/exposure/1"  default="7500"/>
  <arg name="stereo_module/gain/1"      default="16"/>
  <arg name="stereo_module/exposure/2"  default="1"/>
  <arg name="stereo_module/gain/2"      default="16"/>
  
  <include file="$(find imu_transformer)/launch/ned_to_enu.launch"/>

  <group ns="$(arg camera)">
    <include file="$(find realsense2_camera)/launch/includes/nodelet.launch.xml">
      <arg name="tf_prefix"                value="$(arg tf_prefix)"/>
      <arg name="external_manager"         value="$(arg external_manager)"/>
      <arg name="manager"                  value="$(arg manager)"/>
      <arg name="output"                   value="$(arg output)"/>
      <arg name="respawn"                  value="$(arg respawn)"/>
      <arg name="serial_no"                value="$(arg serial_no)"/>
      <arg name="usb_port_id"              value="$(arg usb_port_id)"/>
      <arg name="device_type"              value="$(arg device_type)"/>
      <arg name="json_file_path"           value="$(arg json_file_path)"/>

      <arg name="enable_pointcloud"        value="$(arg enable_pointcloud)"/>
      <arg name="pointcloud_texture_stream" value="$(arg pointcloud_texture_stream)"/>
      <arg name="pointcloud_texture_index"  value="$(arg pointcloud_texture_index)"/>
      <arg name="enable_sync"              value="$(arg enable_sync)"/>
      <arg name="align_depth"              value="$(arg align_depth)"/>

      <arg name="fisheye_width"            value="$(arg fisheye_width)"/>
      <arg name="fisheye_height"           value="$(arg fisheye_height)"/>
      <arg name="enable_fisheye"           value="$(arg enable_fisheye)"/>

      <arg name="depth_width"              value="$(arg depth_width)"/>
      <arg name="depth_height"             value="$(arg depth_height)"/>
      <arg name="enable_depth"             value="$(arg enable_depth)"/>

      <arg name="confidence_width"         value="$(arg confidence_width)"/>
      <arg name="confidence_height"        value="$(arg confidence_height)"/>
      <arg name="enable_confidence"        value="$(arg enable_confidence)"/>
      <arg name="confidence_fps"           value="$(arg confidence_fps)"/>

      <arg name="color_width"              value="$(arg color_width)"/>
      <arg name="color_height"             value="$(arg color_height)"/>
      <arg name="enable_color"             value="$(arg enable_color)"/>

      <arg name="infra_width"              value="$(arg infra_width)"/>
      <arg name="infra_height"             value="$(arg infra_height)"/>
      <arg name="enable_infra"             value="$(arg enable_infra)"/>
      <arg name="enable_infra1"            value="$(arg enable_infra1)"/>
      <arg name="enable_infra2"            value="$(arg enable_infra2)"/>
      <arg name="infra_rgb"                value="$(arg infra_rgb)"/>

      <arg name="fisheye_fps"              value="$(arg fisheye_fps)"/>
      <arg name="depth_fps"                value="$(arg depth_fps)"/>
      <arg name="infra_fps"                value="$(arg infra_fps)"/>
      <arg name="color_fps"                value="$(arg color_fps)"/>
      <arg name="gyro_fps"                 value="$(arg gyro_fps)"/>
      <arg name="accel_fps"                value="$(arg accel_fps)"/>
      <arg name="enable_gyro"              value="$(arg enable_gyro)"/>
      <arg name="enable_accel"             value="$(arg enable_accel)"/>

      <arg name="publish_tf"               value="$(arg publish_tf)"/>
      <arg name="tf_publish_rate"          value="$(arg tf_publish_rate)"/>

      <arg name="filters"                  value="$(arg filters)"/>
      <arg name="clip_distance"            value="$(arg clip_distance)"/>
      <arg name="linear_accel_cov"         value="$(arg linear_accel_cov)"/>
      <arg name="initial_reset"            value="$(arg initial_reset)"/>
      <arg name="reconnect_timeout"        value="$(arg reconnect_timeout)"/>
      <arg name="wait_for_device_timeout"  value="$(arg wait_for_device_timeout)"/>
      <arg name="unite_imu_method"         value="$(arg unite_imu_method)"/>
      <arg name="topic_odom_in"            value="$(arg topic_odom_in)"/>
      <arg name="calib_odom_file"          value="$(arg calib_odom_file)"/>
      <arg name="publish_odom_tf"          value="$(arg publish_odom_tf)"/>
      <arg name="stereo_module/exposure/1" value="$(arg stereo_module/exposure/1)"/>
      <arg name="stereo_module/gain/1"     value="$(arg stereo_module/gain/1)"/>
      <arg name="stereo_module/exposure/2" value="$(arg stereo_module/exposure/2)"/>
      <arg name="stereo_module/gain/2"     value="$(arg stereo_module/gain/2)"/>

      <arg name="allow_no_texture_points"  value="$(arg allow_no_texture_points)"/>
      <arg name="ordered_pc"               value="$(arg ordered_pc)"/>
    </include>
  </group>
</launch>

主要注意以下几个地方:

1、为了保证image和IMU的时钟同步需要添加下面几个参数

image-20221127134816375

2、开启IMU中的角速度和加速度联合发布,以及时间戳同步

image-20221127134917612

3、设置陀螺仪与加速度联合发布的时候的对齐方式

image-20221127134947367

运行

roslaunch realsense2_camera rs_livox.launch # 启动相机,这里我把imu_transform包也放到这个launch文件中启动了
roslaunch livox_ros_driver livox_lidar_msg.launch # 启动雷达
roslaunch fast_livo mapping_avi_we.launch # 启动fast_livo

建图效果如下,发现这个Fast-LIVO建图的时候比较卡,可能是作者还没优化好,针对低性能设备做优化也是一个重要的需求!

0

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/39996.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Flink】各种窗口的使用(处理时间窗口、事件时间窗口、窗口聚合窗口)

文章目录一 Flink 中的 Window1 Window&#xff08;1&#xff09;Window概述&#xff08;2&#xff09; Window类型a 滚动窗口&#xff08;Tumbling Windows&#xff09;b 滑动窗口&#xff08;Sliding Windows&#xff09;c 会话窗口&#xff08;Session Windows&#xff09;2…

ATJ2157内存篇【炬芯音频芯片】---sct语法

ATJ2157 sct语法公共知识篇BNF 简介Sct脚本Sct的作用Sct的语法规则1. 加载域描述(Loadd region descriptions)2. 执行域描述3. 输入节的描述ATJ2157平台使用的sctRO的等效写法ScatterAssert()函数LoadLength()函数LoadBase()函数ImageLimit()函数ATJ2157平台什么数据编译出来是…

CentOS 7.6上安装SqlServer2017

一、 安装 SQL Server 1、 安装 SQL Server 所需的python2 sudo alternatives --config python # If not configured, install python2 and openssl10 using the following commands: sudo yum install python2 sudo yum install compat-openssl10 # Configure python2 a…

Python自动化小技巧12——根据论文题目自动导出参考文献格式

案例背景 在写论文的时候&#xff0c;弄参考文献格式也很麻烦&#xff0c;不可能手打人名题目期刊名称年月日卷号页码这些&#xff0c;我们一般都是使用系统自动导出的格式复制粘贴就行。中国知网可以直接导出论文的格式&#xff0c;但是知网基本只有中文的论文&#xff0c;英…

pdf编辑器工具哪个好?好用的pdf编辑器一款就够!

pdf这类办公软件大家都很熟悉&#xff0c;不过pdf通常情况只能看不能编辑&#xff0c;这着实也很让人苦恼&#xff01;特别是现在国内大多都已居家办公&#xff0c;本来就颇多不便&#xff0c;如果没有一款好用的pdf编辑器工具&#xff0c;那么势必导致工作效率更为低下。 那么…

第十二章 哈希表与字符串哈希

第十二章 哈希表与字符串哈希一、哈希表1、什么是哈希表2、算法逻辑&#xff08;1&#xff09;哈希函数&#xff08;2&#xff09;冲突解决3、算法模板二、字符串哈希1、算法逻辑2、算法用途3、算法模板一、哈希表 1、什么是哈希表 在之前的文章中&#xff0c;我们学习过离散…

Spring-aop技术

前言 spring-aop技术是对oop(面向对象)的一个补充&#xff0c;其底层其实就是使用aspect动态代理进行实现的&#xff0c;本篇文章将大概讨论下aop的核心实现流程 相关的核心概念 刚开始&#xff0c;先介绍下aop中比较核心的一些对象和概念&#xff0c;只要理解了这些&#xff…

【通信】粒子群算法5G物联网云网络优化【含Matlab源码 2160期】

⛄一、简介 1 引言 5G技术被大众所熟知之后&#xff0c;边缘计算也成了各行业关注的重点。最初的边缘计算概念是在2014年提出&#xff0c;到了2016年就拓展到了接入边缘&#xff0c;目前基本被定义为靠近用户边缘的、包含多种技术的接入网络&#xff0c;能够提供比较稳定的IT业…

精华推荐 | 深入浅出学习透析Nginx服务器的基本原理和配置指南「Keepalive性能优化实战篇」

Linux系统&#xff1a;Centos 7 x64Nginx版本&#xff1a;1.11.5 Nginx 是一款面向性能设计的 HTTP 服务器&#xff0c;能反向代理 HTTP&#xff0c;HTTPS 和邮件相关(SMTP&#xff0c;POP3&#xff0c;IMAP)的协议链接。并且提供了负载均衡以及 HTTP 缓存。它的设计充分使用异…

拼搏一周!刷了1000道Java高频面试题喜提阿里offer,定级P7

今年较往年相比面试要难的多&#xff0c;大环境也是对于程序员的要求越来越高&#xff0c;环境是我们无法改变的&#xff0c;我们能改变的只有自己&#xff0c;月初我一好友&#xff0c;努力拼搏一周&#xff0c;刷完了这份阿里P8大牛整理的这1000道Java高频面试题笔记&#xf…

GitHub配置SSH Keys步骤

Git配置SSH Keys步骤 许多 Git 服务器都使用 SSH 公钥进行认证。 为了向 Git 服务器提供 SSH 公钥&#xff0c;如果某系统用户尚未拥有密钥&#xff0c;必须事先为其生成一份。 生成步骤如下&#xff1a; 1. 设置用户名和邮箱 在git命令行中对git进行全局设置 git config --…

八、CANdelaStudio入门-Session

本专栏将由浅入深的展开诊断实际开发与测试的数据库编辑,包含大量实际开发过程中的步骤、使用技巧与少量对Autosar标准的解读。希望能对大家有所帮助,与大家共同成长,早日成为一名车载诊断、通信全栈工程师。 本文介绍CANdelaStudio的Session概念,欢迎各位朋友订阅、评论,…

微信小程序:用户基本信息的采集

写作背景 在开发商城小程序时需要显示用户头像、昵称、手机号等信息以便后续业务的实现&#xff0c;因此需要通过微信小程序的API采集用户数据&#xff0c;由此进行总结。 在微信小程序中获取用户信息可以通过这几种方式获取&#xff0c;getUserInfo、getUserProfile、open-da…

基于多目标遗传算法的IEEE14节点系统分布式电源选址定容matlab程序

基于多目标遗传算法的IEEE14节点系统分布式电源选址定容matlab程序 摘 要: 为更好地解决分布式电源选址定容问题&#xff0c;提出一种改进的多目标遗传算法。之后&#xff0c;考虑投资成本、网损以及电压稳定性三因素建立了一个三目标的数学模型&#xff0c;并采用上述多目标遗…

javaSE -运算符,注释,关键字(复习)

一、运算符 1.1、算术运算符 基本四则运算符 - * / %规则比较简单, 值得注意的是除法和取模 1.1.1、/ 除法 int / int 结果还是 int, 需要使用 double 来计算 public static void main(String[] args) {int a 1;int b 2;System.out.println(a / b);}要得到小数那就要使…

python>>numpy包

章节内容 什么是NumPy模块和NumPy数组 创建数组 基本数据类型 数据可视化 索引和切片 副本和视图 目录 什么是NumPy模块和NumPy数组&#xff1f; 创建数组 基本数据类型 数据可视化 索引和切片 副本和视图 什么是NumPy模块和NumPy数组&#xff1f; NumPy数组 python对象 …

pyhon项目中,使用pip安装第三方插件之后,明明使用pip list可以查到,但是在项目中import时仍然找不到怎么办?

认识pip&#xff1a;python中的pip是用来安装python第三方库的工具&#xff0c;是安装python的时候自带的。 1.安装方式&#xff1a;pip install 第三方库名&#xff0c;比如&#xff1a;pip install selenium 2.查看已安装的所有第三方库&#xff1a;pip list 或 pip3 list &…

Spring Cloud OpenFeign - - - > 日志级别配置

项目源码地址&#xff1a;https://download.csdn.net/download/weixin_42950079/87168704 OpenFeign 有 4 种日志级别&#xff1a; NONE: 不记录任何日志&#xff0c;是OpenFeign默认日志级别&#xff08;性能最佳&#xff0c;适用于生产环境&#xff09;。BASIC: 仅记录请求方…

五魔方、二阶五魔方

五魔方 五魔方是正十二面体魔方&#xff0c;其实和三阶魔方很像&#xff0c;用层先法就能复原&#xff0c;而且公式一模一样。 十二个面分为6个浅色面和6个深色面&#xff0c;所以浅色和深色各有一个中心面。 先复原浅色中心面这一层&#xff1a; 再复原浅色面的5个棱块&…

【GlobalMapper精品教程】030:栅格重采样案例教程(航测DSM)

本文讲解Globalmapper栅格重采样操作方法。数据为配套实验数据包中的data030.rar,航测内业生成的DSM,分辨率为0.04米,现在需要将其重采样为0.05米。 文章目录 一、重采样简介二、重采样操作一、重采样简介 栅格/影像数据进行配准或纠正、投影等几何变换后,像元中心位置通常…