LiDAR点云转换到大地坐标系——简单粗标定

news2024/10/6 1:46:44

目录

  • 一、LiDAR和IMU位姿标定
    • 1.1安装角度标定
    • 1.2安装位置标定
    • 1.3部分代码
  • 二、点云转换到当地水平坐标系
    • 2.1基本理论
      • 2.1.1坐标系
        • 2.1.1.1激光雷达
        • 2.1.1.2导航坐标系/当地水平坐标系/大地坐标系
      • 2.1.2惯性传感器原理
    • 2.2点云转换试验
      • 2.2.1试验场地
      • 2.2.2试验内容
      • 2.2.3点云变换效果


Windows 10(64bits) + VMware 16 Pro + Ubuntu 20.04 + noetic
速腾聚创激光雷达:RS-LIDAR-32
华测导航接收机:CGI-610


一、LiDAR和IMU位姿标定

为了获取更多的车前信息,将激光雷达向下倾斜一定角度安装。这样就会导致点云的Z坐标不对,前方离平台越远的点的Z轴坐标越大,甚至是个正值,这很不利于进行直通滤波等点云预处理。

1.1安装角度标定

在设计雷达安装结构的时候,设计了两个定位销,而且雷达是360°水平视角,暂不考虑点云yaw的安装误差,仅对pitch和roll进行标定。

下面介绍一种简单的半自动标定方法:

  1. 紧固连接激光雷达及其连接结构于平台小车
  2. 小车静置于走廊,且雷达前方朝着走廊方向
  3. 选择无动态物体和人的时刻,采集几秒钟激光点云
  4. 将bag格式的点云数据转换为pcd文件
  5. 选择50帧pcd文件并用cloudcompare合并为一个整体文件,帧数越多越精确
  6. 查看地面点云集中区域的点云坐标,以及两侧墙壁的点云坐标,使用pcl直通滤波提取出地面点
  7. RANSAC拟合出平面表达式,阈值越小越精确
  8. 根据拟合所得表达式可以得到平面法向量,求法向量和理想水平地面法向量(0,0,1)的旋转矩阵
  9. 使用这个旋转矩阵进行点云变换,查看标定效果

做以下几点解释:

  1. 位置变了当然还得重新标定,不如一次性固定好
  2. 合并50帧点云后,可以看出来激光雷达的测距误差,即形成一条条的点云带
  3. 好多算法都是利用迭代优化的方法,我认为选择50帧点云也是一种形式的优化
  4. 设置滤波范围时尽量滤除没有意义的点,减小误差
  5. 得到的是点云变换矩阵,而非坐标系变换矩阵

以下图片是滤波提取的走廊地面点云,白色是原始点云,青色是经旋转后的点云,第二张图是主视图视角,旋转的还可以。

在这里插入图片描述

在这里插入图片描述

1.2安装位置标定

标定完了相对姿态(旋转矩阵),还有激光雷达和组合导航接收机IMU之间的相对位置(平移向量)。
由1.1拟合出的平面方程,可以求出激光雷达中心到地面的垂直距离z,再量取组合导航接收机的安装高度,结合IMU在设备中的位置图纸,即可求出补偿量。
x和y的标定方法:

  1. 将小车侧边与墙壁平行,同样用RANSAC拟合平面方程,求得激光雷达Y坐标的补偿量
  2. 将小车后部贴着墙壁,且下倾的激光雷达可以扫到前方墙壁,用上述方法求X坐标的补偿量

最终将得到的xyz坐标放到变换矩阵的最后一列,与旋转矩阵组成一个4*4的变换矩阵。

1.3部分代码

直通滤波

pcl::PassThrough<pcl::PointXYZI> pass;
pass.setInputCloud (cloud_nonan);
pass.setFilterFieldName ("x");
pass.setFilterLimits (0.0, 8.0);
pass.setFilterLimitsNegative (false);
pass.filter (*cloud_passthrough);
pcl::io::savePCDFileASCII("../pass_x.pcd",*cloud_passthrough);

RANSAC分割

pcl::SACSegmentation<pcl::PointXYZI> plane_seg;
pcl::PointIndices::Ptr plane_inliers ( new pcl::PointIndices );
pcl::ModelCoefficients::Ptr plane_coefficients ( new pcl::ModelCoefficients );
plane_seg.setOptimizeCoefficients (true);
plane_seg.setModelType ( pcl::SACMODEL_PLANE );
plane_seg.setMethodType ( pcl::SAC_RANSAC );
plane_seg.setDistanceThreshold ( 0.005 );
plane_seg.setInputCloud ( cloud_passthrough );
plane_seg.segment (*plane_inliers, *plane_coefficients);

索引滤波

pcl::ExtractIndices<pcl::PointXYZI> extract;
extract.setInputCloud (cloud_passthrough);
extract.setIndices (plane_inliers);	
extract.setNegative (false);	
extract.filter (*cloud_ransac);
std::cerr << "PointCloud representing the planar component: " 
<< cloud_ransac->points.size() << " data points." << std::endl;

二、点云转换到当地水平坐标系

2.1基本理论

2.1.1坐标系

2.1.1.1激光雷达

激光雷达极坐标(有论文叫做瞬时激光束坐标系)和笛卡尔坐标映射,根据激光束的垂直角度、水平旋转角度和实测距离,将激光雷达极坐标投影到XYZ坐标系上。下图是速腾官方说明书中的说明:
在这里插入图片描述
注意:

  • 激光雷达的坐标虽然是X右,Y前,Z上符合右手坐标系,
  • 但是在ROS包里面,X 轴定义指向图 13 中的 Y 正方向, ROS 下面的 Y轴定义指向图 13 中的 X 负方向,同样符合右手坐标系,只是旋转了90度,即一个三维旋转矩阵。

2.1.1.2导航坐标系/当地水平坐标系/大地坐标系

常用的有北东地东北天两种。相对应的载体坐标系有前右下右前上两种。
本人感觉东北天坐标系舒服一点,同时选用右前上载体坐标系,按道理组合导航接收机要放在载体小车的中心,但是无法做到,就会产生“杆臂效应”,也就是配置组合导航接收机的那些值,这些数值的初始化和校准由接收机内算法实现,个人认为组合导航接收机的精度和价格主要就是差在这里的融合补偿算法。
东北天坐标系———— 右前上坐标系
 X轴:指东 ———— X轴:指向载体右侧
 Y轴:指北 ———— Y轴:指向载体前进方向
 Z轴:指天 ———— Z轴:指向上
都符合右手坐标系,拿出右手按照下图比划一下,没毛病。
坐标系xyz和手指对应关系记忆:XYZ——大拇指、食指、中指依次

2.1.2惯性传感器原理

IMU通过感知地球重力加速度和自转角速度,输出自身相对于大地坐标系的三轴角速度和角加速度,以及姿态更新推算出的自身姿态,通常用四元数表达。
具体地,可以看以下链接学习一下:
参考链接: 惯性导航学习笔记——惯性技术基础知识

姿态表示方法有欧拉角、四元数和旋转矩阵。
欧拉角:yaw、pitch和roll,存在万向节死锁,便于直观显示,不利于计算
四元数:超复数,很不直观,计算量和旋转矩阵一样,但是存储时只需要存四个数
有好多介绍这几种姿态表达方式的博客,这里只附上用Eigen实现的四元数和欧拉角的转换代码:
欧拉角转四元数

Eigen::Quaterniond q=
Eigen::AngleAxisd(yaw,Eigen::Vector3d::UnitZ())*
Eigen::AngleAxisd(roll,Eigen::Vector3d::UnitY())*
Eigen::AngleAxisd(pitch,Eigen::Vector3d::UnitX());

四元数转欧拉角

Eigen::Vector3d eulerAngle=quaternion.matrix().eulerAngles(2,1,0);

2.2点云转换试验

2.2.1试验场地

  • 室外,较为平坦的水平地面,采集数据集1
  • 室外,GNSS信号;小车前轮在平地,后轮放在台阶上,采集数据集2

2.2.2试验内容

  • 验证标定激光雷达安装姿态的变换矩阵
  • 验证组合导航接收机输出的姿态角,使点云转换到当地水平坐标系

2.2.3点云变换效果

数据集1:
白色是原始点云,青色是经旋转后的点云
在这里插入图片描述
在这里插入图片描述
数据集2:
白色是原始点云,青色是经激光雷达标定矩阵旋转后的点云
在这里插入图片描述
青色是经激光雷达标定矩阵旋转后的点云,橙色是IMU位姿变换后的点云
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

C语言日记 37 类的友元(1)(全局函数做友元)

根据36 类和对象-友元-全局函数做友元_哔哩哔哩_bilibili复现出如下代码&#xff1a; 一、&#xff08;只是&#xff09;访问&#xff08;公开&#xff09;内部成员&#xff1a; #include <iostream> using namespace std; class Building { private:int ws;//卧室 pub…

NewStarCTF 公开赛-web

week1 HTTP cookie 修改admin 源码发现key GET和POST传参即可 Head?Header! User-Agent: CTF Referer: ctf.com X-Forwarded-For: 127.0.0.1我真的会谢 信息泄露 robots.txt www.zip 源码 /.index.php.swp NotPHP 函数绕过 if(file_get_contents($_GET[data]) &qu…

数据备份一般有哪些方式,如何进行数据备份

在如今这个时代&#xff0c;数据于我们而言是特别重要的&#xff0c;一旦发生丢失&#xff0c;可能会带来严重后果&#xff0c;如果你也很苦恼如何保证这些重要数据的安全&#xff0c;小编建议一定要对重要数据进行备份&#xff0c;以防发生丢失的意外。数据备份一般有哪些方式…

设计一个缓存策略,动态缓存热点数据

&#x1f468;‍&#x1f4bb;个人主页&#xff1a; 才疏学浅的木子 &#x1f647;‍♂️ 本人也在学习阶段如若发现问题&#xff0c;请告知非常感谢 &#x1f647;‍♂️ &#x1f4d2; 本文来自专栏&#xff1a; 常见场景解决方案 &#x1f308; 每日一语&#xff1a;努力不一…

C语言 0 —— 信息在计算机中的表示

计算机的电路 由 逻辑门电路组成。一个逻辑门电路可以看成为一个开关&#xff0c;每个开关的状态是“开” 则 高电位 对应 1 或者 “关” 则 低电位 对应 0 &#xff0c; 那么1和0 刚刚好用二进制数来表示&#xff1a; 每个位只能取1和0 &#xff0c;称为 one 个 bit &#…

谈一谈关于Linux内核编译详解原理

前言&#xff1a;为什么要做这个启动盘&#xff0c;因为内核编译是很危险的&#xff0c;中间出了错系统则直接崩溃&#xff0c;然后就无法开机了&#xff0c;你将看到一个_在你的左上角闪烁。知道启动盘可以帮你从外置设备启动系统&#xff0c;能启动系统才能恢复系统。1.编译前…

Java 线程和反射---尚硅谷Java视频学习

1.Java程序在运行得时候默认就会产生一个进程2.这个进程会有一个主线程3.代码都在主线程中执行 线程的生命周期 线程的执行方式 public class Java02_Thread {public static void main(String[] args) throws Exception {// TODO 线程 - 执行方式&#xff08;串行&#xff0c…

ASP.NET Core 3.1系列(14)——分布式缓存Redis的使用

1、前言 前一篇博客介绍了ASP.NET Core中本地缓存MemoryCache的使用方法。相较于本地缓存&#xff0c;分布式缓存更加适合大多数项目应用场景&#xff0c;下面就来介绍一下如何在ASP.NET Core中对Redis缓存进行相关操作。 2、分布式缓存接口——IDistributedCache 对于分布式…

pytorch深度学习实战24

第二十四课 VGG网络 VGG是Oxford的Visual Geometry Group的组提出的&#xff08;大家应该能看出VGG名字的由来了&#xff09;。该网络是在ILSVRC 2014上的相关工作&#xff0c;主要工作是证明了增加网络的深度能够在一定程度上影响网络最终的性能。VGG有两种结构&#xff0c;分…

远程重启电脑

一、设置电脑允许自动启动 在远程计算机上编辑设置远程注册表 步骤1. 按“WindowsR”键调用运行对话框。输入“services.msc”并点击“确定”。 步骤2. 在“服务”窗口中&#xff0c;双击“RemoteRegistry”以检查其状态。 步骤3. 将启动类型更改为“自动”。 二、查找远程计…

SPARKSQL3.0-各阶段自定义扩展规则源码剖析

一、前言 这一节主要介绍如何自定义扩展各阶段规则 虽然spark内部提供了很多优化规则&#xff0c;但在实际工作中&#xff0c;经常因为业务需求需要自定义扩展优化器或解析器&#xff0c;故自己实现一个优化器才对sparksql有更深的理解 二、扩展范围 spark在扩展方便做的很…

vue.js毕业设计,基于vue.js前后端分离教室预约小程序系统设计与实现

功能介绍 【后台管理功能模块】 系统设置&#xff1a;设置关于我们、联系我们、加入我们、法律声明 广告管理&#xff1a;设置小程序首页轮播图广告和链接 留言列表&#xff1a;所有用户留言信息列表&#xff0c;支持删除 会员列表&#xff1a;查看所有注册会员信息&#xff0…

从零开始学前端:DOM、BOM、焦点事件 --- 今天你学习了吗?(JS:Day20)

从零开始学前端&#xff1a;程序猿小白也可以完全掌握&#xff01;—今天你学习了吗&#xff1f;&#xff08;JS&#xff09; 复习&#xff1a;从零开始学前端&#xff1a;CSSOM视图模式 — 今天你学习了吗&#xff1f;&#xff08;JS&#xff1a;Day19&#xff09; 文章目录从…

java8 (jdk 1.8) 新特性——Stream ApI

在java8 中&#xff0c;有两个最重要的改变&#xff0c;一个就是之前了解的Lmbda java8 (jdk 1.8) 新特性——Lambda ,还有一个就是Stream Api 1. 什么是Stream API 简单来说就是一个类库&#xff0c;里边有一些方法方便我们对集合数据进行操作&#xff0c;就好像使用 SQL 语…

Windows cmd 命令及Linux 环境下导入导入mysql 数据库

文章目录一、背景二、Windows cmd 导入导出mysql 数据库1.导出数据库三种方式&#xff08;导出数据库时不需要连接数据库&#xff09;2. 操作步骤2.导入数据库三、linux 环境下导入导出数据库一、背景 最近在本机上安装了一个WMware 虚拟机&#xff0c;需要从本机&#xff08;…

从三层架构说起,谈谈对历史项目的小改造

项目背景说明 最近接手一个 “老” 项目的需求修改&#xff0c;项目整体基于 .net core 3.1 平台&#xff0c;以传统的三层架构为基础构建。了解需求后&#xff0c;逐步对原有项目框架进行大概的了解&#xff0c;主要是熟悉一些框架的开发规范&#xff0c;基本工具类库的使用&…

寒亭5.8万亩盐碱稻 国稻种芯·中国水稻节:山东潍坊插秧期

寒亭5.8万亩盐碱稻 国稻种芯中国水稻节&#xff1a;山东潍坊插秧期 新京报讯&#xff08;记者赵利新&#xff09;新闻中国采编网 中国新闻采编网 谋定研究中国智库网 中国农民丰收节国际贸易促进会 国稻种芯中国水稻节 中国三农智库网-功能性农业农业大健康大会报道&#xff…

MMRotate 全面升级,新增 BoxType 设计

引言&#xff1a;大大降低水平框检测器改旋转框检测器的难度 MMRotate 是一个基于 PyTorch 和 MMDetection 的开源旋转框目标检测工具箱。它将目标检测从水平框扩展到旋转框&#xff0c;为场景文字、遥感影像、自动驾驶等领域的应用打下了基础&#xff0c;为学术界和产业界提供…

瞄准镜-第12届蓝桥杯Scratch选拔赛真题精选

[导读]&#xff1a;超平老师计划推出Scratch蓝桥杯真题解析100讲&#xff0c;这是超平老师解读Scratch蓝桥真题系列的第82讲。 蓝桥杯选拔赛每一届都要举行4~5次&#xff0c;和省赛、国赛相比&#xff0c;题目要简单不少&#xff0c;再加上篇幅有限&#xff0c;因此我精挑细选…

数据结构——单链表

一.简介 上一篇文章&#xff0c;我们介绍了线性表中的顺序表。 而顺序表拥有一些缺陷 1.空间不够时需要增容&#xff0c;增容需要付出代价 2.为避免重复扩容&#xff0c;我们进行指数扩容&#xff0c;可能会造成空间浪费 3.顺序表从开始位置连续存储&#xff0c;插入删除数…