|
@@ -0,0 +1,167 @@
|
|
|
+/*
|
|
|
+ * @Description: lidar calib tools
|
|
|
+ * @Author: yct
|
|
|
+ * @Date: 2021-09-02 11:02:00
|
|
|
+ * @LastEditTime: 2021-09-02 17:31:42
|
|
|
+ * @LastEditors: yct
|
|
|
+ */
|
|
|
+
|
|
|
+#include "../tool/point_tool.h"
|
|
|
+#include <Eigen/Core>
|
|
|
+#include <Eigen/Geometry>
|
|
|
+
|
|
|
+/**
|
|
|
+ * @description: used to find vlp16 intrinsic
|
|
|
+ * @param {*}
|
|
|
+ * @return {*}
|
|
|
+ * @param {Quaterniond} ground_quat quaternion to align lidar coords with ground plane
|
|
|
+ * @param {double} angle_z_axis rotation angle along z axis to align lidar coords with PLC coords
|
|
|
+ */
|
|
|
+void find_intrinsic(Eigen::Vector3d ground_norm, Eigen::Vector3d y_axis)
|
|
|
+{
|
|
|
+ Eigen::Quaterniond ground_quat = Eigen::Quaterniond::FromTwoVectors(ground_norm, Eigen::Vector3d::UnitZ());
|
|
|
+ Eigen::Quaterniond xy_plane_quat = Eigen::Quaterniond::FromTwoVectors(y_axis, Eigen::Vector3d::UnitY());
|
|
|
+ // std::cout << "y euler: " << xy_plane_quat.toRotationMatrix().eulerAngles(2, 1, 0).transpose() << std::endl;
|
|
|
+ Eigen::Matrix3d combined_rotation = ground_quat.toRotationMatrix() * xy_plane_quat.toRotationMatrix();
|
|
|
+ Eigen::Vector3d euler_angles = combined_rotation.eulerAngles(2, 1, 0);
|
|
|
+ for (size_t i = 0; i < euler_angles.rows(); i++)
|
|
|
+ {
|
|
|
+ if(fabs(euler_angles[i]) > M_PI_2)
|
|
|
+ {
|
|
|
+ if(euler_angles[i] > 0)
|
|
|
+ {
|
|
|
+ euler_angles[i] = euler_angles[i] - M_PI;
|
|
|
+ }else{
|
|
|
+ euler_angles[i] = M_PI + euler_angles[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ std::cout << "lidar intrinsic y p r: " << euler_angles.transpose()*180.0/M_PI << std::endl;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * @description: fit ground norm from two poles, then find y axis direction from front to back
|
|
|
+ * @return {*}
|
|
|
+ * @param {Ptr} front_barrier
|
|
|
+ * @param {Ptr} back_barrier
|
|
|
+ */
|
|
|
+void find_rotation_from_points(pcl::PointCloud<pcl::PointXYZ>::Ptr front_barrier, pcl::PointCloud<pcl::PointXYZ>::Ptr back_barrier,
|
|
|
+ Eigen::Vector3d &front_direction, Eigen::Vector3d &back_direction, Eigen::Vector3d &y_direction)
|
|
|
+{
|
|
|
+ pcl::PointCloud<pcl::PointXYZ>::Ptr direction_cloud = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>);
|
|
|
+
|
|
|
+ Eigen::Vector3d point_front, point_back;
|
|
|
+ // 根据点云拟合直线
|
|
|
+ //创建一个模型参数对象,用于记录拟合结果
|
|
|
+ pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients);
|
|
|
+ //inliers通过点云序号来记录模型内点
|
|
|
+ pcl::PointIndices::Ptr inliers(new pcl::PointIndices);
|
|
|
+ //创建一个分割对象
|
|
|
+ pcl::SACSegmentation<pcl::PointXYZ> seg;
|
|
|
+ //Optional,设置结果直线展示的点是分割掉的点还是分割剩下的点
|
|
|
+ seg.setOptimizeCoefficients(true);//flase 展示的是分割剩下的点
|
|
|
+ //Mandatory-设置目标几何形状
|
|
|
+ seg.setModelType(pcl::SACMODEL_LINE);
|
|
|
+ //分割方法:随机采样法
|
|
|
+ seg.setMethodType(pcl::SAC_RANSAC);
|
|
|
+ //设置误差容忍范围,也就是阈值
|
|
|
+ seg.setDistanceThreshold(0.01);
|
|
|
+ //输入点云
|
|
|
+ seg.setInputCloud(front_barrier);
|
|
|
+ //分割点云
|
|
|
+ seg.segment(*inliers, *coefficients);
|
|
|
+
|
|
|
+ if(coefficients->values.size() < 6)
|
|
|
+ {
|
|
|
+ std::cout << "fatal, front line coeff size not enough." << std::endl;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ point_front << coefficients->values[0], coefficients->values[1], coefficients->values[2];
|
|
|
+ front_direction << coefficients->values[3], coefficients->values[4], coefficients->values[5];
|
|
|
+ std::cout << "front direction: " << front_direction.transpose() << std::endl;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 保存前杆方向点云,调试用
|
|
|
+ for (size_t i = 0; i < 200; i++)
|
|
|
+ {
|
|
|
+ Eigen::Vector3d t_point = point_front + front_direction * 0.01 * i;
|
|
|
+ direction_cloud->push_back(pcl::PointXYZ(t_point.x(), t_point.y(), t_point.z()));
|
|
|
+ }
|
|
|
+
|
|
|
+ seg.setInputCloud(back_barrier);
|
|
|
+ seg.segment(*inliers, *coefficients);
|
|
|
+ if(coefficients->values.size() < 6)
|
|
|
+ {
|
|
|
+ std::cout << "fatal, back line coeff size not enough." << std::endl;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ point_back << coefficients->values[0], coefficients->values[1], coefficients->values[2];
|
|
|
+ back_direction << coefficients->values[3], coefficients->values[4], coefficients->values[5];
|
|
|
+ std::cout << "back direction: " << back_direction.transpose() << std::endl;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 保存后杆方向点云,调试用
|
|
|
+ for (size_t i = 0; i < 200; i++)
|
|
|
+ {
|
|
|
+ Eigen::Vector3d t_point = point_back + back_direction * 0.01 * i;
|
|
|
+ direction_cloud->push_back(pcl::PointXYZ(t_point.x(), t_point.y(), t_point.z()));
|
|
|
+ }
|
|
|
+
|
|
|
+ std::cout << "point front to back : " << point_front.transpose() << " -----> " << point_back.transpose() << std::endl;
|
|
|
+
|
|
|
+ // 注意y方向需要清除z分量
|
|
|
+ y_direction = point_front - point_back;
|
|
|
+ y_direction.z() = 0.0;
|
|
|
+ std::cout << "y direction: " << y_direction.transpose() << std::endl;
|
|
|
+
|
|
|
+ // 保存y方向点云,调试用
|
|
|
+ for (size_t i = 0; i < 200; i++)
|
|
|
+ {
|
|
|
+ Eigen::Vector3d t_point = point_back + y_direction * 0.01 * i;
|
|
|
+ direction_cloud->push_back(pcl::PointXYZ(t_point.x(), t_point.y(), t_point.z()));
|
|
|
+ }
|
|
|
+ save_cloud_txt(direction_cloud, "./direction_cloud.txt");
|
|
|
+}
|
|
|
+
|
|
|
+int main()
|
|
|
+{
|
|
|
+ // cloud 0 calib
|
|
|
+ pcl::PointCloud<pcl::PointXYZ>::Ptr t_front, t_back;
|
|
|
+ t_front = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>);
|
|
|
+ t_front->push_back(pcl::PointXYZ(3.158999919891,-0.365000009537,0.851999998093));
|
|
|
+ t_front->push_back(pcl::PointXYZ(3.158999919891,-0.363999992609,0.734000027180));
|
|
|
+ t_front->push_back(pcl::PointXYZ(3.154000043869,-0.363000005484,0.616999983788));
|
|
|
+ t_front->push_back(pcl::PointXYZ(3.154000043869,-0.361999988556,0.503000020981));
|
|
|
+ t_front->push_back(pcl::PointXYZ(3.155999898911,-0.361000001431,0.389999985695));
|
|
|
+ t_front->push_back(pcl::PointXYZ(3.140000104904,-0.368000000715,0.165999993682));
|
|
|
+ t_front->push_back(pcl::PointXYZ(3.148000001907,-0.368000000715,0.054999999702));
|
|
|
+ t_front->push_back(pcl::PointXYZ(3.142999887466,-0.363000005484,-0.054999999702));
|
|
|
+ t_back = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>);
|
|
|
+
|
|
|
+ Eigen::Vector3d front_direction, back_direction, y_direction;
|
|
|
+
|
|
|
+ if(!read_pointcloud("/home/youchen/extra_space/chutian/fence_wj/back_pole.txt", t_back))
|
|
|
+ {
|
|
|
+ std::cout << "read failed." << std::endl;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ // front direction: 0.0191082 0.002411 0.999815
|
|
|
+ // back direction: 0.0190939 0.0143106 0.999715
|
|
|
+ // 000.00802904 -0.000469358 00000.999968 0000.0897851
|
|
|
+ find_rotation_from_points(t_front, t_back, front_direction, back_direction, y_direction);
|
|
|
+ // 经过测试,地面法向量不适宜使用杆子获取,还是使用地面环点云拟合获得
|
|
|
+ // find_intrinsic((front_direction + back_direction) / 2.0, y_direction);
|
|
|
+ find_intrinsic(Eigen::Vector3d(0.00802904, -0.000469358, 0.999968), y_direction);
|
|
|
+
|
|
|
+
|
|
|
+ // cloud 1
|
|
|
+ // 000.0104679 -0.00822843 0000.999911 000.0986272
|
|
|
+ find_intrinsic(Eigen::Vector3d(0.0104679, -0.00822843, 0.999911), Eigen::Vector3d::UnitY());
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|