无人驾驶,感知模块

今天在看一个无人驾驶的ROS项目

感知主要操作:分类,分割,检测,跟踪

从项目代码中了解到了许多无人驾驶方面的算法逻辑思想(这是我目前看到的,如有遗漏或错误还望指正

1.坐标转换

无人驾驶的汽车一般通过雷达、摄像头或两者同时运用来识别障碍物。这里就以雷达为例,无人车上拥有各种各样的传感器,每个传感器的安装位置和角度又不尽相同。对于传感器的提供商,开始并不知道传感器会以什么角度,安装在什么位置,因此只能根据传感器自身建立坐标系。传感器自身坐标系并不是全车的车身坐标系,无人驾驶系统是一个多传感器整合的系统,需要将不同位置的传感器数据统一到一个固定的坐标系——自车坐标系下。

所以要通过坐标转换统一到人为规定的坐标系中

通过平移,旋转操作将雷达坐标转换成车自身坐标。

平移:

平移步骤根据传感器安装位置和自车后轴的距离进行计算,仅仅是XYZ三个方向加减运算。

旋转:

绕轴旋转需要引入角度,不是简单的加减运算,两个坐标存在角度,也得需要带上角度

这只是大致的思想具体的转换思想运用到了欧拉转换,详细见下面网址

无人驾驶技术入门(十二)| 无人驾驶中的坐标转换 - 知乎 (zhihu.com)

2.体素滤波    

下面是我看项目的代码:

体素滤波的思想就是让点云数据点变少且扫描的图形不能改变

// 降采样 体素滤波      让点云变少且图形不变
void voxelFilter(const pcl::PointCloud<PointType>::Ptr input,
                 pcl::PointCloud<PointType>::Ptr &output)
{
  auto startTimePassThrough = std::chrono::steady_clock::now();
  pcl::VoxelGrid<PointType> sor;
  sor.setInputCloud(input);
  sor.setLeafSize(0.05f, 0.05f, 0.05f);                                  //设置体素大小                         // 剪枝?
  sor.filter(*output);                                                                   //执行滤波
  auto endTimePassThrough = std::chrono::steady_clock::now();
  auto elapsedTimePassThrough = std::chrono::duration_cast<std::chrono::microseconds>(endTimePassThrough - startTimePassThrough);                   //结束时间记录与耗时计算
  // std::cout << "VoxelGridFiltering took " << elapsedTimePassThrough.count() << " milliseconds" << std::endl;
  return;
}

3.地面分割 

地面分割采用RANSAC算法

具体的代码如下:

#include <utility.h>
#include <set>

bool point_cmp(PointType a, PointType b) // PointType表明XYZ点云库的一个点坐标
{
    return a.z < b.z;
}

// 地面分割采用RANSAC算法
void lidar_cluster::RANSAC(const pcl::PointCloud<PointType>::Ptr &cloud_filtered,
                           pcl::PointCloud<PointType>::Ptr &cloud_filtered_out, int maxIterations, float thre)
{

    pcl::SACSegmentation<PointType> seg; 
    pcl::PointIndices::Ptr inliers(new pcl::PointIndices);                         
    pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients);          
    pcl::PointCloud<PointType>::Ptr cloud_plane(new pcl::PointCloud<PointType>()); 

    seg.setOptimizeCoefficients(true);
    seg.setModelType(pcl::SACMODEL_PLANE); 
    seg.setMethodType(pcl::SAC_RANSAC);    /
    seg.setMaxIterations(maxIterations);
    seg.setDistanceThreshold(thre);

    // 从剩余的点云中分割最大平面组成部分
    seg.setInputCloud(cloud_filtered);    
    seg.segment(*inliers, *coefficients); 

    // Extract the planar inliers from the input cloud  从输入云中提取平面内层
    pcl::ExtractIndices<PointType> extract;
    extract.setInputCloud(cloud_filtered); 
    extract.setIndices(inliers);          
    extract.setNegative(false);          
    extract.filter(*cloud_plane); // 设置完之后执行filter才能实现
    std::cout << "PointCloud representing the planar component: " << cloud_plane->points.size() << " data points." << std::endl;

    extract.setNegative(true); 
    extract.filter(*cloud_filtered_out);

}
void lidar_cluster::ground_segmentation(const pcl::PointCloud<PointType>::Ptr &in_pc,
                                        pcl::PointCloud<PointType>::Ptr &g_not_ground_pc)
{

    g_not_ground_pc->points.clear();
    pcl::PointCloud<PointType> laserCloudIn, laserCloudIn_org;
    laserCloudIn = laserCloudIn_org = *in_pc; 
    PointType point;
    g_all_pc = laserCloudIn.makeShared(); 
    sort(laserCloudIn.points.begin(), laserCloudIn.end(), point_cmp); 
    
    pcl::PointCloud<PointType>::iterator it = laserCloudIn.points.begin();
    for (int i = 0; i < laserCloudIn.points.size(); i++)
    {
        if (laserCloudIn.points[i].z < -1 * sensor_height_) // 0.25
        {
            it++;
        }
        else
        {
            break;
        }
    }
    // remove below sensor_height_* - 1.5 points   拆下传感器下方的重量_*-1.5分
    laserCloudIn.points.erase(laserCloudIn.points.begin(), it);
    // 4. Extract init ground seeds. 提取初始地面种子
    extract_initial_seeds_(laserCloudIn); // 这个可能压根都没用上  数据都被清空了  不对  estimate_plane_用上了
    g_ground_pc = g_seeds_pc;             // 获取的地面种子存放到地面里面
    for (int i = 0; i < num_iter_; i++)
    {
        estimate_plane_();
        g_ground_pc->clear();
        g_not_ground_pc->clear();

        MatrixXf points(laserCloudIn_org.points.size(), 3);
        int j = 0;
        for (auto p : laserCloudIn_org.points)
        {
            points.row(j++) << p.x, p.y, p.z;
        }
        
        VectorXf result = points * normal_; // 平面的法线
        for (int r = 0; r < result.rows(); r++)
        {
            if (result[r] < th_dist_d_) 
           {
                g_ground_pc->points.push_back(laserCloudIn_org[r]);
            }
            else
            {
                g_not_ground_pc->points.push_back(laserCloudIn_org[r]);
            }
        }
    }
    g_all_pc->clear();
}

void lidar_cluster::extract_initial_seeds_(const pcl::PointCloud<PointType> &p_sorted)
{
    
    double sum = 0;
    int cnt = 0;
    for (int i = 0; i < p_sorted.points.size() && cnt < num_lpr_; i++)
    {
        sum += p_sorted.points[i].z;
        cnt++;
    }
    double lpr_height = cnt != 0 ? sum / cnt : 0; 
    g_seeds_pc->clear();
    
    for (int i = 0; i < p_sorted.points.size(); i++)
    {
        if (p_sorted.points[i].z < lpr_height + th_seeds_)
        {
            g_seeds_pc->points.push_back(p_sorted.points[i]);
        }
    }
    
}

void lidar_cluster::estimate_plane_(void)
{
    
    Eigen::Matrix3f cov;     
    Eigen::Vector4f pc_mean; 
    pcl::computeMeanAndCovarianceMatrix(*g_ground_pc, cov, pc_mean);
    
    JacobiSVD<MatrixXf> svd(cov, Eigen::DecompositionOptions::ComputeFullU);
    
    normal_ = (svd.matrixU().col(2));
    
    Eigen::Vector3f seeds_mean = pc_mean.head<3>();

    d_ = -(normal_.transpose() * seeds_mean)(0, 0); 
    th_dist_d_ = th_dist_ - d_;

}


其实有一些现在还没弄得太懂,弄懂了再说。(我发的东西只是我最近的领悟,类似于日常的总结,没多大帮助的话,还请见谅,谢谢!!!)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值