镭神ch32外参标定&&Livox_automatic_calibration

文章讲述了使用ch32雷达进行外参标定的困难,尤其是因其视角有限。作者尝试了Livox雷达的数据处理和标定方法,遇到问题后通过理解坐标系变换和优化代码解决了匹配问题。但ch32雷达性能限制导致标定效果不佳。
摘要由CSDN通过智能技术生成

ch32雷达的参数如下:

前后左右面分别部署一个,需要标定出他们之间的外参

开源代码1:

GitHub - GDUT-Kyle/MULTI_LIDARs_CALIBRATE: A Simple Multi-Livox External Parameter Calibration MethodA Simple Multi-Livox External Parameter Calibration Method - GitHub - GDUT-Kyle/MULTI_LIDARs_CALIBRATE: A Simple Multi-Livox External Parameter Calibration Methodhttps://github.com/GDUT-Kyle/MULTI_LIDARs_CALIBRATE

使用一个360度的机械旋转式雷达,进行a-loam建图和一个Livox进行匹配,得到他们之间的外参,详细资料可以看里边的readme文件

这似乎不满足我的需求,我是希望能通过两两之间的固态雷达能够直接进行外参标定的

但是这个ch32雷达垂直视场角很小,扫到的东西非常有限,这种情况下想通过两个固态雷达完成标定,我觉得是很有难度的,雷达扫描的样本如下:

深度录屏_选择区域_20230804105751-CSDN直播https://live.csdn.net/v/316862

开源代码2:

https://github.com/Livox-SDK/Livox_automatic_calibration/blob/master/doc/readme-CN.mdhttps://github.com/Livox-SDK/Livox_automatic_calibration/blob/master/doc/readme-CN.md好像是需要将数据转成pcd格式来读取

首先先用作者提供的数据试一试


结果会报错如下:

Start building local map...
Loaded 1182 frames from Base-LiDAR
100% [||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||]
Saving submap...
Mapping done!
Start calibration...
Reading H-LiDAR map data...
Loaded 1085713 data points from H_LiDAR_Map.pcd
Loaded 1182 frames from Target-LiDAR
  0% [                                                            ]terminate called after throwing an instance of 'std::length_error'
  what():  vector::reserve
Aborted (core dumped)
Read 1 data

需要将 calibration.cpp里的  viewer_final->spinOnce(10); 注释掉才能运行成功

但是如此一来,就看不到 Target里的每帧点云与Base构建好的地图匹配情况了

问题1:

viewer_final->spinOnce(10);

这个窗口显示更新点云函数,有问题

报错:

terminate called after throwing an instance of 'std::length_error'

  what():  vector::reserve

非常奇怪,明明只是显示 match cloud 其他并没有影响

只能注释掉,但是注释掉后也不会显示点云,无法看到匹配情况

准备尝试下载pcl1.7版本

1.7版本太老了,下都下不下来

下了个1.8.1的试一试吧

这需要多版本共存了,可能会出问题,但是最终也没有安装多版本,太懒了!

解决:

通过阅读代码,我发现问题主要是 匹配点云(match cloud)部分,有问题

viewer_final->addPointCloud<pcl::PointXYZ>(H_LiDAR_Map, match_color, "match cloud");

H_LiDAR_Map 已经被添加到 target cloud,下面又加到"match cloud"

问题就出在"match cloud"这块,初始化问题,然后在下边的循环更新成第一帧的点云

因此我用一个空地图来初始化"match cloud"

pcl::PointCloud<pcl::PointXYZ>::Ptr Frame_Map(new pcl::PointCloud<pcl::PointXYZ>);

自己定义一个空地图

viewer_final->addPointCloud<pcl::PointXYZ>(Frame_Map, match_color, "match cloud");

用这个空的地图,初始化 匹配点云

此时不用在注释上边的代码,也能能跑通,而且还能看到每帧地图的匹配情况,拟合程度

遍历Target中的每一帧,并根地图中对应到的帧进行匹配,icp计算score

首先一定要明白坐标系变换和点云变换是有区别的

我们填写的Init_Matrix是base坐标系到Target坐标系的变换矩阵,也就是Target坐标系下的点云到Base坐标系点云的变换

Base坐标系到Target坐标系的变换:就是Target坐标系在Base坐标系下的位姿表示

以下图为例,左雷达为Base 前雷达为Target

现在得到的这个变换矩阵,既可以说是A坐标系到B坐标系的变换矩阵,有可以说是B坐标系的点云到A坐标系的点云的变换矩阵

由此可以得知想要知道两个坐标系的变换,只需要知道一个坐标系在另一个坐标系下的位姿表示就可以了

现在知道B在A下的坐标表示,得到了A坐标系到B坐标系的变换矩阵T,假如B坐标系有一点P(x,y),将其转化成A坐标系下的表示的P'(x',y')则 P'=T*P(x,y)

所以一定要分清楚 坐标系变换,点云变换这两个概念

代码标定部分大致流程:

*frames点云(用给的初始矩阵将该帧点云变换到base的world下了)

       |

*trans_output_cloud(根据处理的当前帧位姿找到对应在base下的该帧位姿,并将点云变换)

      |

*final_output_cloud(变换完成后可以从map找到该帧点云在map下的近邻点)

      |

neightbors_L(map中找到的最近邻点云)

     |

neightbors_trans(用T_Matrix_Inverse *neightbors_L  将点云换到world下 )

就可以用icp进行迭代了

icp.InputSource(trans_output_cloud)  源点云

icp.InputTarget(neighbors_trans)  目标点云

通过求解源点云到目标点云的微小变换,Tiny_T,score<1 就更新初始init_guess

当sore<0.1 就会得到一次calib的结果,以此类推,直到将Target中所有frames遍历完

calib.txt会将所有满足score<0.1的,结果保存出来

使用流程:

首先需要将bag转成pcd文件,并将各自的话题进行区分

rosrun pcl_ros bag_to_pcd <*.bag> <topic> <output_directory>

rosrun pcl_ros bag_to_pcd 2023-06-27-11-46-11.bag /minibus/left/lslidar_point_cloud new-11-46/left/

会将pcd文件以时间戳命名,还需要稍微转化一下

代码输入是100000.pcd依次往下命名

用一个脚本把名字转化一下(  resort.py 该脚本可以将文件夹下的pcd文件按照顺序重命名)

import os

# 输入文件夹路径
folder_path = './front'

# 获取文件列表并根据时间戳排序
file_list = os.listdir(folder_path)
file_list.sort()  # 这里假设文件名的时间戳部分是可以直接按字母顺序排序的

# 开始重新命名并按顺序命名
new_number = 100000
for old_name in file_list:
    # 提取旧的时间戳部分
    timestamp = old_name.split('.')[0]
    
    # 构建新文件名
    new_name = f"{new_number:06d}.pcd"
    new_number += 1
    
    # 构建文件的完整路径
    old_path = os.path.join(folder_path, old_name)
    new_path = os.path.join(folder_path, new_name)
    
    # 重命名文件
    os.rename(old_path, new_path)

print("重新命名完成!")

转化完成后,将雷达数据做好的pcd文件根据需求放进(Base-Frame,Target-Frame)

就可以运行起来辣!!

但是我在运行过程中发现了很多问题

由于lslidar_ch32垂直市场角太小,扫描到的信息很少,再加上我当时的录包的场景也太过开阔,所以标定的结果非常不好,因为如何我当前帧看到的是一堵墙的一部分,但是我的地图有墙的完整部分,那我这部分墙只要跟地图上的墙匹配上就可以了,虽然score<0.1了但是当前扫到的墙和匹配上的墙根本就不是正确的匹配,因此得到的结果也就不正确了

而且他会记录所有满足条件下得到的calib结果,如果你提供的pcd文件刚好是在得到不准确匹配的部分时结束的,那么将最后得到的结果作为最终结果,也是不科学的。

我有一个比较苯的方法

因为我可以看到每帧匹配在地图上的效果,所以我就看当我的当前帧遍历到 显著性物体时的拟合程度,如果拟合的挺好,那这个结果肯定是差不多的,但是像这样的帧也有很多个,具体以哪个结果为准,也成立一个难题,唉,为什么要有那么恶心的雷达,真心绝望了!

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值