2019年江苏省机器人大赛"1:10无人车多车交互赛", 我有幸带领我的小伙伴参加. 最近由在简历中提到, 写此篇,作为补充说明.


由于年代久远, 大部分图片资料已丢失, 本文大部分图片都来源于网络

1. 规则

详细规则有一大堆, 我便长话短说. "无人车" 这一比赛分为两个项目:

项目一: 超车及会车

在不违反交通规则的前提下, 超越前方龟速车, 进入逆向车道行驶, 遇到对向来车, 返回原车道


项目二: 避障及斑马线前停车

在不违反交通规则的前提下, 遇到前方减速锥, 进入逆向车道行驶, 再次遇到前方减速锥,返回原车道;
与减速标线, 及时减速, 并在斑马线前停车, 等待5S, 后继续行驶过终点


2. 视觉处理

视觉处理, 其实就是: 读入图片, 到计算出当前车体状态的过程, 这是本篇的重点

2.1 开发环境

系统环境ubuntu16.04
使用CLion作为代码编写调试的平台
调用opencv中的函数进行图像的处理 识别

loading picture

2.2 逆透视变换

平直道路的道路标线相互平行, 永不相交, 但在人眼看来, 它们似乎都汇聚于一点, 这就是因为存在透视现象. 这种现象增加了计算车体姿态的难度, 所以从摄像头获取图像后, 我们进行了逆透视变换
代码也不复杂, 仅仅调用了cv::warpPerspective(src, dst, warp_mat, size); 输入原图,目标图像和相应的变换矩阵即可. 矩阵可以事先测量, 因为它仅与摄像头参数, 姿态有关, 详细方法可以查看:
https://blog.csdn.net/ganbelieve/article/details/91996326

loading picture

2.3 霍夫直线变换

霍夫直线变换可以理解为将图像中点的坐标(x,y), 转换为ρ Θ空间中的一条曲线, 曲线上每一点(ρ,Θ)代表一条过(x, y)的直线, 该直线做垂线过原点, 垂线长度为ρ, 与坐标轴夹角为Θ. 当ρ Θ空间中两曲线相交于一点, 代表图像空间中的两点共线, 当ρ Θ空间中五百条曲线相交于一点, 代表图像空间中的五百个点共线, 即我们常说的直线段
说白了,这就是用来找直线的, 具体变换可参考:
https://blog.csdn.net/shenziheng1/article/details/75307410 具体步骤如下:(相关图片没有保存)
①图线二值化, 突出道路标线(白)与路面(黑)
②Canny边缘检测, 可以理解为找出图片中像素值突变的区域(梯度大于阈值)
③将检测结果输入霍夫变换

loading picture

实际使用过程中, 效果却并不理想, 对同一道路标线, 常常检测出多条相交的直线, 因此我们还对这些直线进行了筛选. 利用直线的ρ Θ值进行筛选,(图片很精彩,可惜没了) 找到最佳的两条, 求取平均, 得到最终的直线, 该直线的Θ表示了 车体与目标方向的偏离程度, ρ表示了车体是靠近左标线还是靠近右标线

2.4 斑马线及停车线检测

起初打算想道路标线检测一样, 使用霍夫直线检测, 判断前方是否有斑马线或停车线, 但效果不理想, 后尝试使用SVM, 判断图中是否有斑马线, 结果SVM受环境影响较大.
最后决定使用最简单的方法: 计算图片中白色区域的面积
在正常道路上行驶, 只有两侧标线为白色, 白色较少, 当出现停车线及斑马线时, 白色区域增多, 同时为了避免环境亮度干扰, 以图像平均亮度作为二值化的阈值. 这种方法简单粗暴, 但却很有效.

2.5 回想

现在回想起来, 当时的我真是又笨又勤奋, 现在我会使用神经网络, 输入图像, 输出控制车体的指令, 然后用遥控器训练它一周, 肯定跑的飞快


3. 避障

使用激光雷达进行障碍物的检测, 该部分有我的小伙伴"王海龙"实现, 在此进行简述

激光雷达的原理是, 发出一束激光, 并接受其反射信号, 计算二者时间差, 测出距离, 如果我有无数个这样的装置, 对空间任意方向进行测量, 我就可以得到一个所在空间的不完整模型(可能有遮挡). 现实中不可能使用那么多的激光发射器和激光传感器, 我们就让单个或多个激光发射器和激光传感器旋转起来, "扫描"指定空间.

我们使用三杉的单线激光雷达, 测量距地面3cm高处的, 障碍物, 激光雷达用串口将扫描数据发送至电脑, 通过筛选特定角度区域中, 距离小于阈值的点, 判断前方是否有障碍物. 例如, 前方-30至30°范围内, 距离小于0.4m的点有20个, 我便认为前方出现障碍物, 并决定变道


4. 串口通信

串口接入ubuntu后, ubuntu自动给他分配一个"编号", 如"ttyUSB0"; 我们通过串口控制底盘运动, 由于激光雷达和底盘控制都需要串口, 导致这一编号混乱, 我们难以教会电脑:"是ttyUSB0代表雷达,还是ttyUSB1代表雷达"

我们通过"串口绑定"解决这一问题.

5. 代码

具体代码参考我的github

6. 参赛视频

最后给大家献上参赛视频