目录
一、前言
二、无元素状态
三、直线与弯道
四、十字与环岛
1、十字识别处理
2、环岛识别处理
五、坡道
六、障碍物
七、斑马线
八、入库
九、出界停车
一、前言
在写这篇文章之前,考虑了很久到底该写到什么程度,但思来想去,不同的摄像头高度、角度、赛道元素、车身运行情况等,都或多或少会影响元素的处理。而且在实际调试中,会遇到非常多的特殊情况需要处理,无论怎么讲解,不能做到面面俱到。同时当对所得边线提取的信息有了完全的了解以后,其实所有的元素处理是一通百通的。
在实际处理时,多个信息互相搭配,需要什么调用什么,到了后期,要能做到看到一张图像就知道有哪些信息可以使用。因此此篇并不过多赘述,只是讲讲不同元素处理的方法并提供一些思路。
对于同一个元素,如左环岛,可能识别就有好几种情况,比如车头斜入、偏向直线一侧斜入、偏向环一侧斜入、赛道中间进入等,都需对应的识别并处理,否则会导致漏判。但判断过多,可能又会与其他元素误判,所以说前面所有的代码必须理解透彻,才能在调用不同的信息处理元素时得心应手。
注:处理元素务必在摄像头角度和高度确定好并把摄像头固定死以后,之后不要再改变。
二、无元素状态
无元素状态通常出现在元素与元素之间的衔接过程,如直线与弯道,直线与环岛等等情况,对于无元素状态,可不做相关处理。
本人采用识别到直线时,直接进入while循环,此时元素标志位为直线,在循环内反复识别其他元素,当出现其他元素时,打破while循环,更改元素标志位,而出现无元素状态时,不打破循环。这种处理方式可以极大的减少无元素状态出现的情况,实现元素间的快速过渡。
三、直线与弯道
直线与左右弯道是最好判断的元素,备赛前中期可通过识别直线与弯道实现加减速,但对于速度的控制效果不甚理想,至于识别后要怎么用,就是各取所需了。
直线常规的识别方法为:两侧边线均为直线,爬线相遇点位于图像顶部,两侧的边界点个数小于一定阈值。
弯道常规的识别方法为:爬线相遇点的Y坐标值大于一定阈值(图像最远端的Y坐标为0),两侧边线不为直线,且一侧的边界点个数大于一定阈值,另一侧的边界点个数小于一定阈值(可用于判断左右弯道)。
弯道元素可开启陀螺仪角度积分,对于平衡组别来说可在180°弯道处进行特殊处理避免转向力度不够或转向角度过大的问题。
四、十字与环岛
1、十字识别处理
正入十字不用处理即可正常通过,但小车高速运行或平衡类组别车模很容易斜入十字,当斜入十字时,处理就极其困难了。常用的处理方法有补线法(如斜率截距补线,拉格朗日插值,贝塞尔曲线等)可找ai询问相关的补线算法,并尝试出最好的方法。对于本人的求取边线算法来说,补线方法可以使用,但并不稳定,对于四轮车模来说影响不大,但平衡类车模很容易冲出赛道。若可准确判断出斜入十字,那正入十字便可不用处理,但还是建议不论是哪种情况都去处理以确保代码的鲁棒性。
这里给出处理思路供参考:当遇到十字进入一个循环接管控制,用switch将十字的处理分为三个状态(入十字,十字内,出十字。至于三个状态怎么划分,有很多可参考的文章,就不过多赘述。每个状态都要能准确判断下一个状态的出现)。每个状态时补线的位置和计算的参考点不同。
大多数情况下十字后都会接圆环,那对于难以控制的平衡组别来说,可以将两个十字写入一个循环函数,即分为五个状态:入十字,十字内,出十字,圆环内,出十字,即在第四个状态“圆环内时”,开启陀螺仪角度积分,积分270°左右(根据实际情况测量调整)后进入出十字状态,给一个固定的偏差值,确保侧向倾斜的车身可以驶出十字,判定车身出第二个十字后结束循环。(当时摩托在环岛内转一圈后,车身向一侧倾倒严重,不给固定值拉起车身会导致车冲出赛道,因此采用这种方法,平衡组若遇到同样问题可尝试此方法)。
在入十字,十字内,出十字三个状态时,除了常用的补线算法外,可采用如下方式循迹:两侧边线都是边界点的行,该行的中线点不参与偏差值的计算,同时当某行存在一侧边线是边界点的行,降低其偏差值的权重值。如上方法需对每行的的一维边线进行遍历。具体函数需车友实现。
在十九届比赛中出现了比标准尺寸圆环大一些的环岛(并非很多车友实验室的大圆环),事先赛方并未给出相关通知,各组别需确保算法的适应性,以应对突发情况。
2、环岛识别处理
环岛通常分为五个状态:预入环,入环,环内,预出环,出环,如下图:
其中,预入环,入环,预出环,出环四个状态,常规处理方法是补线,但本人采用上交的单边巡线方案。其中预入环、出环两个状态使用单边巡左线,入环、预出环两个状态使用单边巡右线,具体实现如下:
对于右圆环,需要单边巡左线, 首先将车放在直线的正中央,用手机拍摄屏幕上显示的图像(需包含左右一维边线,以及中线),然后将图片放大,定义一个全局变量数组,数出每一行中线与右侧边线的X坐标差值(或者写一个函数直接在屏幕上显示即可),将差值录入数组。
当需要单边巡左线时,直接将实际左线每一行的X坐标加上提前录入的数组即可得到中线,进而避免使用左右两侧边线一起计算中线,可以使车行驶到预定位置。对于右环,预入环时单边巡左线,可使车直线行驶到指定位置进行预入环程序。预入环时单边巡右线,可使车拐入环内,环内采用正常巡线即可。然后识别到预出环状态时,切换为单边巡右线模式,可使车保持向右转向而非直线驶出赛道。最后出环时,切换为单边巡左线可使车直线驶出环岛。
左环也是同样的原理。这里给出部分单边巡线部分的示例代码:
case L_Unilateral_Patrol:{uint8 L_Staright[60] = { 0, 0, 4, 5, 5, 5, 6, 6, 6, 7,7, 7, 8, 8, 9, 9,10,11,11,12,12,13,13,13,13,14,14,15,15,16,16,16,17,17,18,18,19,19,19,20,20,21,21,21,21,22,22,23,23,24,24,24,25,25,25,26,26,27,27,28};for(i = 2; i < point_num + 2; i++){c_line[i] = l_border[i] + L_Staright[i];}break;}case R_Unilateral_Patrol:{uint8 R_Staright[60] = { 0, 0, 4, 5, 5, 5, 6, 6, 6, 7,7, 7, 8, 8, 9, 9,10,11,11,12,12,13,13,13,13,14,14,15,15,16,16,16,17,17,18,18,19,19,19,20,20,21,21,21,21,22,22,23,23,24,24,24,25,25,25,26,26,27,27,28};for(i = 2; i < point_num + 2; i++){c_line[i] = r_border[i] - R_Staright[i];}break;}
使用单边巡线处理圆环时,需注意摄像头角度和高度不可变动,若出现调整,单边巡线的数组需重新录入。同时对于入环和预出环使用单边巡线时,对车的控制不是太精确,可使用黑线补全圆环,然后将车模放入预入环和预出环状态的起始位置,录入专用的单边巡线数组,而非使用直线状态下录入的数组。
单边巡线的优势很明显,及其稳定性较高,不会像补线算法那样容易受影响,尤其是对于平衡组别来说尤为明显。同时我们希望小车尽可能快的通过圆环,那么车身在环岛元素内可以适当内切以缩短路径,那么我们可以手动修改入环和预出环状态时的数组值,使其适当内切,同时在圆环内正常巡线时,可手动加减值干预偏差值使其适当内切以缩短路径距离。
至于环岛的每个阶段如何切换,需考验车友的功底,根据提取的赛道信息和实际情况调整,确保可以准确识别每个状态和快速过渡。
为了防止卡死在环岛内的某一状态,而无法结束环岛状态,通常会采用除识别特定元素以外的方法去确保代码的正常运行:环岛的五个状态,都可使用定时器设定时间,到达设定时间时强行打破该状态进入下一状态;或者计数图像张数,到达设定数量时强行进入下一状态。至于设定的时间和计数的图像张数,都需根据实际车速去调整,同时在执行预入环时,可开启角度积分,根据积分值进行状态的切换,也可和其他配合使用,即除识别特定元素信息外还有其余保障。算是后期图像位的调参工作,这样可保证识别到环岛和十字等元素时可以确保跑完元素和顺利出元素。
同时如同十字后的圆环一样,十九届国赛也是在未通知的情况下出现了比正常环岛略大一圈 的圆环,比较考验算法的鲁棒性。
五、坡道
坡道与直道极其相似,正常情况下可识别图像远端左右边线差值的减小来识别坡道,但误判率较高,强烈建议有坡道的组别使用摄像头和TOF测距模块组合判断坡道。对于坡道的处理,正常电机闭环后可不必担心上不去坡的问题,所以可以不用识别坡道。但有些竞速组别要担心车速太快导致的飞坡问题,可识别到坡道后进行相应的处理,但胜负就在毫厘之间,避免出现适得其反的处理。
六、障碍物
因障碍物较小,很多车速较快的组别可能还未做出反应就已经走过障碍物。即使不识别障碍物,大多数组别车模都会适当做出避让。
障碍物的识别比较容易误判,需谨慎处理,通常可识别黑色凸起区域并且出现右转上和上转左拐点(障碍物在赛道左半边),并且两点之间的Y坐标差值小于某一阈值。十九届我们摩托参赛时并未过多处理障碍物,车可自行驶过障碍物,因此无法给出很好的建议,需车友自行探索。
对于障碍物,可建模并3D打印对应尺寸的盒子,并贴上黑胶带,可减少一定资金开销。(实验室有条件的话)
当车撞墙并电机缓慢转动或停转时,需及时快速的拿起车模,因为此时电机堵转很容易烧毁。在此祝愿各位车友的车车少撞障碍物和墙,愿每一个车车的电机和舵机可以活的长长久久。
七、斑马线
斑马线可扫描固定行去识别,通常扫描图像中下部位的三行或两行,每两行之间有一定间隔,找左右边线内黑点个数,几行相加个数大于一定阈值判定为出现斑马线,具体实现如下:
①可使用之前文章内算法求出的均值阈值作为二值化阈值,从对应行左侧边线的X坐标开始向右遍历每个点至右侧边线,注意判定为黑点的条件为当前点为黑并且X坐标相差1或2的点为白(因为斑马线为黑白交错,所以务必判断黑白交替,否则在某些时候车身冲出赛道一部分会直接停车)。使用二值化算法的可直接扫描黑白交替即可。
②使用差比和算法,函数输出的两个灰度值为当前点和X坐标相差1或2的点,判断黑白交替的边界个数,大于一定阈值时判定为出现斑马线。但效果并不如第一种方法。
在判断斑马线时,可将其判断函数放入直线循环内,因为斑马线在直道上,这样可有效防止误判导致的半路停车。
八、入库
使用摄像头识别入库的话仍然需要注意误判问题,通过拐点、直线等因素可识别,识别出车库后使用单边巡线配合定时器即可停车。十九届无组别有入库需求,因此无法提供更多的思路,需车友自行摸索。
九、出界停车
很多车友会写车模冲出赛道后自动停车的代码,本人建议在实验室时启用此部分代码,但当正式比赛时关闭此部分代码,即让车模放开了跑。很多时候车身一部本超出赛道但并未到判罚程度,车自动停止了,或者在坡道顶部突然停车等情况,会导致一次发车机会和时间的浪费。很多时候车会自行驶回赛道,因此尽量珍惜每一次发车机会和时间。
与此同时,需确保可以第一时间抓取冲出赛道的车模,防止撞到挡车牌冲入其他组别赛道的情况(甚至出现冲进其他组别赛道恰好继续循迹的情况)。