Windows 10(64bits) + VMware 16 Pro + Ubuntu 20.04 + noetic
速腾聚创激光雷达:RS-LIDAR-32
华测导航接收机:CGI-610
为了获取更多的车前信息,将激光雷达向下倾斜一定角度安装。这样就会导致点云的Z坐标不对,前方离平台越远的点的Z轴坐标越大,甚至是个正值,这很不利于进行直通滤波等点云预处理。
在设计雷达安装结构的时候,设计了两个定位销,而且雷达是360°水平视角,暂不考虑点云yaw的安装误差,仅对pitch和roll进行标定。
下面介绍一种简单的半自动标定方法:
做以下几点解释:
以下图片是滤波提取的走廊地面点云,白色是原始点云,青色是经旋转后的点云,第二张图是主视图视角,旋转的还可以。


标定完了相对姿态(旋转矩阵),还有激光雷达和组合导航接收机IMU之间的相对位置(平移向量)。
由1.1拟合出的平面方程,可以求出激光雷达中心到地面的垂直距离z,再量取组合导航接收机的安装高度,结合IMU在设备中的位置图纸,即可求出补偿量。
x和y的标定方法:
最终将得到的xyz坐标放到变换矩阵的最后一列,与旋转矩阵组成一个4*4的变换矩阵。
直通滤波
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;
激光雷达极坐标(有论文叫做瞬时激光束坐标系)和笛卡尔坐标映射,根据激光束的垂直角度、水平旋转角度和实测距离,将激光雷达极坐标投影到XYZ坐标系上。下图是速腾官方说明书中的说明:

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

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);
数据集1:
白色是原始点云,青色是经旋转后的点云


数据集2:
白色是原始点云,青色是经激光雷达标定矩阵旋转后的点云

青色是经激光雷达标定矩阵旋转后的点云,橙色是IMU位姿变换后的点云

