感谢开源!
想咨询下,我的激光雷达是禾赛的OT-128
我查看了工程源码,支持XT-32、AT-128
采集场景:结构化道路、乘用车、路口数据。车速约4~50km/h
我也查看了我自己的点云数据结构,为XYZIRT,对应的timestamp是每个点的绝对时间戳,我就直接适配到的xt32handle,但也加了一个根据相对时间对点云排序的代码:
void Preprocess::xt32_handler(const sensor_msgs::msg::PointCloud2::ConstSharedPtr &msg)
{
pl_surf.clear();
pl_corn.clear();
pl_full.clear();
pcl::PointCloud<xt32_ros::Point> pl_orig;
pcl::fromROSMsg(*msg, pl_orig);
int plsize = pl_orig.points.size();
pl_surf.reserve(plsize);
bool is_first[MAX_LINE_NUM];
double yaw_fp[MAX_LINE_NUM] = {0}; // yaw of first scan point
double omega_l = 3.61; // scan angular velocity
float yaw_last[MAX_LINE_NUM] = {0.0}; // yaw of last scan point
float time_last[MAX_LINE_NUM] = {0.0}; // last offset time
if (pl_orig.points[plsize - 1].timestamp > 0) { given_offset_time = true; }
else
{
given_offset_time = false;
memset(is_first, true, sizeof(is_first));
double yaw_first = atan2(pl_orig.points[0].y, pl_orig.points[0].x) * 57.29578;
double yaw_end = yaw_first;
int layer_first = pl_orig.points[0].ring;
for (uint i = plsize - 1; i > 0; i--)
{
if (pl_orig.points[i].ring == layer_first)
{
yaw_end = atan2(pl_orig.points[i].y, pl_orig.points[i].x) * 57.29578;
break;
}
}
}
double time_head = pl_orig.points[0].timestamp;
if (feature_enabled)
{
for (int i = 0; i < N_SCANS; i++)
{
pl_buff[i].clear();
pl_buff[i].reserve(plsize);
}
for (int i = 0; i < plsize; i++)
{
PointType added_pt;
added_pt.normal_x = 0;
added_pt.normal_y = 0;
added_pt.normal_z = 0;
int layer = pl_orig.points[i].ring;
if (layer >= N_SCANS) continue;
added_pt.x = pl_orig.points[i].x;
added_pt.y = pl_orig.points[i].y;
added_pt.z = pl_orig.points[i].z;
added_pt.intensity = pl_orig.points[i].intensity;
added_pt.curvature = pl_orig.points[i].timestamp / 1000.0; // units: ms
if (!given_offset_time)
{
double yaw_angle = atan2(added_pt.y, added_pt.x) * 57.2957;
if (is_first[layer])
{
// printf("layer: %d; is first: %d", layer, is_first[layer]);
yaw_fp[layer] = yaw_angle;
is_first[layer] = false;
added_pt.curvature = 0.0;
yaw_last[layer] = yaw_angle;
time_last[layer] = added_pt.curvature;
continue;
}
if (yaw_angle <= yaw_fp[layer]) { added_pt.curvature = (yaw_fp[layer] - yaw_angle) / omega_l; }
else { added_pt.curvature = (yaw_fp[layer] - yaw_angle + 360.0) / omega_l; }
if (added_pt.curvature < time_last[layer]) added_pt.curvature += 360.0 / omega_l;
yaw_last[layer] = yaw_angle;
time_last[layer] = added_pt.curvature;
}
pl_buff[layer].points.push_back(added_pt);
}
for (int j = 0; j < N_SCANS; j++)
{
PointCloudXYZI &pl = pl_buff[j];
int linesize = pl.size();
if (linesize < 2) continue;
vector<orgtype> &types = typess[j];
types.clear();
types.resize(linesize);
linesize--;
for (uint i = 0; i < linesize; i++)
{
types[i].range = sqrt(pl[i].x * pl[i].x + pl[i].y * pl[i].y);
vx = pl[i].x - pl[i + 1].x;
vy = pl[i].y - pl[i + 1].y;
vz = pl[i].z - pl[i + 1].z;
types[i].dista = vx * vx + vy * vy + vz * vz;
}
types[linesize].range = sqrt(pl[linesize].x * pl[linesize].x + pl[linesize].y * pl[linesize].y);
give_feature(pl, types);
}
}
else
{
for (int i = 0; i < plsize; i++)
{
PointType added_pt;
// cout<<"!!!!!!"<<i<<" "<<plsize<<endl;
added_pt.normal_x = 0;
added_pt.normal_y = 0;
added_pt.normal_z = 0;
added_pt.x = pl_orig.points[i].x;
added_pt.y = pl_orig.points[i].y;
added_pt.z = pl_orig.points[i].z;
added_pt.intensity = pl_orig.points[i].intensity;
added_pt.curvature = (pl_orig.points[i].timestamp - time_head) * 1000.f;
// printf("added_pt.curvature: %lf %lf \n", added_pt.curvature,
// pl_orig.points[i].timestamp);
// if(i==(plsize-1)) printf("index: %d layer: %d, yaw: %lf, offset-time:
// %lf, condition: %d\n", i, layer, yaw_angle, added_pt.curvature,
// prints);
if (i % point_filter_num == 0)
{
double r2 = added_pt.x * added_pt.x + added_pt.y * added_pt.y + added_pt.z * added_pt.z;
if (r2 > blind_sqr && r2 < 3600)
{
pl_surf.points.push_back(added_pt);
// printf("time mode: %d time: %d \n", given_offset_time,
// pl_orig.points[i].t);
}
}
}
auto comparePoints = [](const PointType& a, const PointType& b) -> bool
{
return a.curvature < b.curvature;
};
std::sort(pl_surf.points.begin(), pl_surf.points.end(), comparePoints);
}
// pub_func(pl_surf, pub_full, msg->header.stamp);
// pub_func(pl_surf, pub_surf, msg->header.stamp);
// pub_func(pl_surf, pub_corn, msg->header.stamp);
}
我运行lo模式,发现水平方向上的重影比较严重;想询问下,是否是我激光type没有适配正确导致的?
对应的config:请忽略config中线束的数字,因为我将原始的128按ring根据固定步长抽线为32线,取的0,4,8....
/**:
ros__parameters:
common:
img_topic: "/image"
lid_topic: "/hesai/ot32"
imu_topic: "/chcnav/devpvt"
img_en: 0 # 是否使用相机
lidar_en: 1 # 是否使用激光雷达
ros_driver_bug_fix: false # 是否修复ROS驱动器bug
extrin_calib: # 外参 lidar->imu
extrinsic_T: [0.864749, -0.00179501, 1.62208]
extrinsic_R: [0.00935207, -0.999951, -0.0033473,
0.999946, 0.00936742, -0.00459907,
0.00463019, -0.00330411, 0.999984]
Rcl: [-0.00387589,-0.999952, -0.00901998,
0.0026016, 0.00900993, -0.999956,
0.999989, -0.00389919, 0.00256655]
Pcl: [-0.0483692, -0.76351, -1.47161]
time_offset: # 时间偏移
imu_time_offset: 0.0 # 激光和imu之间的时间差
img_time_offset: 0.1 # 激光和相机之间的时间差
exposure_time_init: 0.0 # 曝光时间
preprocess: # 点云预处理
point_filter_num: 3 #这里其实是选点的间隔,每搁多少个点选一个点处理,作为系统的待处理点云
filter_size_surf: 0.1 # # 体素滤波设置 0.1*0.1*0.1
# 必须与 common_lib.h 中 LID_TYPE 一致:1=AVIA 2=VELO16 3=OUST64 4=L515 5=XT32 6=PANDAR128
# 设为 0 会走 preprocess 的 default 分支,不填充点云,易导致空点云段错误(SIGSEGV, exit -11)
lidar_type: 5
scan_line: 32
blind: 0.1
vio:
max_iterations: 5 # ESIKF的最大迭代次数
outlier_threshold: 1000 # 78 100 156 #100 200 500 700 infinite 每个像素块的阈值
img_point_cov: 100 # 100 1000 vio观测方程(光度误差)的协方差,也可以说是像素点噪声协方差
patch_size: 8 # 图像块的尺寸
patch_pyrimid_level: 4 # 金字塔层数
normal_en: true # 是否细化法向量,决定是否能够从单应阵获得仿射变换阵
raycast_en: false # 是否进行体素投射
inverse_composition_en: false # 是否进行逆补偿,SVO 采用的,Fast-livo2 默认不使用(逆补偿下的状态更新考虑的没有 Fast-livo2 全面)
exposure_estimate_en: true # 是否估计逆曝光时间
inv_expo_cov: 0.1 # 逆曝光时间估计的协方差
imu:
imu_en: false # 是否使用imu
imu_int_frame: 30 # 初始化所需要的 IMU 帧数(Fast-LIVO2 需要静止初始化)
acc_cov: 0.5 # 0.2 加速度计的方差
gyr_cov: 0.3 # 0.5 陀螺仪的方差
b_acc_cov: 0.0001 # 0.1 加速度计的偏置协方差
b_gyr_cov: 0.0001 # 0.1 陀螺仪的偏置协方差
lio:
max_iterations: 5 # ESIKF 中的更新迭代次数
dept_err: 0.02 # 激光雷达的深度误差
beam_err: 0.05 # 激光雷达的方向误差
min_eigen_value: 0.0025 # 0.005 # 平面奇异值分解后的最小特征上限(阈值)
voxel_size: 0.5 # 体素块的大小 0.5*0.5*0.5。有读者可能混淆 filter_size_surf 中设置的体素尺寸,具体就是:系统先将每帧点云用 0.1*0.1*0.1 的体素进行滤波,再用 0.5*0.5*0.5 的体素划分地图。
max_layer: 2 # 八叉树的最大层数
max_points_num: 50 # 每个节点的最大存点量
layer_init_num: [5, 5, 5, 5, 5] # 每个节点的最小存点量
local_map:
map_sliding_en: false # 是否进行滑动地图,当内存较小时使用
half_map_size: 100 # 地图边长的一半
sliding_thresh: 8.0 # 每 8 米滑动一次
uav:
imu_rate_odom: false
gravity_align_en: true
publish:
dense_map_en: false # 是否进行稠密建图
pub_effect_point_en: false # 是否发布有效点
pub_plane_en: false # 是否发布平面点
pub_scan_num: 1 # 每次发布的累积点云帧
blind_rgb_points: 0.0 # 盲区内的 RGB 点值为 0
evo:
seq_name: "CBD_Building_01"
pose_output_en: true
pcd_save:
pcd_save_en: true # 是否保存 PCD
colmap_output_en: false # need to set interval = -1 是否输出 COLMAP 格式
filter_size_pcd: 0.15 # 对 PCD 文件进行降采样
# interval: 每个 PCD 的累积帧数。
# -1: 仅在程序退出时保存一个 all_raw_points.pcd(需 Ctrl+C 正常退出);>0: 运行中按帧数保存 1.pcd, 2.pcd...
interval: -1 # 建议用 -1 并在退出时 Ctrl+C,否则可能因无 VIO 帧或点云为空而看不到文件
感谢开源!
想咨询下,我的激光雷达是禾赛的OT-128
我查看了工程源码,支持XT-32、AT-128
采集场景:结构化道路、乘用车、路口数据。车速约4~50km/h
我也查看了我自己的点云数据结构,为XYZIRT,对应的timestamp是每个点的绝对时间戳,我就直接适配到的xt32handle,但也加了一个根据相对时间对点云排序的代码:
我运行lo模式,发现水平方向上的重影比较严重;想询问下,是否是我激光type没有适配正确导致的?
对应的config:请忽略config中线束的数字,因为我将原始的128按ring根据固定步长抽线为32线,取的0,4,8....