开源汇总写在下面

第18届全国大学生智能汽车竞赛四轮车开源讲解_Joshua.X的博客-CSDN博客

开源链接写在下面

https://gitee.com/joshua_xu/the-18th-smartcaricon-default.png?t=N7T8https://gitee.com/joshua_xu/the-18th-smartcar

这应该是最后一章赛道元素了,其实三叉只出现了十六届、十七届这两届比赛。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.1 出库

比赛时没有明文规定,但是一般约定俗成:车手准备好发车后,举手向裁判示意。按下设置好的发车按键,双手离开车,中间最好有1~2秒的时间间隔,车模再自行出发。为的是防止用手推车这样的协助发车情况。

说实话,四轮车出库其实可以不用写的,车子稍微歪着放在车库,让他自由寻迹即可。可以不用特别处理。

不用特殊处理,这样放着,自由寻迹就可以自己出库

为了稳妥起见,这这里还是介绍几种办法,供出库使用。

法一:

车子放在车库,发车阶段让车模前轮左/右方向打死,速度给定速。编码器积分超过某一阈值,切换自由寻迹。

法二:

车子放在车库,发车阶段让车模前轮左/右方向打死,速度给定速。利用陀螺仪积分,航向角积分满90度左右(正90度或者负90度,取决于左或者右发车),切换自由寻迹。

车库与赛道垂直,用陀螺仪积分90度认为出库成功
法三:

车子放在车库,发车阶段让车模前轮左/右方向打死,速度给定速。利用图像,比视野变长,边界起始点靠下等条件。满足即可认为出库成功,切换自由寻迹。

1.2 入库

车模入库是一个很值得注意的问题。

因为能够跑完全程,但是入库失败是会罚时。有些情况入库失败没有触发计时装置会导致没有成绩的。我在现场以及车赛直播的时候经常有这种情况发生,很可惜。

不知道别人入库是怎么做的,我一直的利用的找斑马线。

1.2.1 斑马线

斑马线是在车库中心与赛道的中心区域,通常由黑色绝缘胶粘贴在赛道上。

详细参数见下图:

斑马线详细参数

对于智能车而言,车子看到的图像是这样的。

智能车视野的斑马线

最大的区别就是中间多了一片黑条区。

这时,最朴素的判断方法就有了。

法一:

固定区间里面找跳变。由于过于简单,前期可以使用,后期建议换掉。

划定一块区域(区域需要自行整定),(左边的像素点!=右边像素点) 计数,超出某一阈值(阈值手动调整),认为斑马线。

代码如下:

/*
 * 斑马线检测函数,检测屏幕黑白跳变数,阈值可调,也要注意判断范围,近车靠头还是远离车头
 */
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。

法二:

是上面方法的改进,将固定区域换成满足某一条件的活动区域。

是我最后选择的方案

思路

  1. 元素互斥,斑马线需要与所有元素进行互斥
  2. 最长白列比较长(因为斑马线前后必定有直道)
  3. 最长白列位于偏中间的位置(因为最长白列会穿过斑马线)
  4. 边界起始点比较靠下,不一定在最下(因为斑马线前后必定有直道,斑马线会影响车子方向,车子会晃一下)
  5. 从下向上找赛道宽度很窄的地方,超过某一阈值,记录最后窄的地方的行数(由于斑马线条纹,赛道宽度会卡在两条条纹之间,远远小于标准赛道宽度)
  6. 找到赛道宽度过窄的地方,向上移动某行,向下移动某行,找到这两行的左右边界,圈定这一片区域进行跳变计数。

图示如下

图示

先找到连续几行赛道很窄,找到了连续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弯误判

大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;
    }
}

1.3 注意事项

出库可以不进行特别处理,入库需要。

入库可以在看到斑马线后,直接打角,然后积分停车。

有一个取巧的办法,在设置出库方向时候,就顺手将入库方向准备好。如果赛道是环型赛道,那么左出库,一定意味着左入库。右出库同理。那么我在看到了斑马线时,出库是向左,那么我左打角就好,无需判断左右车库。

出库方向与入库方向关系

这样就只用判断斑马线,不需要判断左右库。

上述方法还是有瑕疵,因为从看到斑马线,到打角还需要时间,这中间的延迟是需要考虑的,最好的方法是找到斑马线区域,以斑马线区域为基准,找到车库的角点,然后补线进库。

18届车赛前车不需要入库,在斑马线后1m内停车即可,我就没有进行下一步处理,希望就继续研究吧。

二、三叉

三叉是个很有意思的元素,他的出现直接让16届车赛从跑一圈,变成了跑两圈。圈数的增多直接导致了失误率的直线上升,对车模的稳定性的要求大大增加。

三叉的理论图如下

三叉

三叉智能车实拍图如下

智能车视角的三叉

由于18届没有此元素,所以我不进行代码分享

只进行思路分析

  1. 边界起始点靠下
  2. 左右同时出现单调转折点,单调转折点纵坐标差不多
  3. 最长白列在经历了v字的过程,先减后增。同时找到最长白列最低点,用于补线。
  4. 从左或者右单调转折点连线到顶端v字的下沿即可
入三叉最长白列情况

入三叉补线情况

入三叉和出三叉的图形基本一样,判断条件一样使用。

由于历史久远,我手头没有图,出三叉就不在展示了。

建议三叉可以搞个状态机。

  1. 状态1:第一次看到这种情况认为进三叉。
  2. 状态2:尖角消失,认为进入到三叉内部。
  3. 状态3:再一次看到类似的尖角情况,出三叉。

三、T字

T字更是命惨,只出现了十七届一次。

T字示意图

实际图如下

T字实拍

代码就不分享了,思路如下

  1. 边界起始点低
  2. 有两个下拐点
  3. 最长白列比较短
  4. 最长白列长度差距不大

满足情况就补线出T字,出t字的原则仍可以和出库方向直接绑定,详情见上图,简答粗暴。

希望能够帮助到一些人。

本人菜鸡一只,各位大佬发现问题欢迎留言指出

qq:2296449414

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐