Udacity 传感器融合笔记 (一)lidar
Udacity 传感器融合笔记 (一)lidar
udacity的传感器融合课程整体上分为四大部分,分别为lidar、radar、camera、以及传感器的融合。此篇记录下第一部分lidar学习过程中的一些笔记与心得,便于自己和广大开发者日后查看。博客内容为自己对课程的理解,如有问题,欢迎留言或私信讨论。
课程对lidar的介绍分为四部分:
1.对lidar传感器及其点云数据的介绍
激光雷达感测通过发送数千个激光信号为我们提供高分辨率数据。 这些激光从物体上反弹出来,返回到传感器,然后我们可以通过定时返回信号所需的时间来确定物体的距离。 我们还可以通过测量返回信号的强度来告诉一些有关撞击物体的信息。 每束激光都在红外光谱范围内,并以许多不同的角度发出,通常在360度范围内。 激光雷达传感器可为我们提供3D周围世界的高精度模型。
(1)激光雷达以不同角度发送数千条激光。
(2)激光被发射出来,被障碍物反射,然后使用接收器进行检测。
(3)根据发射和接收激光之间的时间差,计算距离。
(4)还接收激光强度值,并且可以将其用于评估激光反射离开的对象的材料属性。
lidar的数据是以点云的形式被记录的,所谓点云,就是每个测量点的激光信号的集合。通常以PCD文件格式记录,具体的数据格式为(X,Y,Z,I),其中(X,Y,Z)表示测量点的三维空间坐标。I表示接收激光的强度值。
可视化后的PCD,不同的颜色代表不同的激光强度。
为了方便处理点云数据,我们需要使用PCL点云处理的库,需自行下载安装
2.课程代码结构介绍
udacitiy课程的是提供代码的。其代码结构和功能如下:
- Top-level CMakelists.txt 配置文件
- readMe
- src:
render
box.h 定义了目标方形的结构体
render.h
render.cpp 定义了目标渲染如车道线等的函数
lidar.h 定义了传感器的相关功能以及形成pcd文件
environment.cpp 主函数、创建了pcl的Viewer窗口、进程和读取PCD文件
processPointClouds.h
processPointClouds.cpp 点云滤波、点云分割、点云聚类、box功能、读取保存pcd功能的实现。
接下来,将逐一功能进行记录,介绍。
3.代码解读
3.1 box.h
box.h文件定义了框定目标物体的长方体的长宽高等结构体,其结构体定义如下:
struct BoxQ
{Eigen::Vector3f bboxTransform; //旋转向量的定义Eigen::Quaternionf bboxQuaternion; //四元数的定义float cube_length; //长float cube_width; //宽float cube_height; //高
};//这个结构体是目标物体长方体的结构定义
struct Box
{float x_min; //所属一类点云中X方向最小的点坐标,以下六个量可以确定长方体的长宽高float y_min;float z_min;float x_max;float y_max;float z_max;
};
此图片中的红色长方体就是在box.h文件中所定义的结构体。
3.2 render.h
render用于pcd文件显示的渲染,render.h文件中定义了渲染相关的结构体和相关成员函数声明。
颜色的渲染
//自定义颜色结构体
struct Color
{float r, g, b; //使用RGB颜色通道Color(float setR, float setG, float setB): r(setR), g(setG), b(setB){}
};
位置的定义
//自定义位置结构
struct Vect3
{double x, y, z; //xyz三维空间坐标//构造函数Vect3(double setX, double setY, double setZ): x(setX), y(setY), z(setZ){}//重载Vect3类型的 + 运算并返回结果Vect3 operator+(const Vect3& vec){Vect3 result(x+vec.x,y+vec.y,z+vec.z);return result;}
};
枚举类型,视角的定义
enum CameraAngle
{XY, TopDown, Side, FPS //XY为 轴测图 TopDown 为俯视 side 为侧视图 Fps为前视图
};
汽车的定义
struct Car
{// units in metersVect3 position, dimensions; //位置、尺寸(长宽高)std::string name;Color color;//构造函数Car(Vect3 setPosition, Vect3 setDimensions, Color setColor, std::string setName): position(setPosition), dimensions(setDimensions), color(setColor), name(setName){}//渲染函数 ,用于汽车的渲染void render(pcl::visualization::PCLVisualizer::Ptr& viewer){// 汽车底部的渲染 viewer->addCube(position.x-dimensions.x/2, position.x+dimensions.x/2, position.y-dimensions.y/2, position.y+dimensions.y/2, position.z, position.z+dimensions.z*2/3, color.r, color.g, color.b, name); viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_REPRESENTATION, pcl::visualization::PCL_VISUALIZER_REPRESENTATION_SURFACE, name); viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, color.r, color.g, color.b, name);viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_OPACITY, 1.0, name);// 汽车顶部的渲染viewer->addCube(position.x-dimensions.x/4, position.x+dimensions.x/4, position.y-dimensions.y/2, position.y+dimensions.y/2, position.z+dimensions.z*2/3, position.z+dimensions.z, color.r, color.g, color.b, name+"Top"); viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_REPRESENTATION, pcl::visualization::PCL_VISUALIZER_REPRESENTATION_SURFACE, name+"Top"); viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, color.r, color.g, color.b, name+"Top");viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_OPACITY, 1.0, name+"Top");}
其他函数的声明,其函数定义在render.cpp中
//车道线定义及渲染函数
void renderHighway(pcl::visualization::PCLVisualizer::Ptr& viewer);
//lidar光束的渲染
void renderRays(pcl::visualization::PCLVisualizer::Ptr& viewer, const Vect3& origin, const pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud);
void clearRays(pcl::visualization::PCLVisualizer::Ptr& viewer);
//点云渲染
void renderPointCloud(pcl::visualization::PCLVisualizer::Ptr& viewer, const pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud, std::string name, Color color = Color(1,1,1));
void renderPointCloud(pcl::visualization::PCLVisualizer::Ptr& viewer, const pcl::PointCloud<pcl::PointXYZI>::Ptr& cloud, std::string name, Color color = Color(-1,-1,-1));
//目标物立方体的渲染
void renderBox(pcl::visualization::PCLVisualizer::Ptr& viewer, Box box, int id, Color color = Color(1,0,0), float opacity=1);
void renderBox(pcl::visualization::PCLVisualizer::Ptr& viewer, BoxQ box, int id, Color color = Color(1,0,0), float opacity=1);
3.3 render.cpp
车道线渲染
void renderHighway(pcl::visualization::PCLVisualizer::Ptr& viewer)
{// units in meters 长宽高double roadLength = 50.0;double roadWidth = 12.0;double roadHeight = 0.2;//渲染viewer->addCube(-roadLength/2, roadLength/2, -roadWidth/2, roadWidth/2, -roadHeight, 0, .2, .2, .2, "highwayPavement"); viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_REPRESENTATION, pcl::visualization::PCL_VISUALIZER_REPRESENTATION_SURFACE, "highwayPavement"); viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_COLOR, .2, .2, .2, "highwayPavement");viewer->setShapeRenderingProperties(pcl::visualization::PCL_VISUALIZER_OPACITY, 1.0, "highwayPavement");//添加车道线viewer->addLine(pcl::PointXYZ(-roadLength/2,-roadWidth/6, 0.01),pcl::PointXYZ(roadLength/2, -roadWidth/6, 0.01),1,1,0,"line1");viewer->addLine(pcl::PointXYZ(-roadLength/2, roadWidth/6, 0.01),pcl::PointXYZ(roadLength/2, roadWidth/6, 0.01),1,1,0,"line2");
}
其他各个函数定义类似,就不过多介绍。需要注意的是addCube、addLine、addPointCloud等都是PCL库自带的模型建立及渲染功能。详细功能可学习PCL点云库。
3.4lidar.h
lidar.h中定义了lidar传感器的相关结构体
激光线束及测量返回值的定义
const double pi = 3.1415;struct Ray //lidar 线束
{Vect3 origin; //原点,光束的起始位置,也就是lidar位置double resolution; //射线分辨率的大小,Vect3 direction; //xy平面与射线之间的方向角,例如0弧度沿xy平面,而pi / 2弧度沿法线Vect3 castPosition; //返回测量点double castDistance;//返回测量距离// parameters:// setOrigin: the starting position from where the ray is cast// horizontalAngle: the angle of direction the ray travels on the xy plane// verticalAngle: the angle of direction between xy plane and ray // for example 0 radians is along xy plane and pi/2 radians is stright up// resoultion: the magnitude of the ray's step, used for ray casting, the smaller the more accurate but the more expensive//构造函数Ray(Vect3 setOrigin, double horizontalAngle, double verticalAngle, double setResolution): origin(setOrigin), resolution(setResolution), direction(resolution*cos(verticalAngle)*cos(horizontalAngle), resolution*cos(verticalAngle)*sin(horizontalAngle),resolution*sin(verticalAngle)),castPosition(origin), castDistance(0){}void rayCast(const std::vector<Car>& cars, double minDistance, double maxDistance, pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud, double slopeAngle, double sderr){// reset raycastPosition = origin;castDistance = 0;bool collision = false;while(!collision && castDistance < maxDistance){castPosition = castPosition + direction;castDistance += resolution;// check if there is any collisions with ground slope 检测是否有地面返回值collision = (castPosition.z <= castPosition.x * tan(slopeAngle));// check if there is any collisions with cars 检查是否有车辆检测返回值if(!collision && castDistance < maxDistance){for(Car car : cars){collision |= car.checkCollision(castPosition);if(collision)break;}}}if((castDistance >= minDistance)&&(castDistance<=maxDistance)){// add noise based on standard deviation error 添加噪声 并加入cloud向量中double rx = ((double) rand() / (RAND_MAX));double ry = ((double) rand() / (RAND_MAX));double rz = ((double) rand() / (RAND_MAX));cloud->points.push_back(pcl::PointXYZ(castPosition.x+rx*sderr, castPosition.y+ry*sderr, castPosition.z+rz*sderr));}}};
lidar结构体的定义
struct Lidar
{std::vector<Ray> rays; //激光线束pcl::PointCloud<pcl::PointXYZ>::Ptr cloud; //点云储存向量std::vector<Car> cars; //车Vect3 position; //位置double groundSlope; //地面坡度double minDistance; //最小距离double maxDistance; //最大距离double resoultion; //分辨率double sderr; //标准误差 用于给测量点添加噪声//构造函数Lidar(std::vector<Car> setCars, double setGroundSlope): cloud(new pcl::PointCloud<pcl::PointXYZ>()), position(0,0,2.6){// TODO:: set minDistance to 5 to remove points from roof of ego car 将自小距离设置为5m 用于删除minDistance = 5;maxDistance = 50;resoultion = 0.2;// TODO:: set sderr to 0.2 to get more interesting pcd filessderr = 0.2;cars = setCars;groundSlope = setGroundSlope;// TODO:: increase number of layers to 8 to get higher resoultion pcd 将层数增加到8以获得更高的分辨率pcdint numLayers = 8;// the steepest vertical angledouble steepestAngle = 30.0*(-pi/180);double angleRange = 26.0*(pi/180);// TODO:: set to pi/64 to get higher resoultion pcd 设置为pi / 64以获取更高分辨率的pcddouble horizontalAngleInc = pi/64;double angleIncrement = angleRange/numLayers;for(double angleVertical = steepestAngle; angleVertical < steepestAngle+angleRange; angleVertical+=angleIncrement){for(double angle = 0; angle <= 2*pi; angle+=horizontalAngleInc){Ray ray(position,angle,angleVertical,resoultion);rays.push_back(ray);}}}//析构函数~Lidar(){// pcl uses boost smart pointers for cloud pointer so we don't have to worry about manually freeing the memory}pcl::PointCloud<pcl::PointXYZ>::Ptr scan(){cloud->points.clear(); //clear操作auto startTime = std::chrono::steady_clock::now();//开始时间设置for(Ray ray : rays)ray.rayCast(cars, minDistance, maxDistance, cloud, groundSlope, sderr);auto endTime = std::chrono::steady_clock::now();//结束时间设置auto elapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime);//飞行时间法,计算往返时间cout << "ray casting took " << elapsedTime.count() << " milliseconds" << endl;cloud->width = cloud->points.size();cloud->height = 1; // one dimensional unorganized point cloud datasetreturn cloud;}};
其程序运行结果可以用下图大致表示
红色为激光线束,蓝色为目标车辆渲染为蓝色,车道渲染为灰色,车道线渲染为黄色。
关于lidar如的得到测量点做如下简单说明:
lidar有其固有属性,激光雷达利用飞行时间计算物体的距离,发射激光脉冲时,发射时间和发射方向被记录,碰到障碍物返回的激光脉冲被接收时,记录采集和接收的时间。
由于激光雷达传感器的是一个特殊的球面坐标系值,让我们来复习该特殊的球面坐标系。球面坐标系在球面坐标系中,点由距离和两个角度定义。为了表示这两个角,我们使用方位角(Th)和极角(γ)约定。因此,点是由(r,τ,γ)定义的。
从上面的图解可以看出,方位角是在X轴上测量的X-Y平面,极坐标角是Z轴测量的Z-Y平面。
从上面的图,我们可以得到下列方程,将笛卡尔坐标转换为球面坐标。
可以使用下面的方程从球坐标导出笛卡尔坐标。
详细资料可转至:
lidar基础-坐标系及测量点
本篇记录了udacity传感器信息融合中的基础代码部分,主要包括,环境的渲染,lidar、car、position、ray等结构体的定义。
在接下来中会继续介绍lidar点云数据的一些处理,重点在
processPointClouds.h
processPointClouds.cpp
两个文件,包含了点云滤波、RANSAC的点云分割,聚类等核心部分。
文中有什么问题,欢迎大家评论区交流指正!
Udacity 传感器融合笔记 (一)lidar相关推荐
- Udacity传感器融合笔记(三)Camera与lidar数据融合-(上)
之前两篇文章记录了lidar感知相关笔记,这篇记录视觉感知以及视觉数据和lidar数据的简单融合.直接上干货.文章主要记录两部分: 1.lidar数据的处理 2.camera与lidar数据的融合 关 ...
- 「Self-driving: Perception」多传感器融合之Camera、Lidar 雷达融合
1. 硬件介绍 1.1 Camera 1.2 Lidar 2. 传感器同步 2.1 时间同步 2.2 空间同步 3. 传感器融合 3.1 融合基础 3.1.1 传统融合 3.1.2 深度学习融合 3. ...
- 领域最全!多传感器融合方法综述!(Camera/Lidar/Radar等多源异构数据)
点击下方卡片,关注"自动驾驶之心"公众号 ADAS巨卷干货,即可获取 点击进入→自动驾驶之心技术交流群 后台回复[ECCV2022]获取ECCV2022所有自动驾驶方向论文! 自动 ...
- 笔记《基于无人驾驶方程式赛车的传感器融合目标检测算法研究及实现》
论文结构 关键字:无人驾驶方程式赛车,相机,激光雷达,目标检测,传感器融合 一.绪论 1. 感知技术研究现状 1.1.1 基于相机的目标检测技术研究现状 1.1.2 基于激光雷达的目标检测技术研究现状 ...
- 论文阅读:PMF基于视觉感知的多传感器融合点云语义分割Perception-Aware Multi-Sensor Fusion for 3D LiDAR Semantic Segmentation
题目:Perception-Aware Multi-Sensor Fusion for 3D LiDAR Semantic Segmentation 中文:用于 3D LiDAR 语义分割的多传感器感 ...
- 论文笔记——基于多传感器融合的即时定位与地图构建方法研究
1.多传感器融合SLAM不完全分类: 视觉和IMU融合VIO: 基于滤波的VIO:采用EKF进行视觉信息和IMU数据进行数据融合.预测和更新.经典算法:MSCKF.ROVIO 基于优化的VIO:对视觉 ...
- 多传感器融合课程笔记------多传感器融合之绪论
多传感器融合之绪论 一.传感器类型 摄像头 激光雷达 毫米波雷达 超声波雷达 IMU GNSS和RTK 1. 摄像头 摄像头根据安装位置,可以分为前视.侧视.后视.内置.环视等. 摄像头相关参数介绍: ...
- 自动驾驶——多传感器融合的学习笔记
1 多传感器融合算法的选择--使用EKF 因为Apollo使用的是EKF,所以我们也用EKF,(具体的资料可以查看issues_10957) <无人驾驶>课程的贾老师推荐的论文<EK ...
- 论文笔记——基于因子图消元优化的多传感器融合定位算法
创新点: 为了提高抗干扰性和容错能力,在链式因子图模型中加入滑动窗口用于保留窗口内历史状态信息:同时为了避免高维矩阵运算,引入消元算法将因子图转化为贝叶斯网络,依次边缘化历史状态,实现矩阵降维. 提出 ...
- 多传感器信息融合笔记
随着机器人技术的不断发展,机器人的应用领域和功能有了极大的拓展和提高.智能化已成为机器人技术的发展趋势,而传感器技术则是实现机器人智能化的基础之一.由于单一传感器获得的信息非常有限,而且,还要受到自身 ...
最新文章
- UVA 10954 Add All
- 第一章 GuassDB数据库介绍
- 驱动编程中的头文件与内核源码的关系
- 【Boost】boost库中thread多线程详解6——线程组简单例子
- 【POJ - 3273 】Monthly Expense (二分,最小最大值)
- 开发手记之实现web.config的快速配置(转载)
- python经典教程游戏_使用pygame制作经典小游戏:五子棋
- python中标点符号大全_Python处理中文标点符号大集合
- 利用matlab的帮助功能分别查询inv,MATLAB实验报告第一章..doc
- mybatis ——xml方式与动态sql
- 问题 G: [入门OJ]差(NHOI2015xj6)
- LA4487 加权并查集
- 电脑打开html不显示图片,网页不显示图片,教您网页不显示图片怎么解决
- 海尔简爱s11怎么进入bios_海尔笔记本如何进入BIOS设置_海尔笔记本进入bios方法...
- cl.3hh.win/index.php,windows 系统下 安装 gitblit 教程
- 郭敬明:7亿级产品经理的五大绝招
- VMware vSphere 7.0 Update 2 发布 - 数据中心虚拟化和 Kubernetes 云原生应用引擎
- “Word无法打开此文档模板”的解决办法
- ubuntu 16.04 清理内存空间的方法总结
- 简易日历(Java)
热门文章
- 计算机网络共享文件密码,如何给局域网共享文件夹设置访问密码
- 正则表达式 边界符 量词符 敏感词替换
- 龙哥库他发matlab程序,编程实现四阶龙哥库塔法解方程
- 爬取豆瓣电影排行榜(评分)
- alt 工程开发时,atl向导报IE脚本错误问题的处理
- UML结构建模图———复合结构图
- 使用 FireDAC的 TFDConnection, TFDQuery 最初只能显示50条记录,TDateSet.RecordCount总是获得50的解决方法。
- BiTree T 和Bitree T
- 为什么大多数程序员没有工程思维
- 台式linux系统安装,LINUX安装方法