智能车竞赛圆环、避障等元素方案开源

本文详细描述了一种基于传统扫线方法和摄像头辅助的圆环追踪算法,包括寻找拐点、拉线、编码器计步以及避障策略,以帮助智能车在赛道上精准操作。同时,文章提及了电磁圆环判断和避障过程中的图像处理和传感器使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、圆环

1.基于传统扫线的补线方法

   以右圆环为例

(1)找到近端右拐点,且左边界不丢线

 (2)找到右边中间拐点,定位近端右拐点,拉线

 (3)右边界底部丢线,结束拉线,找远端右拐点

 

 (4)定位远端右拐点,补线进环

 (5)编码器计步大于某阈值,停止补线,进普通循迹状态

  (6)赛道宽度突变,补线出环

 (7)找远端右拐点,补线不入环

 

 (8)结束,清空状态

void Right_Roll_Judge(void)
{
    extern int Distance_L;
    extern int Distance_R;

    int erro_x,erro_y;
	if(XK.roll_flag==0&&XK.roll_situation==0)//初始状态
	{
		if((Right_NearInflection_Judge(40,30)==1)&&(Left_Road_Lose(10,60)==1))//找到右拐点且左边界不丢失
		{
			XK.roll_situation=1;
			XK.roll_flag=1;
			XK.y3=28;
			erro_x=0;
			erro_y=0;
			XK.y2=0;
			XK.x2=0;
		}
	}
	if(XK.roll_situation==1)//找拐点,定位
	{
		Right_NearInflection_Catch(XK.y,60,XK.x,XK.y);//近拐点定位
		Right_RoundInflection_Catch(XK.y,1,XK.x2,XK.y2);//中间拐点定位
		if(XK.y>0&&XK.y2>0)//找到两个拐点,准备拉线
		{
		    erro_x=0;
		    erro_y=0;
		    XK.y1=XK.y2;
		    XK.x1=XK.x2;
		    XK.roll_situation=2;
		}
	}
	if(XK.roll_situation==2)//拉线
	{

	    Right_NearInflection_Catch((XK.y-2),60,XK.x2,XK.y2);
		erro_y=abs(XK.y2-20);

	    XK.y3=XK.y;
	    XK.y4=XK.y1+erro_y;
	    XK.x3=XK.x;
	    XK.x4=XK.x1;
		XK.line=1;
		if(XK.right_line[100]>160)//当右边界底部丢线,结束拉线
		{
			XK.line=0;
			XK.y2=0;
			XK.roll_situation=3;
		}
	}
	if(XK.roll_situation==3)//找远拐点
	{
		Right_FarInflection_Catch(1,40,XK.x2,XK.y2);//远拐点定位
		if((XK.y2>0)&&(XK.right_line[20]>150))//找到远拐点且右边界前端丢线,准备拉线
		{
            XK.y1=XK.y2;
            XK.x1=XK.x2;
            Distance_L=0;
            Distance_R=0;
            XK.Encoder_distance=0;
		    XK.roll_situation=4;
		}
	}
	if(XK.roll_situation==4)//入环补线
	{

        XK.y3=25;
        XK.y4=55;
        XK.x3=110;
        XK.x4=45;
        XK.line=1;

        if(XK.Encoder_distance>5)//编码器计步(走一段距离,结束补线)
        {
            XK.y2=0;
            XK.line=0;
            Distance_L=0;
            Distance_R=0;
            XK.Encoder_distance=0;
            XK.roll_situation=6;
        }
	}
	if(XK.roll_situation==6)//环内状态
	{
	    if((XK.road_width[29]-XK.road_width[30]>50)||XK.road_width[30]>150)//赛道宽度突变
	    {
            XK.y1=XK.y2;
            XK.x1=XK.x2;
            XK.y2=0;
            Distance_L=0;
            Distance_R=0;
            XK.Encoder_distance=0;
	        XK.roll_situation=7;
	    }
	}
	if(XK.roll_situation==7)//出环补线
	{
        XK.y3=25;
        XK.y4=60;
        XK.x3=115;
        XK.x4=30;
        XK.line=1;
        Right_FarInflection_Catch(1,30,XK.x2,XK.y2);找远端拐点
        distence_count();
        if((XK.y2>0)&&XK.Encoder_distance>7)//不入环判断:在走一段距离的情况下,找到远端拐点
        {
            XK.y1=XK.y2;
            XK.x1=XK.x2;
            XK.roll_situation=8;
        }
	}
	if(XK.roll_situation==8)//不入环补线
	{
        XK.y3=100;
        XK.y4=20;
        XK.x3=136;
        XK.x4=113;
        XK.line=1;
	}
	if(XK.roll_situation==8)//不入环补线
	{
        Distance_L=0;
        Distance_R=0;
        XK.Encoder_distance=0;
        XK.y3=100;
        XK.y4=20;
        XK.x3=136;
        XK.x4=113;
        XK.line=1;
	}
    if((Left_Road_Lose(20,60)==1)&&XK.roll_situation==8)//右边界不丢失,圆环标志位清零
    {
        XK.roll_situation=0;
		XK.roll_flag=0;
        XK.line=0;
    }

}

void draw_line(void)//补线处理函数
{
    if(XK.line==1)
    {
 		ips114_add_line(XK.y,XK.x+0,XK.y1,XK.x1+0,0x00);
		ips114_add_line(XK.y,XK.x+1,XK.y1,XK.x1+1,0x00);
		ips114_add_line(XK.y,XK.x+2,XK.y1,XK.x1+2,0x00);
 		ips114_add_line(XK.y,XK.x+3,XK.y1,XK.x1+3,0x00);
		ips114_add_line(XK.y,XK.x-1,XK.y1,XK.x1-1,0x00);
		ips114_add_line(XK.y,XK.x-2,XK.y1,XK.x1-2,0x00);
    }
}

关于如何在图像数组中补线,基于逐飞的IPS114画线函数更改即可

void ips114_add_line (uint16 x_start, uint16 y_start, uint16 x_end, uint16 y_end, const uint16 color)
{

    int16 x_dir = (x_start<x_end ? 1:-1);
    int16 y_dir = (y_start<y_end ? 1:-1);
    float temp_rate = 0;
    float temp_b = 0;

    if(x_start != x_end)
    {
        temp_rate = (float)(y_start-y_end)/(float)(x_start-x_end);
        temp_b = (float)y_start-(float)x_start*temp_rate;
    }
    else
    {
        while(y_start != y_end)
        {
            mt9v03x_image_copy[x_start][ y_start]=0x00;//根据需要更改的图像数组

            y_start += y_dir;
        }
        return;
    }
    if(abs(y_start-y_end)>abs(x_start-x_end))
    {
        while(y_start != y_end)
        {
            mt9v03x_image_copy[x_start][ y_start]=0x00;//根据需要更改的图像数组
            y_start += y_dir;
            x_start = (int16)(((float)y_start-temp_b)/temp_rate);
        }
    }
    else
    {
        while(x_start != x_end)
        {
            mt9v03x_image_copy[x_start][ y_start]=0x00;//根据需要更改的图像数组
            x_start += x_dir;
            y_start = (int16)((float)x_start*temp_rate+temp_b);
        }
    }
}
2.电磁圆环,摄像头辅助判断
void elec_roll_judge(void)
{
// ********* 摄像头区分左右环(这一段可单独放在图像处理函数里) ***********
    if(XK.roll_flag==1&&XK.roll_situation==1)
    {
        XK.rolldirr=rroll_dir_judge(10,50,65);
        XK.rolldirl=lroll_dir_judge(10,50,65);
    }
// *****************************************************************
    extern float AD[6];
    if(XK.roll_flag==0&&XK.roll_situation==0)
    {
        if(AD[1]>3000&&AD[0]>3000)//中间电感大于一定阈值
        {
            XK.roll_flag=1;
            XK.roll_situation=1;
            Distance_L=0;
            Distance_R=0;
            XK.Encoder_distance=0;
        }
    }
        if(XK.roll_flag==1&&XK.roll_situation==1)
        {

            if(XK.rolldirr==1)//右圆环状态
            {
                XK.roll_flagr=1;
                XK.roll_flagl=0;
                XK.roll_situation=2;
                Distance_L=0;
                Distance_R=0;
                XK.Encoder_distance=0;
            }
            else if(XK.rolldirl==1)//左圆环状态
            {
                XK.roll_flagr=0;
                XK.roll_flagl=1;
                XK.roll_situation=2;
                Distance_L=0;
                Distance_R=0;
                XK.Encoder_distance=0;
            }
            if(XK.Encoder_distance>15)//计步大于某值,跳出圆环
             {
                XK.roll_situation=0;
                XK.roll_flag=0;
                XK.roll_flagl=0;
                XK.roll_flagr=0;
                Distance_L=0;
                Distance_R=0;
                XK.Encoder_distance=0;
             }
        }
        if(XK.roll_flag==1&&XK.roll_situation==2)
        {
            if(XK.roll_flagl==1&&XK.roll_flagr==0)//右圆环状态
            {
                if(AD[3]>3300)//右斜电感大于阈值,舵机打角
                {
                    XK.roll_situation=3;
                    Distance_L=0;
                    Distance_R=0;
                    XK.Encoder_distance=0;
                }
            }

            if(XK.roll_flagl==0&&XK.roll_flagr==1)//左圆环状态
            {
                if(AD[4]>3400)//左斜电感大于阈值,舵机打角
                {
                    XK.roll_situation=3;
                    Distance_L=0;
                    Distance_R=0;
                    XK.Encoder_distance=0;
                }
            }
        }
        if(XK.roll_flag==1&&XK.roll_situation==3)//环内状态
        {
            if(XK.Encoder_distance>9)//计步
            {
                XK.roll_situation=5;
                Distance_L=0;
                Distance_R=0;
                XK.Encoder_distance=0;
            }
        }
        if(XK.roll_flag==1&&XK.roll_situation==5)
        {
            if(XK.roll_flagl==1&&XK.roll_flagr==0)//右圆环出环判断
            {
                if(AD[5]>1700)//右侧电感大于某阈值,右打角
                {
                    XK.roll_situation=6;
                    Distance_L=0;
                    Distance_R=0;
                    XK.Encoder_distance=0;
                }
            }
            if(XK.roll_flagl==0&&XK.roll_flagr==1)//左圆环出环判断
            {
                if(AD[2]>2800)//左侧电感大于某阈值,左打角
                {
                    XK.roll_situation=6;
                    Distance_L=0;
                    Distance_R=0;
                    XK.Encoder_distance=0;
                }
            }
        }
   
        if(XK.roll_flag==1&&XK.roll_situation==6)//计步大于某阈值,结束圆环,标志位清零
        {
            if(XK.Encoder_distance>3)
            {
                XK.roll_situation=0;
                XK.roll_flag=0;
                XK.roll_flagr=0;
                XK.roll_flagl=0;
                Distance_L=0;
                Distance_R=0;
                XK.Encoder_distance=0;
            }
        }
}

二、避障

 这里需要用到编码器计行驶圈数

#define ENCORDER_PRCISION   1024.f  //512线、1024线等
#define ENCORDER_D      19.2f   //编码器齿轮直径   齿数30
#define WHEEL_D         64.0f   //车轮直径
#define WHEEL_GEAR_D            41.0f   //车轮直连齿轮直径    齿数  68
#define GET_DISTANCE_M(val)    ((((val/ENCORDER_PRCISION)*ENCORDER_D*PI )*WHEEL_D)/WHEEL_GEAR_D/1000)


void distence_count(void)
{

    Distance_L = Distance_L + XK.speedl;
    Distance_R = Distance_R + XK.speedr;
    XK.Encoder_distance=GET_DISTANCE_M((Distance_L + Distance_R) / 2);

}

void barrier (void)
{
    extern int Distance_L;//左轮距
    extern int Distance_R;//右轮距

	if(dl1a_distance_mm<XK.dis1&&XK.barrier_judge==0)//避障预判断
	{
	    Gyro_qin0();//陀螺仪数值清零
		XK.barrier_in=1;//避障状态
		XK.barrier_judge=1;//避障进入标志位
		XK.Encoder_distance=0;//测距距离

	}
	if(XK.barrier_judge==1)
	{
	    switch (XK.barrier_in)
	    {
        case 1:
        {
            if(dl1a_distance_mm<=XK.dis2)//行进距离
            {
                if((mt9v03x_image[2][94]+mt9v03x_image[3][94]+mt9v03x_image[3] 
                [93]+mt9v03x_image[3][95])/4<55)//tof测距小于某阈值且图像灰度像素小于某阈值                                                                        
                                                                        (区分坡道与避障)
                {
                Distance_L=0;
                Distance_R=0;
                XK.Encoder_distance=0;
                XK.barrier_in=2;
                Gyro_qin0();
                wireless_uart_send_string("6");//与后车通信
                }
                else//未达条件跳出状态
                {
                    Distance_L=0;
                    Distance_R=0;
                    XK.time=0;
                    XK.Encoder_distance=0;
                    XK.barrier_in=0;
                    XK.barrier_judge=0;
                    Gyro_qin0();
                }
            }
        }
        break;
	    case 2://打角避障
	    {

	        if(XK.dash_dir==1)//右边避障
	        {
	          if(eulerAngle.yaw<-3.1)//右航向角
	          {
	            Distance_L=0;
	            Distance_R=0;
	            XK.time=0;
	            XK.Encoder_distance=0;
	            XK.barrier_in=3;
	            Gyro_qin0();//陀螺仪数值清零
	          }
	        }
            if(XK.dash_dir==0)//左边避障
            {
              if(eulerAngle.yaw>1.6)//左航向角
              {
                Distance_L=0;
                Distance_R=0;
                XK.time=0;
                XK.Encoder_distance=0;
                XK.barrier_in=3;
                Gyro_qin0();//陀螺仪数值清零

              }
            }
	    }
	    break;
        case 3://直行
        {
            distence_count();//编码器测距
            if(XK.Encoder_distance>3)//行进距离
            {
                Distance_L=0;
                Distance_R=0;
                XK.time=0;
                XK.Encoder_distance=0;
                XK.barrier_in=4;
                Gyro_qin0();
            }
        }
        break;
        case 4://打角
        {
           
            if(XK.dash_dir==1)//左边避障
            {
              if(eulerAngle.yaw>3.6)//左航向角
              {
                Distance_L=0;
                Distance_R=0;
                XK.time=0;
                XK.Encoder_distance=0;
                XK.barrier_in=5;
                Gyro_qin0();
              }
            }
            if(XK.dash_dir==0)//右边避障
            {
              if(eulerAngle.yaw<-6.0)//右航向角
              {
                Distance_L=0;
                Distance_R=0;
                XK.time=0;
                XK.Encoder_distance=0;
                XK.barrier_in=5;
                Gyro_qin0();
              }
            }
        }
        break;
        case 5://直行
        {
            distence_count();//编码器测距
            if(XK.Encoder_distance>1)//行进距离
            {
                Distance_L=0;
                Distance_R=0;
                XK.time=0;
                XK.Encoder_distance=0;
                XK.barrier_in=6;
                Gyro_qin0();
            }
        }
        break;
        case 6://打角
        {
           
            if(XK.dash_dir==1)//左边避障
            {
              if(eulerAngle.yaw>5.0)//左航向角
              {
                Distance_L=0;
                Distance_R=0;
                XK.time=0;
                XK.Encoder_distance=0;
                XK.barrier_in=7;
                Gyro_qin0();
              }
            }
            if(XK.dash_dir==0)//右边避障
            {
              if(eulerAngle.yaw<-5.9)//右航向角
              {
                Distance_L=0;
                Distance_R=0;
                XK.time=0;
                XK.Encoder_distance=0;
                XK.barrier_in=7;
                Gyro_qin0();
              }
            }
        }
        break;
        case 7://直行,回赛道
        {
            extern float AD[6];
            distence_count();//编码器测距
            if(XK.dash_dir==1)
            {
              if((mt9v03x_image[110][140]+mt9v03x_image[110][141]+mt9v03x_image[110] 
                  [139])/3>100)//图像灰度像素大于某阈值(白色赛道)

              {
                Distance_L=0;
                Distance_R=0;
                XK.time=0;
                XK.Encoder_distance=0;
                XK.barrier_in=0;
                XK.barrier_judge=0;
               
              }
            }
            if(XK.dash_dir==0)
            {
              if((mt9v03x_image[110][48]+mt9v03x_image[110][49]+mt9v03x_image[110] 
              [50])/3>100)//图像灰度像素大于某阈值(白色赛道)

              {
                Distance_L=0;
                Distance_R=0;
                XK.time=0;
                XK.Encoder_distance=0;
                XK.barrier_in=0;
                XK.barrier_judge=0;
               
              }
            }
        }
        break; 
	  }
	}
}

本文旨在本校智能车实验室教学,若有错漏,欢迎指正

<think>好的,我现在需要帮用户解决关于智能车圆环赛道上使用一维数组实现补线算法的问题。首先,我得回顾用户提供的引用内容,看看有没有相关的信息。引用1提到要利用赛道特殊性取巧,可能涉及阈值计算和算法选择;引用2介绍了摄像头循迹的基本方法,即通过中线跟踪,而中线来自左右边线处理;引用3则提到了图像二值化和找中线的代码实现。 用户的问题集中在圆环赛道的补线算法,特别是用一维数组来实现。我需要先理解圆环赛道的特点。通常,圆环赛道会有两个环岛,车辆需要识别入口和出口,可能需要进行特殊补线处理,比如在环岛处补全缺失的边线或中线。 接下来,我需要考虑一维数组在图像处理中的应用。通常,摄像头采集的图像是二维的,但为了简化处理,可能会将图像压缩成一维数组,比如每列取一个平均值或极值,这样可以在降低计算量的同时保留关键信息。这在引用3的视频中可能有提到。 补线算法的关键点可能包括:识别圆环的入口和出口,判断当前是否处于圆环区域,根据左右边线的缺失情况进行补线,生成合理的中线。例如,当进入圆环时,一侧的边线可能消失,此时需要根据另一侧的边线或历史数据来补线。 结合用户提供的引用,引用2中提到中线是通过左右边线获得的,而补线可能是在边线缺失时的处理。因此,补线算法可能需要先检测边线的连续性,当检测到边线断开时,根据已有的边线趋势进行延长,或者使用对称性假设(如圆环的对称结构)来补线。 另外,一维数组的处理可能需要逐列扫描图像,找到每列的左右边线位置,记录在数组中。当某列的边线缺失时,根据相邻列的数据进行插值或外推。例如,使用前几列的边线位置来预测当前列的边线位置,从而补全数组中的缺失值。 还需要考虑圆环的特殊标志,比如环岛入口处可能有特定的颜色或形状变化,可以通过阈值法(引用1和3提到的)来识别,从而触发补线逻辑。补线后的中线需要平滑过渡,避免突变,这可能涉及到滤波或插值算法。 最后,可能需要参考引用3中的代码实现,特别是图像二值化和找中线的部分,将其适配到一维数组的处理中,优化计算效率,确保实时性。同时,引用1的建议提醒我们要利用赛道特性,避免过度复杂的计算,因此补线算法应尽可能简单有效,比如使用线性预测或固定半径的圆弧补线。</think>针对智能车圆环赛道补线算法的一维数组实现,结合图像处理特点和赛道特征,整理以下解决方案: ### 一、圆环赛道特征与补线原理 1. 圆环赛道呈现闭合环状结构,存在内外边线跳变特征[^2] 2. 传统扫线算法在环岛区域会出现边线断裂现象,需要特殊补线处理 3. 一维数组处理通过列方向投影简化计算: $$ \text{Column}[i] = \arg\max_{y}(EdgeValue(y)) $$ ### 二、一维数组补线实现步骤 ```python # 伪代码示例 def circle_compensation(line_array): # 1. 边线连续性检测 for i in range(1, len(line_array)-1): if abs(line_array[i] - line_array[i-1]) > threshold: # 2. 环岛特征识别 if check_circle_feature(i): # 3. 动态插值补偿 line_array[i] = (line_array[i-1] + line_array[i+1]) // 2 # 4. 半径约束修正 line_array[i] = constrain(line_array[i], max_radius) return line_array ``` ### 三、关键技术实现 1. **环岛识别**:通过连续列宽突变检测 ```c // C语言示例 if( (right_edge[i] - left_edge[i]) > 2*normal_width ) circle_flag = 1; ``` 2. **动态补偿策略**: - 前向预测补偿:$$ x_{n} = x_{n-1} + k\Delta x $$ - 对称补偿:利用圆环对称性补全对侧边线 3. **数据平滑**: ```python smoothed = [sum(line_array[i-1:i+2])/3 for i in range(1,len(line_array)-1)] ``` ### 四、性能优化建议 1. 采用差分数组存储边线位置变化量[^1] 2. 设置环岛补偿激活区间(如列号50-70区域) 3. 结合历史数据建立预测模型: $$ \hat{y}_t = \alpha y_{t-1} + (1-\alpha)\hat{y}_{t-1} $$
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值