赞
踩
这应该是最后一章赛道元素了,其实三叉只出现了十六届、十七届这两届比赛。T字也只是出现了十七届一届比赛而已。车库和他们相比,稍微老一点,从十五届开始出现的。我和大家分享一下这几个元素的处理方法吧。
注:以下方案有可能会用到一个或者多个下述变量,以下变量均在开源【3】边线提取一章有讲。
- const uint8 Standard_Road_Wide[MT9V03X_H];//标准赛宽数组
- volatile int Left_Line[MT9V03X_H]; //左边线数组
- volatile int Right_Line[MT9V03X_H];//右边线数组
- volatile int Mid_Line[MT9V03X_H]; //中线数组
- volatile int Road_Wide[MT9V03X_H]; //实际赛宽数组
- volatile int White_Column[MT9V03X_W];//每列白列长度
- volatile int Search_Stop_Line; //搜索截止行,只记录长度,想要坐标需要用视野高度减去该值
- volatile int Boundry_Start_Left; //左右边界起始点
- volatile int Boundry_Start_Right; //第一个非丢线点,常规边界起始点
- volatile int Left_Lost_Time; //边界丢线数
- volatile int Right_Lost_Time;
- volatile int Both_Lost_Time;//两边同时丢线数
- int Longest_White_Column_Left[2]; //最长白列,[0]是最长白列的长度,也就是Search_Stop_Line搜索截止行,[1】是第某列
- int Longest_White_Column_Right[2];//最长白列,[0]是最长白列的长度,也就是Search_Stop_Line搜索截止行,[1】是第某列
- int Left_Lost_Flag[MT9V03X_H] ; //左丢线数组,丢线置1,没丢线置0
- int Right_Lost_Flag[MT9V03X_H]; //右丢线数组,丢线置1,没丢线置0

比赛时没有明文规定,但是一般约定俗成:车手准备好发车后,举手向裁判示意。按下设置好的发车按键,双手离开车,中间最好有1~2秒的时间间隔,车模再自行出发。为的是防止用手推车这样的协助发车情况。
说实话,四轮车出库其实可以不用写的,车子稍微歪着放在车库,让他自由寻迹即可。可以不用特别处理。
为了稳妥起见,这这里还是介绍几种办法,供出库使用。
车子放在车库,发车阶段让车模前轮左/右方向打死,速度给定速。编码器积分超过某一阈值,切换自由寻迹。
车子放在车库,发车阶段让车模前轮左/右方向打死,速度给定速。利用陀螺仪积分,航向角积分满90度左右(正90度或者负90度,取决于左或者右发车),切换自由寻迹。
车子放在车库,发车阶段让车模前轮左/右方向打死,速度给定速。利用图像,比视野变长,边界起始点靠下等条件。满足即可认为出库成功,切换自由寻迹。
车模入库是一个很值得注意的问题。
因为能够跑完全程,但是入库失败是会罚时。有些情况入库失败没有触发计时装置会导致没有成绩的。我在现场以及车赛直播的时候经常有这种情况发生,很可惜。
不知道别人入库是怎么做的,我一直的利用的找斑马线。
斑马线是在车库中心与赛道的中心区域,通常由黑色绝缘胶粘贴在赛道上。
详细参数见下图:
对于智能车而言,车子看到的图像是这样的。
最大的区别就是中间多了一片黑条区。
这时,最朴素的判断方法就有了。
固定区间里面找跳变。由于过于简单,前期可以使用,后期建议换掉。
划定一块区域(区域需要自行整定),(左边的像素点!=右边像素点) 计数,超出某一阈值(阈值手动调整),认为斑马线。
代码如下:
- /*
- * 斑马线检测函数,检测屏幕黑白跳变数,阈值可调,也要注意判断范围,近车靠头还是远离车头
- */
- void Zebra_Detect(void)
- {
- int i,j;
- change=0;
- for(i=55;i>=40;i--)
- {
- for(j=15;j<=90;j++)
- {
- if(image_two_value[i][j+1]-image_two_value[i][j]!=0)
- {
- change++;
- }
- }
- }
- // lcd_showint16(100,6,change);
- if(change>=100)
- {
-
- zebra_flag=1;
- }
- else
- {
- zebra_flag=0;
- }
- }

这里的减法和不等号是一个意思,因为图片二值化后只有两个值:0x00,0xff。
是上面方法的改进,将固定区域换成满足某一条件的活动区域。
是我最后选择的方案
思路
图示如下
先找到连续几行赛道很窄,找到了连续5行过窄。从这行开始向上找15行,往下找8行,找到这两行的左右边界,这样就圈定了一块区域,在这个区域内找跳变。大于某一阈值,认为是斑马线。
代码
- /*-------------------------------------------------------------------------------------------------------------------
- @brief 斑马线检测
- @param null
- @return null
- Sample Zebra_Stripes_Detect(void)
- @note 边界起始靠下,最长白列较长,赛道宽度过窄,且附近大量跳变
- -------------------------------------------------------------------------------------------------------------------*/
- void Zebra_Stripes_Detect(void)
- {
- int i=0,j=0;
- int change_count=0;//跳变计数
- int start_line=0;
- int endl_ine=0;
- int narrow_road_count=0;
- if(Cross_Flag!=0||(1<=Ramp_Flag&&Ramp_Flag<=3)||Zebra_Stripes_Flag!=0||
- Stop_Flag!=0 ||Electromagnet_Flag!=0||Barricade_Flag!=0)//元素互斥,不是十字,不是,不是坡道,不是停车
- {
- return;
- }
-
- 赛宽变化判斑马线
- if(Search_Stop_Line>=60&&
- 30<=Longest_White_Column_Left[1]&&Longest_White_Column_Left[1]<=MT9V03X_W-30&&
- 30<=Longest_White_Column_Right[1]&&Longest_White_Column_Right[1]<=MT9V03X_W-30&&
- Boundry_Start_Left>=MT9V03X_H-15&&Boundry_Start_Right>=MT9V03X_H-15)
- {//截止行长,.最长白列的位置在中心附近,边界起始点靠下
- for(i=65;i>=20;i--)//在靠下的区域进行寻找赛道宽度过窄的地方
- {
- if((Standard_Road_Wide[i]-Road_Wide[i])>10)
- {
- narrow_road_count++;//多组赛宽变窄,才认为是斑马线
- if(narrow_road_count>=5)
- {
- start_line=i;//记录赛道宽度很窄的位置
- break;
- }
- }
- }
- }
- if(start_line!=0)//多组赛宽变窄,,以赛道过窄的位置为中心,划定一个范围,进行跳变计数
- {
- start_line=start_line+8;
- endl_ine=start_line-15;
- if(start_line>=MT9V03X_H-1)//限幅保护,防止数组越界
- {
- start_line=MT9V03X_H-1;
- }
- if(endl_ine<=0)//限幅保护,防止数组越界
- {
- endl_ine=0;
- }
- for(i=start_line;i>=endl_ine;i--)//区域内跳变计数
- {
- for(j=Left_Line[i];j<=Right_Line[i];j++)
- {
- if(image_two_value[i][j+1]-image_two_value[i][j]!=0)
- {
- change_count++;
-
- }
- }
- }
- // ips200_show_uint(0*16,100,change_count,5);//debug使用,查看跳变数,便于适应赛道
- }
- //画出区域,便于找bug,debug使用
- // Draw_Line( Left_Line[start_line], start_line, Left_Line[endl_ine], endl_ine);
- // Draw_Line( Left_Line[start_line], start_line, Right_Line[start_line], start_line);
- // Draw_Line(Right_Line[endl_ine], endl_ine, Right_Line[start_line], start_line);
- // Draw_Line(Right_Line[endl_ine], endl_ine, Left_Line[endl_ine], endl_ine);
- // ips200_draw_line ( Left_Line[start_line], start_line, Left_Line[endl_ine], endl_ine, RGB565_RED);
- // ips200_draw_line ( Left_Line[start_line], start_line, Right_Line[start_line], start_line, RGB565_RED);
- // ips200_draw_line (Right_Line[endl_ine], endl_ine, Right_Line[start_line], start_line, RGB565_RED);
- // ips200_draw_line (Right_Line[endl_ine], endl_ine, Left_Line[endl_ine], endl_ine, RGB565_RED);
-
- if(change_count>30)//跳变大于某一阈值,认为找到了斑马线
- {
- Zebra_Stripes_Flag=1;
- }
- //相关参数显示。debug使用
- // ips200_show_uint(0*16,50,narrow_road_count,5);
- // ips200_show_uint(1*16,50,change_count,5);
- }

实际使用效果良好,过可以把边界起始行条件放的再松一些。因为像上图,右边已经看到车库了,边界起始点已经比较高,才看清晰看到斑马线。
调试时可以用方框圈出区域,实际使用效果如下:
注意,会有一个地方会有误判
大S弯会有误判,因为右边赛道宽度很窄,其他条件都符合,大家可以把最长白列的位置放的再居中一点。
这是我后期想到的一个算法,理论上可行,实际上不知道效果怎样,因为我没有时间去实验了。在这里写一下,大家自行尝试。
我们在前文的巡线里面找过一个东西叫做最长白列。并且将所有列的最长白列长度存在了一个数组里面。
我们再看看一下斑马线实拍图。
我们是不是可以将最长白列理解为从下往上的边界。
那么,我们是否可以将纵向撕裂过多认为是斑马线呢?
我觉得是可以的。具体情况看各位大佬尝试,我只提出一个想法。
代码如下
- /*-------------------------------------------------------------------------------------------------------------------
- @brief 斑马线判断
- @param null
- @return null
- Sample Zebra_Detect();
- @note 一个新想法,利用最长白列,每一列的最长白列可以看成从下往上的赛道边界,
- 当看到斑马线时,会有较大的纵向撕裂,一条斑马线会有两次撕裂
- 那么我用这个跳变计数,是否能识别斑马线呢,代码如下,
- 我就不去测试了,看各位的测试结果了
- -------------------------------------------------------------------------------------------------------------------*/
- void Zebra_Detect(void)
- {
- int j=0;
- int count=0;
- //前面的元素互斥各位自行补全
- if(Search_Stop_Line>=60)//视野很长
- {
- for(j=10;j<=MT9V03X_W-10;j++)
- {
- if(abs(White_Column[j]-White_Column[j+1])>=30)
- {
- count++;
- }
- }
- }
- if(count>=8)//阈值手动调整
- {
- Zebra_Stripes_Flag=1;
- }
- }

出库可以不进行特别处理,入库需要。
入库可以在看到斑马线后,直接打角,然后积分停车。
有一个取巧的办法,在设置出库方向时候,就顺手将入库方向准备好。如果赛道是环型赛道,那么左出库,一定意味着左入库。右出库同理。那么我在看到了斑马线时,出库是向左,那么我左打角就好,无需判断左右车库。
这样就只用判断斑马线,不需要判断左右库。
上述方法还是有瑕疵,因为从看到斑马线,到打角还需要时间,这中间的延迟是需要考虑的,最好的方法是找到斑马线区域,以斑马线区域为基准,找到车库的角点,然后补线进库。
18届车赛前车不需要入库,在斑马线后1m内停车即可,我就没有进行下一步处理,希望就继续研究吧。
三叉是个很有意思的元素,他的出现直接让16届车赛从跑一圈,变成了跑两圈。圈数的增多直接导致了失误率的直线上升,对车模的稳定性的要求大大增加。
三叉的理论图如下
三叉智能车实拍图如下
由于18届没有此元素,所以我不进行代码分享
只进行思路分析
入三叉和出三叉的图形基本一样,判断条件一样使用。
由于历史久远,我手头没有图,出三叉就不在展示了。
建议三叉可以搞个状态机。
T字更是命惨,只出现了十七届一次。
实际图如下
代码就不分享了,思路如下
满足情况就补线出T字,出t字的原则仍可以和出库方向直接绑定,详情见上图,简答粗暴。
希望能够帮助到一些人。
本人菜鸡一只,各位大佬发现问题欢迎留言指出
qq:2296449414
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。