点云格式转换:将 ros PointCloud2格式数据转为livox CustomMsg格式

将 ros PointCloud2格式数据转为livox CustomMsg格式

  • 前言
  • 点云格式
    • PointCloud2 点云格式
    • livox CustomMsg 点云格式
  • 将 ros PointCloud2格式数据转为livox CustomMsg格式
  • 测试

前言

览沃科技有限公司(Livox)成立于2016年。为了革新激光雷达行业,Livox致力于提供高性能、低成本的激光雷达传感器。通过降低使用门槛和生产成本,Livox将激光雷达技术集成到更多产品和应用之中,从而为自动驾驶、智慧城市、测绘、移动机器人等行业带来创新性改变。Livox产品已销往包括美国、加拿大、中国、日本和欧盟在内的 26 个国家和地区。

面向智能移动机器人市场,Livox 推出最新一代 3D 激光雷达 Mid-360,开启混合固态激光雷达 360° 立体感知新篇章。凭借小巧体积,Mid-360 的安装布置更加灵活。同时,Mid-360 充分考虑了移动机器人对导航、避障等升维感知的需求,兼容室内外场景,赋能移动机器人进入空间智能感知新时代。 但是这款产品官网一直购买不到, 本篇博客 在 gazebo 中 可实现对该激光雷达的仿真 。

传统激光雷达普遍采用机械扫描方式,扫描路径随时间重复。而Livox 激光雷达采用了独特的扫描⽅式,扫描路径不会重复。在非重复扫描方式中,视场中被激光照射到的区域面积会随时间增大,这意味着视场覆盖率随时间推移而显著提高,可减小视场内物体被漏检的概率,有助于探测视场中的更多细节。
在这里插入图片描述
下图中给出了一个直观的例子。(a)图由于采用了非重复扫描方式,随着时间的积累,视场覆盖率逐渐升高。而(b)图,由于扫描每次都是重复的,视场覆盖率几乎没有提升。

gazebo中自带的laser插件是上图中b的方式,并不能代表livox的这种雷达。

livox 的仿真功能包(livox_laser_simulation)中 提供了 多种半固体的雷达仿真模型,可以在gazebo中进行该雷达的仿真与其扫描方式(非重复式扫描)点云发布。

但是经过测试发现 livox_laser_simulation 雷达仿真功能包发布的是 ros PointCloud2 点云格式数据。

而现在针对livox雷达的激光slam算法用的是 livox CustomMsg 点云格式数据,例如 Fast-Lio2 、Faster-Lio 、Lio-livox等。所以想在gazebo中仿真这些算法,需要将 ros PointCloud2格式数据转为livox CustomMsg格式 。

点云格式

PointCloud2 点云格式

PointCloud2 是ros的一种点云格式

具体官方数据 http://docs.ros.org/en/jade/api/sensor_msgs/html/msg/PointCloud2.html

std_msgs/Header header
  uint32 seq
  time stamp
  string frame_id
uint32 height
uint32 width
sensor_msgs/PointField[] fields
  uint8 INT8=1
  uint8 UINT8=2
  uint8 INT16=3
  uint8 UINT16=4
  uint8 INT32=5
  uint8 UINT32=6
  uint8 FLOAT32=7
  uint8 FLOAT64=8
  string name
  uint32 offset
  uint8 datatype
  uint32 count
bool is_bigendian
uint32 point_step
uint32 row_step
uint8[] data
bool is_dense

一个仿真的点云消息长这样

header:  // 点云的头信息
  seq: 963 //
  stamp:  // 时间戳
    secs: 1541143772
    nsecs: 912011000
  frame_id: "/camera_init"
height: 1   // If the cloud is unordered, height is 1  如果cloud 是无序的 height 是 1
width: 852578  //点云的长度
fields:  //  sensor_msgs/PointField[] fields 
  - 
    name: "x"
    offset: 0
    datatype: 7 	// 	uint8 INT8    = 1
			//	uint8 UINT8   = 2
			//	uint8 INT16   = 3
			//	uint8 UINT16  = 4
			//	uint8 INT32   = 5
			//	uint8 UINT32  = 6
			//	uint8 FLOAT32 = 7
			//	uint8 FLOAT64 = 8
    count: 1
  - 
    name: "y"
    offset: 4
    datatype: 7
    count: 1
  - 
    name: "z"
    offset: 8
    datatype: 7
    count: 1
  - 
    name: "intensity"
    offset: 16
    datatype: 7
    count: 1
is_bigendian: False
point_step: 32 // Length of a point in bytes 一个点占的比特数 
row_step: 27282496 // Length of a row in bytes 一行的长度占用的比特数
data: [ .......................................................... ] //  Actual point data, size is (row_step*height)
is_dense: True // 没有非法数据点

livox CustomMsg 点云格式

CustomMsg 是 livox雷达的 专有的点云格式,其格式如下:

Header header             # ROS standard message header
uint64 timebase          # The time of first point
uint32 point_num      # Total number of pointclouds
uint8 lidar_id               # Lidar device id number
uint8[3] rsvd                 # Reserved use
CustomPoint[] points    # Pointcloud data

上述自定义数据包中的自定义点云(CustomPoint)格式 :

uint32 offset_time      # offset time relative to the base time
float32 x               # X axis, unit:m
float32 y               # Y axis, unit:m
float32 z               # Z axis, unit:m
uint8 reflectivity      # reflectivity, 0~255
uint8 tag               # livox tag
uint8 line              # laser number in lidar
  • line
    最后一行line是激光雷达扫描的线数(livox avia为6线),从原始扫描点云可以看出,后期可以按线来对原始点处理、筛选
  • tag
    tag: 主要指示多回波信息及噪点信息。是一个二进制表达,标记信息的格式如下:bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0

bit7 bit6 保留位

bit5 bit4 回波序号 : 00: 第 0 个回波 01: 第 1 个回波 10: 第 2 个回波 11: 第 3 个回波 由于Livox Avia 采用同轴光路,即使外部无被测物体,其内部的光学系统也会产生一个回波,该回波记为第 0个回波。随后,若激光出射方向存在可被探测的物体,则最先返回系统的激光回波记为第 1 个回波,随后为第 2个回波,以此类推。如果被探测物体距离过近(例如 1.5 m),第 1 个回波将会融合到第 0 个回波里,该回波记为第 0 个回波。

bit3 bit2 基于强度的点属性: 00:正常点 01:回波能量噪点置信度高 10:回波能量噪点置信度中 11:保留位
基于回波能量强度判断采样点是否为噪点。通常情况下,激光光束受到类似灰尘、雨雾、雪等干扰产生的噪点的回波能量很小。目前按照回波能量强度大小将噪点置信度分为二档:01表示回波能量很弱,这类采样点有较高概率为噪点,例如灰尘点;10表示回波能量中等,该类采样点有中等概率为噪点,例如雨雾噪点。噪点置信度越低,说明该点是噪点的可能性越低。

bit1 bit0 基于空间位置的点属性 : 00:正常点 01:空间噪点置信度高 10:空间噪点置信度中 11:空间噪点置信度低
基于采样点的空间位置判断是否为噪点。例如,激光探测测距仪在测量前后两个距离十分相近的物体时,两个物体之间可能会产生拉丝状的噪点。目前按照不同的噪点置信度分为三档,噪点置信度越低,说明该点是噪点的可能性越低。

  • offset_time
    时间戳
    点云数据及 IMU 数据中都包含时间戳信息。

  • reflectivity
    目标反射率
    目标反射率:以 0 至 255 表示。其中 0 至 150 对应反射率介于 0 至 100% 的漫散射物体;而 151 至255 对应全反射物体。

  • x y z
    坐标信息:Livox Avia 的坐标信息可表示为直角坐标(x, y, z)或球坐标(r, θ, φ)。如果前方无被探测物体或者被探测物体超出量程范围(例如 600 m),在直角坐标系下,点云输出为(0,0,0);在球坐标系下,点云输出为(0,θ, φ)。

将 ros PointCloud2格式数据转为livox CustomMsg格式

为了使 livox_laser_simulation 功能包可以输出 CustomMsg 格式数据用于 fast-lio仿真,需要对其代码进行修改。主要是livox_laser_simulation/src/livox_points_plugin.cpp 这个文件。

重新编写这个函数

void LivoxPointsPlugin::OnNewLaserScans()

前面的这些可以不变

    if (rayShape) 
    {
        std::vector<std::pair<int, AviaRotateInfo>> points_pair;
        InitializeRays(points_pair, rayShape);
        rayShape->Update();

        msgs::Set(laserMsg.mutable_time(), world->SimTime());
        msgs::LaserScan *scan = laserMsg.mutable_scan();
        InitializeScan(scan);

        SendRosTf(parentEntity->WorldPose(), world->Name(), raySensor->ParentName());

        auto rayCount = RayCount();
        auto verticalRayCount = VerticalRayCount();
        auto angle_min = AngleMin().Radian();
        auto angle_incre = AngleResolution();
        auto verticle_min = VerticalAngleMin().Radian();
        auto verticle_incre = VerticalAngleResolution();

声明要发布的 custom格式的livox 点云

        livox_ros_driver::CustomMsg pp_livox;//声明要发布的 custom格式的livox 点云

赋值点云帧头

        // 赋值点云帧头
        pp_livox.header.stamp = ros::Time::now();//时间
        pp_livox.header.frame_id = "livox";//坐标系
        int count = 0;

用 high_resolution_clock 记录 起始时间

        boost::chrono::high_resolution_clock::time_point start_time = boost::chrono::high_resolution_clock::now();

遍历每个点

        for (auto &pair : points_pair)
        {

获得点的距离

            auto range = rayShape->GetRange(pair.first);

获得点的强度

            auto intensity = rayShape->GetRetro(pair.first);

最大最小距离限制

            if (range >= RangeMax()) {
                range = 0;
            } else if (range <= RangeMin()) {
                range = 0;
            }

将极坐标转为x y z

            auto rotate_info = pair.second;
            // 将极坐标转为x y  z 
            ignition::math::Quaterniond ray;
            ray.Euler(ignition::math::Vector3d(0.0, rotate_info.zenith, rotate_info.azimuth));
            auto axis = ray * ignition::math::Vector3d(1.0, 0.0, 0.0);
            auto point = range * axis;

声明一个 Custom 点

livox_ros_driver::CustomPoint p;//声明一个 Custom 点

赋值坐标

            p.x = point.X();
            p.y = point.Y();
            p.z = point.Z();

赋值强度

 p.reflectivity = intensity;

计算当前点时间到起始时间差

            boost::chrono::high_resolution_clock::time_point end_time = boost::chrono::high_resolution_clock::now();// 当前点时间
            boost::chrono::nanoseconds elapsed_time = boost::chrono::duration_cast<boost::chrono::nanoseconds>(end_time - start_time);
           

赋值偏移时间

p.offset_time = elapsed_time.count();

将当前点存入点云中

pp_livox.points.push_back(p);
// 计点个数的计数器加1
count ++;
}//结束遍历每个点

赋值点云中点的个数

        pp_livox.point_num = count;

发布点云

        livox_pub.publish(pp_livox);
        ros::spinOnce();
    }

测试

将功能包进行编译,需要引入 livox_ros_driver 功能包

find_package(catkin REQUIRED COMPONENTS
  roscpp
  tf
  livox_ros_driver  # 新增
)

包含头文件

#include <livox_ros_driver/CustomMsg.h>

完成编译后启动仿真环境
在这里插入图片描述
产看当前话题名
可以看到这个 /livox/lidar 话题名

查看这个话题信息

rostopic info /livox/lidar

在这里插入图片描述

jk-jone@JKKC:~$ rostopic info /livox/lidar
Type: livox_ros_driver/CustomMsg
Publishers:
/gazebo (http://JKKC:38793/)
Subscribers: None

消息类型改成了 livox_ros_driver/CustomMsg

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Docker及其使用思维导图

Docker的架构 构建分发运行镜像 Client&#xff08;客户端&#xff09;&#xff1a;是Docker的用户端&#xff0c;可以接受用户命令和配置标识&#xff0c;并与Docker daemon通信。Images&#xff08;镜像&#xff09;&#xff1a;是一个只读模板&#xff0c;含创建Docker容器…

JAVA对文档加密

当 Word 文档中包含无法公开的机密信息时&#xff0c;我们可以对其进行加密&#xff0c;使其在没有密码的情况下无法打开。本文将向您介绍如何使用 Spire.Doc for Java 加密 Word 文档和移除 Word 密码保护。 加密 Word 文档删除 Word 密码保护 安装 Spire.Doc for Java 首先…

Linux系统中如何开启和配置OpenGauss数据库的远程连接

文章目录 前言1. Linux 安装 openGauss2. Linux 安装cpolar3. 创建openGauss主节点端口号公网地址4. 远程连接openGauss5. 固定连接TCP公网地址6. 固定地址连接测试7. 结语 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍…

分布式 SQL 数据库与表格优化技术

分布式 SQL 数据库会将应用程序数据存储在多个节点上&#xff0c;从存储和计算的角度提高了可扩展性。这种分布意味着某些应用程序请求&#xff0c;包括 JOIN 操作和聚合&#xff0c;可能跨多个数据库节点&#xff0c;可能导致数据在网络中的传输。 为了减轻网络延迟对整体应用…

Echarts 热力图与折线图的结合

热力图与折线图结合使用(文末含源码) 这种需求并不多见&#xff0c;遇到后第一时间翻看了Echars官方文档&#xff0c;并没有发现类似的例子。于是自己动手合并了双轴&#xff0c;后发现折线图会被遮盖。经过排查发现了一个关键参数&#xff1a;visualMap的配置。这个配置在热力…

什么是客服RPA?客服RPA应用场景有哪些?客服RPA解决什么问题?

客服RPA&#xff0c;全称Robotic Process Automation&#xff0c;即机器人流程自动化。它是一种软件机器人&#xff0c;可以模拟人类在计算机上执行的任务&#xff0c;包括数据输入、网络浏览、电子邮件和文本消息发送等。 客服RPA适用于自动化处理客户咨询、投诉、退货等业务流…

wps左上角有绿色小三角的数字如何求和

1.这个状态是求和不了的&#xff0c;使用求和公式求出来的也是0 2.进行如下操作 3.转换好后 则可以求和成功了

C++ 学习系列 -- 模板 template

一 C 模板介绍&#xff1f; C 为什么引入模板&#xff1f; 我的理解是&#xff1a; C 引入模板的概念&#xff0c;是为了复用重复的代码&#xff0c;当某些代码除了操作的数据类型不同以外&#xff0c;其他逻辑全都相同&#xff0c;此时就适合采用模板的方式。 定义模板类或者…

2023.12.13 关于 MySQL 复杂查询

目录 聚合查询 聚合函数 group by 子句 执行流程图 联合查询 笛卡尔积 内连接 外连接 左外连接 右外连接 自连接 子查询 单行子查询 多行子查询 EXISTS 关键字 合并查询 union on 和 union 的区别 聚合查询 聚合函数 函数说明COUNT([DISTINCT] expr)返回查询到…

ClickHouse Kafka 引擎教程

如果您刚开始并且第一次设置 Kafka 和 ClickHouse 需要帮助怎么办&#xff1f;这篇文章也许会提供下帮助。 我们将通过一个端到端示例&#xff0c;使用 Kafka 引擎将数据从 Kafka 主题加载到 ClickHouse 表中。我们还将展示如何重置偏移量和重新加载数据&#xff0c;以及如何更…

数据库和数据仓库的区别

数据仓库是在数据库已知大量存在的前提下&#xff0c;为了进一步挖掘数据资源&#xff0c;为了决策需要产生的&#xff1b;数据仓库在设计的时候有意添加反范式设计&#xff0c;目的是提高查询效率 对比内容数据库数据仓库数据内容近期值历史的 归档的数据数据目标面向业务操作…

【数学建模】《实战数学建模:例题与讲解》第十三讲-相关分析(含Matlab代码)

【数学建模】《实战数学建模&#xff1a;例题与讲解》第十三讲-相关分析&#xff08;含Matlab代码&#xff09; 基本概念典型相关分析综合评价模型对应分析因子分析聚类分析 习题10.41. 题目要求2.解题过程3.程序 习题10.51. 题目要求2.解题过程3.程序 习题10.6&#xff08;1&a…

[原创][R语言]股票分析实战:周级别涨幅趋势的相关性

[简介]常用网名: 猪头三 出生日期: 1981.XX.XX QQ联系: 643439947 个人网站: 80x86汇编小站 https://www.x86asm.org 编程生涯: 2001年~至今[共22年] 职业生涯: 20年 开发语言: C/C、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python 开发工具: Visual Studio、De…

SQL Server数据库使用T-SQL语句简单填充

文章目录 操作步骤&#xff1a;1.新建数据库起名RGB2.新建表起名rgb3.添加三个列名4.点击新建查询5.填入以下T-SQL语句&#xff0c;点击执行&#xff08;F5&#xff09;6.刷新之后&#xff0c;查看数据 操作环境&#xff1a; win10 Microsoft SQL Server Management Studio 20…

Leetcode—237.删除链表中的节点【中等】

2023每日刷题&#xff08;六十&#xff09; Leetcode—237.删除链表中的节点 偷天换日实现代码 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode(int x) : val(x), next(NULL) {}* };*/ class Solution { pub…

动态内存管理,malloc和calloc以及realloc函数用法

目录 一.malloc函数的介绍 malloc的用法 举个例子 注意点 浅谈数据结构里的动态分配空间 二.calloc函数的介绍 三.realloc函数的介绍 四.柔性数组的介绍 为什么有些时候动态内存函数头文件是malloc.h,有些时候却是stdlib.h 一.malloc函数的介绍 malloc其实就是动态开辟…

npm ,yarn 更换使用国内镜像源,阿里源,清华大学源

在平时开发当中&#xff0c;我们经常会使用 Npm&#xff0c;yarn 来构建 web 项目。但是npm默认的源的服务器是在国外的&#xff0c;如果没有梯子的话。会感觉特别特别慢&#xff0c;所以&#xff0c;使用国内的源是非常有必要的。 在这里插入图片描述 Nnpm&#xff0c; yarn …

[极客大挑战 2019]BuyFlag1

打开网站&#xff1a; 右上角有个菜单 (menu) &#xff0c;先点一下&#xff0c;然后就进入了 pay.php 页面。 其中关键信息如下&#xff1a; ## FlagFlag need your 100000000 money### attentionIf you want to buy the FLAG:You must be a student from CUIT!!!You must…

云端赋能大湾区:华为云照亮数字化转型之路

编辑&#xff1a;阿冒 设计&#xff1a;沐由 在中国的经济版图上&#xff0c;大湾区是极其重要的增长引擎。这块富有活力和创新力的经济区域里&#xff0c;荟聚了大量的高新技术企业&#xff0c;以及一批创新孵化器和科研机构&#xff0c;产业升级和技术创新的氛围格外浓烈。 1…