lidar_calib_tools.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /*
  2. * @Description: lidar calib tools
  3. * @Author: yct
  4. * @Date: 2021-09-02 11:02:00
  5. * @LastEditTime: 2021-10-12 14:01:29
  6. * @LastEditors: yct
  7. */
  8. #include "../tool/point_tool.h"
  9. #include <Eigen/Core>
  10. #include <Eigen/Geometry>
  11. /**
  12. * @description: used to find vlp16 intrinsic
  13. * @param {*}
  14. * @return {*}
  15. * @param {Quaterniond} ground_quat quaternion to align lidar coords with ground plane
  16. * @param {double} angle_z_axis rotation angle along z axis to align lidar coords with PLC coords
  17. */
  18. void find_intrinsic(Eigen::Vector3d ground_norm, Eigen::Vector3d y_axis)
  19. {
  20. Eigen::Quaterniond ground_quat = Eigen::Quaterniond::FromTwoVectors(ground_norm, Eigen::Vector3d::UnitZ());
  21. Eigen::Quaterniond xy_plane_quat = Eigen::Quaterniond::FromTwoVectors(y_axis, Eigen::Vector3d::UnitY());
  22. // std::cout << "y euler: " << xy_plane_quat.toRotationMatrix().eulerAngles(2, 1, 0).transpose() << std::endl;
  23. Eigen::Matrix3d combined_rotation = ground_quat.toRotationMatrix() * xy_plane_quat.toRotationMatrix();
  24. Eigen::Vector3d euler_angles = combined_rotation.eulerAngles(2, 1, 0);
  25. for (size_t i = 0; i < euler_angles.rows(); i++)
  26. {
  27. if(fabs(euler_angles[i]) > M_PI_2)
  28. {
  29. if(euler_angles[i] > 0)
  30. {
  31. euler_angles[i] = euler_angles[i] - M_PI;
  32. }else{
  33. euler_angles[i] = M_PI + euler_angles[i];
  34. }
  35. }
  36. }
  37. if(euler_angles[0]<0)
  38. {
  39. euler_angles[0] = euler_angles[0] + M_PI;
  40. }
  41. std::cout << "lidar intrinsic y p r: " << euler_angles.transpose()*180.0/M_PI << std::endl;
  42. }
  43. /**
  44. * @description: fit ground norm from two poles, then find y axis direction from front to back
  45. * @return {*}
  46. * @param {Ptr} front_barrier
  47. * @param {Ptr} back_barrier
  48. */
  49. void find_rotation_from_points(pcl::PointCloud<pcl::PointXYZ>::Ptr front_barrier, pcl::PointCloud<pcl::PointXYZ>::Ptr back_barrier,
  50. Eigen::Vector3d &front_direction, Eigen::Vector3d &back_direction, Eigen::Vector3d &y_direction)
  51. {
  52. pcl::PointCloud<pcl::PointXYZ>::Ptr direction_cloud = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>);
  53. Eigen::Vector3d point_front, point_back;
  54. // 根据点云拟合直线
  55. //创建一个模型参数对象,用于记录拟合结果
  56. pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients);
  57. //inliers通过点云序号来记录模型内点
  58. pcl::PointIndices::Ptr inliers(new pcl::PointIndices);
  59. //创建一个分割对象
  60. pcl::SACSegmentation<pcl::PointXYZ> seg;
  61. //Optional,设置结果直线展示的点是分割掉的点还是分割剩下的点
  62. seg.setOptimizeCoefficients(true);//flase 展示的是分割剩下的点
  63. //Mandatory-设置目标几何形状
  64. seg.setModelType(pcl::SACMODEL_LINE);
  65. //分割方法:随机采样法
  66. seg.setMethodType(pcl::SAC_RANSAC);
  67. //设置误差容忍范围,也就是阈值
  68. seg.setDistanceThreshold(0.01);
  69. //输入点云
  70. seg.setInputCloud(front_barrier);
  71. //分割点云
  72. seg.segment(*inliers, *coefficients);
  73. if(coefficients->values.size() < 6)
  74. {
  75. std::cout << "fatal, front line coeff size not enough." << std::endl;
  76. return;
  77. }
  78. else
  79. {
  80. point_front << coefficients->values[0], coefficients->values[1], coefficients->values[2];
  81. front_direction << coefficients->values[3], coefficients->values[4], coefficients->values[5];
  82. std::cout << "front direction: " << front_direction.transpose() << std::endl;
  83. }
  84. // 保存前杆方向点云,调试用
  85. for (size_t i = 0; i < 200; i++)
  86. {
  87. Eigen::Vector3d t_point = point_front + front_direction * 0.01 * i;
  88. direction_cloud->push_back(pcl::PointXYZ(t_point.x(), t_point.y(), t_point.z()));
  89. }
  90. seg.setInputCloud(back_barrier);
  91. seg.segment(*inliers, *coefficients);
  92. if(coefficients->values.size() < 6)
  93. {
  94. std::cout << "fatal, back line coeff size not enough." << std::endl;
  95. return;
  96. }
  97. else
  98. {
  99. point_back << coefficients->values[0], coefficients->values[1], coefficients->values[2];
  100. back_direction << coefficients->values[3], coefficients->values[4], coefficients->values[5];
  101. std::cout << "back direction: " << back_direction.transpose() << std::endl;
  102. }
  103. // 保存后杆方向点云,调试用
  104. for (size_t i = 0; i < 200; i++)
  105. {
  106. Eigen::Vector3d t_point = point_back + back_direction * 0.01 * i;
  107. direction_cloud->push_back(pcl::PointXYZ(t_point.x(), t_point.y(), t_point.z()));
  108. }
  109. std::cout << "point front to back : " << point_front.transpose() << " -----> " << point_back.transpose() << std::endl;
  110. // 注意y方向需要清除z分量
  111. y_direction = point_front - point_back;
  112. y_direction.z() = 0.0;
  113. std::cout << "y direction: " << y_direction.transpose() << std::endl;
  114. // 保存y方向点云,调试用
  115. for (size_t i = 0; i < 200; i++)
  116. {
  117. Eigen::Vector3d t_point = point_back + y_direction * 0.01 * i;
  118. direction_cloud->push_back(pcl::PointXYZ(t_point.x(), t_point.y(), t_point.z()));
  119. }
  120. save_cloud_txt(direction_cloud, "./direction_cloud.txt");
  121. }
  122. int main()
  123. {
  124. std::cout << "------------------------ start calib lidar 4 ----------------------" << std::endl;
  125. pcl::PointCloud<pcl::PointXYZ>::Ptr t_front, t_back;
  126. t_front = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>);
  127. t_back = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>);
  128. if (!read_pointcloud("/home/youchen/extra_space/chutian/fence_wj/front_pole.txt", t_front))
  129. {
  130. std::cout << "read front failed." << std::endl;
  131. return -1;
  132. }
  133. if(!read_pointcloud("/home/youchen/extra_space/chutian/fence_wj/back_pole.txt", t_back))
  134. {
  135. std::cout << "read back failed." << std::endl;
  136. return -1;
  137. }
  138. Eigen::Vector3d front_direction, back_direction, y_direction;
  139. // front direction: 0.0191082 0.002411 0.999815
  140. // back direction: 0.0190939 0.0143106 0.999715
  141. // -0.000887596 00-0.0100556 00000.999949 0000.0650278
  142. find_rotation_from_points(t_front, t_back, front_direction, back_direction, y_direction);
  143. // 经过测试,地面法向量不适宜使用杆子获取,还是使用地面环点云拟合获得
  144. // find_intrinsic((front_direction + back_direction) / 2.0, y_direction);
  145. find_intrinsic(Eigen::Vector3d(-0.000887596, 0.0100556, 0.999949), y_direction);
  146. return 0;
  147. std::cout << "------------------------ start calib lidar 1 ----------------------" << std::endl;
  148. // cloud 1
  149. if (!read_pointcloud("/home/youchen/extra_space/chutian/fence_wj/front_pole2.txt", t_front))
  150. {
  151. std::cout << "read front failed." << std::endl;
  152. return -1;
  153. }
  154. if(!read_pointcloud("/home/youchen/extra_space/chutian/fence_wj/back_pole2.txt", t_back))
  155. {
  156. std::cout << "read back failed." << std::endl;
  157. return -1;
  158. }
  159. find_rotation_from_points(t_front, t_back, front_direction, back_direction, y_direction);
  160. // -0.00566995 0-0.0233422 0000.999712 000.0949598
  161. find_intrinsic(Eigen::Vector3d(-0.00566995,-0.0233422,0.999712), y_direction);
  162. return 0;
  163. }