zl程序教程

您现在的位置是:首页 >  其他

当前栏目

智能车竞赛技术报告 | 双车接力组 - 东北大学 - 三好学生

技术智能 报告 竞赛
2023-09-11 14:15:18 时间

简 介: 本文主要介绍了第十六届智能车竞赛双车的相关设计思想。此直立车与三轮车系统均由MM32F3277G9P微控制器为核心控制单元,通过电感电容传感器检测赛道下方导线以识别赛道,通过ICM-20602六轴加速度陀螺仪模块检测车身姿态,使用编码器采集车轮速度。结合车模赛道物理模型对行车最优路径进行规划,利用模糊PID、串级PID等控制算法调节双电机输出,达到对直立车的转向路径、平衡直立姿态和速度的闭环控制,以及对三轮车转向和速度的控制。

关键词 MM32F3277G9P模糊/串级pid 控制路径规划差速

学 校:东北大学
队伍名称:三好学生
参赛队员:刘俊滨 
陈庆鹏 
张天强 
韩骁  
    带队教师:马明旭 
李小号 

 


  国大学生智能汽车竞赛是以“立足培养、重在参与、鼓励探索、追求卓越” 为指导思想,鼓励创新的一项科技竞赛活动。竞赛要求在规定的汽车模型平台上,使用MindMotion公司的芯片作为核心控制模块,通过增加道路传感器、电机驱动模块以及编写相应控制程序,制作完成一个能够自主识别道路的模型汽车。参赛队员的目标是模型汽车需要按照规则在规定时间内跑出更多的赛道元素积分。

  该竞赛得到了教育部相关领导与各高校师生的高度评价,已发展成全国 30 个省市自治区400余高校的全国大学生智能汽车竞赛。
  在这份报告中,我们小组通过对小车设计制作整体思路、电路、算法、调试、车辆参数的介绍,详尽地阐述了我们的思想和创意,具体表现在电路的创新设计,以及算法方面的独特想法,而对单片机具体参数的调试也让我们付出了艰辛的劳动。这份报告凝聚着我们的心血和智慧,是我们共同努力后的成果。

  在准备比赛的过程中,我们小组成员涉猎控制、模式识别、传感技术、汽车电子、电气、计算机、机械等多个学科,这次磨练对我们的知识融合和实践动手能力的培养有极大的推动作用,所有队员都为此次智能汽车竞赛付出了艰苦的劳动。

 

第一章 统总体设计


1.1系统概述

  智能车主要由三个部分组成:检测系统,控制决策系统和动力系统。其中检测系统采用电感和总转风摄像头,控制决策系统采用MM32F3277G9P作为主控芯片,动力系统主要控制直流电机的转速。整体的流程为,通过电感来检测前方的赛道信息,并将赛道信息发送给单片机。同时,通过编码器构成的反馈渠道将车体的行驶速度信息传送给主控单片机。根据所取得的赛道信息和车体当前的速度信息,由主控单片机做出决策,并通过PWM信号控制直流电机进行相应动作,从而实现车体的转向控制和速度控制。

1.2整车布局

  (1)电池放于车模后部,重心后移大致分布在车轴的后方,提高转向灵敏度。
  (2)将电磁安装在碳纤维圆杆上,再固定在车前部。
  (3)接力装置分别放在两辆车的前部和后部。
  (4)后车直立摄像头大致装于车模直立状态车轴正上方,用来检测三叉。

 

第二章 赛任务及机械结构设计


2.1 双车接力组比赛任务

2.1.1 比赛任务

(1)车模

  车模可以使用竞赛指定车模中任何型号,车模运行方向不限,我们直立车采用D车模,三轮车采用F车模。
  车模制作完毕后,车模宽度不超过 25 厘米,高度不超过 20 厘米,长度小 于 30 厘米。

(2)微控制器与传感器

  双车车模中,两辆车模都使用Mindmotion公司的单片机。 允许使用各类电磁、摄像头、超声传感器器件进行赛道和环境检测。

(3)比赛赛道与任务

  我们组采用的方案:

  直立车模在赛道中间三叉路的某一边。三轮车模从车库出发,到达中间车模位置时,将车上的一个尺寸不小于 40 毫米见方的球体传递给第二辆车模。在规定时间120秒内依次进行:第二辆车模带着球体绕赛道跑一圈到达三叉路的另一端,并停下,同时另一辆车模启动。

  双车接力组出发和返回进入车库传递的球体可以使用用标准的乒乓球,或者高尔夫球。也可以另外自制其他材质的球体,只要其直径不小于 40 毫米即可。 如图2.2。

▲ 图2.1

▲ 图2.1

![▲ 图2.2 ](https://img-blog.csdnimg.cn/b8c2b491b67040478bd61c960d007f97.png#pic_center =22.x)

▲ 图2.2

2.1.2第十六届赛道特殊元素

  三叉路口:在赛道上存在两个三岔路口,路口之间直线距离小于三米。三岔路 口的三条进出口之间的夹角为 120°。

2.2 机械结构设计

  为了提高智能车的竞技性能,必须了解其机械结构,并且对其结构上的不足 之处加以改进。双车直立采用D车模,三轮采用F车模。双车的结构如图2.4所示。

2.2.1传递球的固定

  为了符合比赛要求,我们自己设计并用3D打印机打印了传递球在F车的放置位置,和D车接球的装置,如图2.5。

2.2.2 碳杆支架

  为了确保电磁能稳定循迹减少晃动,碳杆的牢固性是关键。两车均采用逐飞提供的对应车模的电感支架,相对于自己3d打印设计的,该支架更可靠。如图2.6。

▲ 图

▲ 图

▲ 图 2.5(b) 后车接力接力装置

▲ 图 2.5(b) 后车接力接力装置

2.2.3 摄像头安装与调试

  为了识别三叉元素,使用摄像头总钻风摄像头识别三岔路。为了确保摄像头能稳定识别三叉,摄像头整体的牢固性是关键,尽量减少晃动。由于摄像头巡线对光线有较高要求,且动态阈值算法该芯片算力的限制,我们主要使用电磁用于车的导向,摄像头仅用于识别三叉元素,离地高度为18.6cm,符合要求。如图2.7。

▲ 图 2.7

▲ 图 2.7

2.2.4 编码器的安装

  为了更为精确的获得电机转速的返回值,本次车模上安装的是龙邱512 线编码器,选择质量和体积都较小的编码器以控制车身重量。编码器安装直接使用车模上的编码器安装孔。如图2.8。

2.2.5 电池安装

  今年电池可以采用往年的镍铬电池,也可使用两节18650锂电池串联。锂电池放电性能优越,质量轻。所以两车均采用动力型锂离子电池,如图2.9。同时,为了使小车重心偏向车轴,并略微靠后方,我们在F车模使用镍镉电池作为配重,我们发现,也许是F车模本身较长的车型,若是车身重量不够或重心在车轴靠前,极容易在转弯时甩尾。

2.3 本章小结

  本章主要介绍了小车的安装制作和调试过程中机械方面的具体的问题。我们一直坚持机械结构和算法是同样重要的原则,在更新算法的同时也在提高相应的机械和硬件结构来适应。上面的介绍是我们最稳定的小车版本的经验。而在刚开始做小车到现在,对机械结构方面我们做了许许多多各种各样的尝试和实验,收获了一些效果,但是目前这版是能够适应算法并且较稳定的机械结构系统。

 

第三章 件设计


3.1 硬件设计方案

  整个智能车控制系统是由三部分组成的:MM32F3277G9P、主板、电机驱动电路板。最小系统板可以插在主板上组成信号采集、处理和电机控制单元。同时为了减小电机驱动电路带来的干扰,我们把控制部分和电机驱动分开来。主板主要电路包括如下:电源稳压电路、最小系统板插座、电机驱动器接口、编码器接口、运放接口、摄像头接口、OLED/TFT、电源接口等。

3.2 系统核心板

  单片机最小系统板使用Mindmotion的 MM32F3277G9P核心板,该核心板主频高达120MHz。主板上仅将本系统所用到的引脚引出,包括信号接口、外部中断接口、若干普通 IO 接口等。

3.3 传感器选择

  本设计中,传感器分为五部分:摄像头传感器、加速度计陀螺仪传感器、超声波测距传感器、运放传感器、无线串口透传模块。

3.3.1 摄像头

  比赛所用的摄像头可以分为两类:一类为CCD摄像头,另一类为CMOS摄像头。

  CCD摄像头图像对比度高、动态特性好,但供电电压比较高,需要12V的工作电压。在智能车的实际运行中,电机加减速时会产生很大的冲击电流,会对12V的升压模块造成冲击。同时CCD摄像头的耗电也比较严重,这会使拍摄的图像稳定性不高。

  CMOS摄像头,体积小,图像稳定性较高,只需3.3V供电,耗电量低,但动态性能不如CCD摄像头好。智能车高速运行时,摄像头拍摄的图像可能会变得模糊。但为了保证系统的稳定性,最终决定选用CMOS摄像头MT9V034,也就是新款的总钻风摄像头。

3.3.2 编码器

  处理器通过读取编码器脉冲数来实现小车速度的检测,通过读取编码器旋转方向脚的高低电平来检测电机的正反转。编码器原则上轻,小为好,我们选用逐飞科技的1024线编码器。

3.3.3 超声波测距模块

  有来有去超声波测距模块方便上手,在需要接受距离信息的车上安装接受模块,在另一辆车上安装发送模块,要注意尽量保持两个模块发送端与接收端相对且在一个水平面上。我们使用串口的方式将距离信息发送出来。赛后,我们发现这可能会与两车串口通信发生冲突。所以,尽量还是使用pwm发送距离信息。

3.3.4 无线串口透传模块

  为了避免其他相同模块的干扰,建议先修改模块的发送与接收地址。同时还需注意模块发送与接受功能函数的调用位置,是在while中调用,还是在pit中断中开启其对应的中断,需要尝试,观察是否会出现意想不到的错误。比如,我在pit中断中调用发送与接受函数,会出现在不该发送信号时发送信号的错误。

3.4 电路设计

  智能车的电路设计决定了系统可靠性与稳定性,电路设计决定着摄像头图像采集的好坏以及驱动的性能等,本系统的电路围绕MM32F3277G9P单片机为核心的最小系统板设计主板,且驱动与主板在同一块板上,核心板可插在主板上,经过测试及使用,本系统的电路设计稳定可用。

3.4.1 电源管理部分

  电源部分使用1片 LDO芯片LM2940将电源电压转为5V、3 片LDO芯片RT9013-33转 3.3V 为核心板、OLED 、运放模块及摄像头供电,电源部分电路图如图3.1 所示:

▲ 图3.1

▲ 图3.1

3.4.2 电机驱动电路

  DRV8701是一款采用4个外部N通道MOSFET的单路H桥栅极驱动器,主要用于驱动12V至24V双向有刷直流电机。该器件可通过PH /EN(DRV8701E)或PWM(DRV8701P)接口轻松连接控制器电路。内置的感测放大器能够实现可调节的电流控制。这款栅极驱动器内置有DRV8701采用9.5VV GS 栅极驱动电压来驱FET FET。所有外部FET的栅极驱动电流均可通过IDRIVE引脚上的单个外部电阻进行配置。

▲ 图3.2 电机驱动

▲ 图3.2 电机驱动

 

第四章 件系统设计


4.1. 软件控制程序的整体思路

  软件的控制,就是让控制车模在符合比赛规则前提下,以最快最稳定的速度跑完整个赛道。不论上哪种方案,软件的总体框架总是相似的,我们追求的就是稳定至上,兼顾速度,以我们的方案,软件上就是图像采集、图像处理识别横断,速度控制以及速度反馈,电感采集以及计算偏差。但是双车组有别于普通组别,不仅仅要追求速度和稳定性,还要求两辆车的配合。

4.2 图像处理和识别三叉

  后车:摄像头并未参与循迹,只是识别三叉。设定特定竖列,再检测特定行的白色像素点个数,当其达到一定数量后给转向环一个目标角速度,角速度积分到达一定数值后认为入库完成关闭电机,具体数值在实际过程中试验确定。出库同理也是固定角度。
  前车:左右电感值同时小于某个阈值,及判断检测到三叉。因为前车为三轮F车模,提前开始半闭环转向有失控风险,因此采用前瞻较短的电磁来进行检测。

4.3 电机控制

  三轮车的控制主要是电机的控制。具体的控制算法有 PID 控制、串级PID控制和模糊控制。

【通用原理部分,此处省略3000字...】

4.4 双车接力

  根据比赛规则以及两车跑的情况,前车带球出库,一直运行到后车停靠的位置,利用超声波测距模块检测距离,待两车相撞并传递小球后,前车进入停止状态,小车停止运行,后车在相撞后有初速度,这是编码器返回值大于阈值,程序启动,后车开始带着小球跑完本圈赛道后半程,并进入另一个三岔口。

4.5 本章小结

  本章主要介绍了智能车比赛中所用到的图像处理,电机控制算法和双车接力过程等软件程序。这些程序是赛车检测系统的核心,我们一次又一次的找问题后优化,优化后找问题。不断尝试新的控制算法,学习新的知识,并把新的知识应用于智能车上。
  智能车比赛的程序不是一时半会就能写好的,也不是一些好就能直接使用的,它需要经过一次次的调试,找问题调参数,直到到达最佳状态。并且我们要想更近一步,要不断去尝试新的算法,从其他角度经行寻找解决方案,对比之下选最优。

 

考 文 献


  (1) 王盼宝.智能车制作.北京.清华大学出版社.2018

附录A:主要技术参数

  • 赛题组 双车接力组
  • 车号 F车
  • 车模几何尺寸(长、宽、高)(毫米) 275/247/115(前车)
  • 电路电容总量(微法) 1000μF
  • 电路功耗(焦耳) 400J
  • 传感器种类及个数 光电编码器×2;运放板×1;超声波×1;无线透传模块×1;icm20602×1
  • 新增加伺服电机个数 0
  • 摄像头检测精度、频率 无摄像头

车号 D车

  • 车模几何尺寸(长、宽、高)(毫米) 255/247/165(后车)
  • 电路电容总量(微法) 1000μF
  • 电路功耗(焦耳) 400J
  • 传感器种类及个数 摄像头×1;光电编码器×2;运放板×1;超声波×1;无线透传模块×1;icm20602×1
  • 新增加伺服电机个数 0
  • 摄像头检测精度、频率 精度:320×240;检测频率 50 Hz

  附录C :主函数源代码

/*********************************************************************************************************************
//直立
#include "headfile.h"
#include "special_control.h"

#include "pid.h"
#include "speed.h"
#include "fun.h"
#include "angle.h"
#include "turn.h"
#include "init.h"
#include "elector.h"

//串口
#include "zf_uart.h"
#include "zf_gpio.h"

//计数
int8 count1=0;
int8 count2=0;
int8 count3=0;

//算速度
int32 iV_Avg;

//电机
int32 L_PWM=0; 
int32 R_PWM=0;

// **************************** 代码区域 ****************************
int main(void)
{	
        board_init(true);																// 初始化 debug 输出串口

	//此处编写用户代码(例如:外设初始化代码等)
        Init_All();//几乎所有的初始化 阈值变量
        lcd_init();
       tim_interrupt_init_ms(TIM_8, 2, 0x00);//进入pit中断
	//此处编写用户代码(例如:外设初始化代码等)

	while(1)
	{
		//此处编写需要循环执行的代码
       
       /*   lcd_showint32(0,1,FLAG_SPECIAL,10);
          lcd_showint32(0,2,roundabout_data.angle,10);
          lcd_showint32(0,5,sancha_data.count,10);//sancha_data.count
          lcd_showint32(0,6,pitch,10);//roundabout_data.angle
          lcd_showint32(0,7,tongxin_count,10);//angle_pid.set2
*/
// 备用区         
/*           if(fasong_flag==1&&tongxin_data.flag==1)//发送两百次 并判断是否接受起步信号
           {    
             if(tongxin_count<3)
             {
              uart_putchar(UART_4,44);
             }
           }
*/
//          
          
//新加
             if(FLAG_SPECIAL==14)
             {
              if(count_xinjia<4)
              {
                uart_putchar(UART_4,44);
              }
             }
             
//
//摄像头识别三叉          
  /*        
          if(mt9v03x_finish_flag)
          {

                for(int h=89; h>=39; h--)
                {
                      for(int w=0; w<=187; w++)
                      {
                            if(mt9v03x_image[h][w]>=187)
                            {
                                mt9v03x_image[h][w]=255;
                                
                            }
                            else
                            {
                                mt9v03x_image[h][w]=0;
                            }
                      
                      }
                
                }

            Sancha_panduan();

            lcd_displayimage032(mt9v03x_image[0], MT9V03X_W, MT9V03X_H);    
            mt9v03x_finish_flag = 0;
          }      */

        systick_delay_ms(2);
	}
}
// **************************** 代码区域 ****************************

void pit_handler (void)																// 本函数在 TIM8_UP_IRQHandler 中调用
{

        Attitude_calculation_20602();
        
        inductor_value();
    //    xielv();
   //     ConstructElectro();	//电磁处理1	

   //   EM_ADC();//电磁处理2           

       ESpecial_control();
       ESpecial_do();
       
       // DifferControl();//输出price_PWM
       
        angle_pid.now=pitch;
        angle_pid.now=limit_ab(angle_pid.now, -20, 80);//-2080可改

        //角速度参数
        angular_pid.now=GYRO.Y;
        
        Get_Speed();
        iV_Avg+=V_Avg;
        //count1++;
        count2++;
        count3++;  
        speed_out_filter(&speed_pid, COUNT);
        angle_pid.set2 = angle_pid.set1 + speed_pid.real_output; //angle_pid.set1由路况决定
        
        if (count2 > 1)
	{
            count2 = 0;
	    pid_angle(&angle_pid);//角度环运行周期
	}
        if(count3 > 3)
        {
            count3 = 0;
            pid_speed(&speed_pid);//速度环运行周期 尽量长些,与角度环区分开
        }

if((FLAG_SPECIAL!=-1)&&(FLAG_SPECIAL!=6)&&(tongxin_data.flag!=1))
 {
                            
        angular_pid.set1 = angle_pid.output; //正跑去掉符号-
        //angular_pid.set1 =0;
        pid_angular(&angular_pid);
 
       L_PWM = angle_pid.output+ 5.5*turn_in.ut_int;//1*angular_pid.output+ 6.5*turn_in.ut_int;//修改5增加转向环强度 若电机转的太慢则增大2 否则改21
       R_PWM = angle_pid.output- 5.5*turn_in.ut_int;//1*angular_pid.output- 6.5*turn_in.ut_int;//修改5增加转向环强度  若电机转的太慢则增大2 否则改21                              
        Motor_Output(L_PWM,R_PWM); 
   
}
if(tongxin_data.flag==1)
{
      pwm_duty_updata(PWM_TIM, PWM_R, - 0.5*turn_in.ut_int);  //停车状态直立的转向环尽量小些         
      pwm_duty_updata(PWM_TIM, PWM_L, 0.5*turn_in.ut_int); //
}
  }

//三轮
********************************************************************************************************************/

#include "headfile.h"

#include "special_control.h"

#include "pid.h"
#include "speed.h"
#include "fun.h"
#include "angle.h"
#include "turn.h"
#include "init.h"

//串口
#include "zf_uart.h"
#include "zf_gpio.h"

//计数
int8 count1=0;
int8 count2=0;
int8 count3=0;

//算速度
int32 iV_Avg;

//电机
int32 L_PWM=0; 
int32 R_PWM=0;

// **************************** 代码区域 ****************************
int main(void)
{
	board_init(true);																// 初始化 debug 输出串口

	//此处编写用户代码(例如:外设初始化代码等)
        Init_All();//几乎所有模块的初始化以及阈值
        lcd_init();
        tim_interrupt_init_ms(TIM_8, 2, 0x00);//开启pit中断
	//此处编写用户代码(例如:外设初始化代码等)

	while(1)
	{
		//此处编写需要循环执行的代码
/*环岛
          lcd_showfloat(0,3,FLAG_SPECIAL,5,0);
          lcd_showfloat(0,4,roundabout_data.angle,5,0);  
          lcd_showint32(0,7,roundabout_data.distance,10);  
          systick_delay_ms(100);*/
		//此处编写需要循环执行的代码
          //lcd_showfloat(0,4,12,5,0);//sancha_data.angle roundabout_data.directionadc_convert(ADC_2, ADC_CH1)
	/*lcd_showint32(0,0,FLAG_SPECIAL,10);
        lcd_showint32(0,1,roundabout_data.direction,10);
        lcd_showint32(0,2,roundabout_data.angle,10);
          lcd_showint32(0,3,roundabout_data.distance,10);
          lcd_showint32(0,5,adc_convert(ADC_2, ADC_CH1),10);
          lcd_showint32(0,6,adc_convert(ADC_2, ADC_CH2),10);
          lcd_showint32(0,7,adc_convert(ADC_2, ADC_CH3),10);
         */
       //调试摄像头识别三叉时用到 
        /*if(mt9v03x_finish_flag)
	{
		lcd_displayimage032(mt9v03x_image[0], MT9V03X_W, MT9V03X_H);
		mt9v03x_finish_flag = 0;
                
	}
        systick_delay_ms(10);*/
        //调参时会用到
        //lcd_showint32(70,8,FLAG_SPECIAL,10);FLAG_SPECIAL roundabout_data.direction
       /* lcd_showint32(0,5,sancha[0],10);
        lcd_showint32(0,6,sancha[1],10);   */
        lcd_showint32(0,0,FLAG_SPECIAL,10);
        lcd_showint32(0,1,turn_in.ut_int,10);
        
        lcd_showint32(0,2,adc_convert(ADC_2, ADC_CH1),10);
        lcd_showint32(0,3,adc_convert(ADC_2, ADC_CH2),10);
        lcd_showint32(0,4,adc_convert(ADC_2, ADC_CH3),10);
        systick_delay_ms(10);

	}
}
// **************************** 代码区域 ****************************

void pit_handler (void)																// 本函数在 TIM8_UP_IRQHandler 中调用
{

        Attitude_calculation_20602();
        
        inductor_value();//此处使用最简单的电磁处理方式,取五次的平均值
    //    ConstructElectro();	//电磁处理1	

   //   EM_ADC();//电磁处理2           

       ESpecial_control();
       ESpecial_do();
       
/*        
        Get_Speed();
        //iV_Avg+=V_Avg;
        count1++;
        count2++;
        count3++;  
        
//速度获取
        if(count1 > 2)
        {
              count1 = 0;
              speed_pid.now=V_Avg;//结合两个编码器测得数值
              pid_speed(&speed_pid);
                            
        }
        
*/         
        speed_out_filter(&speed_pid, COUNT);//速度环输出滤波
       
if((FLAG_SPECIAL!=-1)&&(FLAG_SPECIAL!=6))
 {
                            
       L_PWM = 1*speed_pid.output + 50*turn_in.ut_int;//修改5增加转向环强度 若电机转的太慢则增大2 否则改21 30
       R_PWM = 1*speed_pid.output - 50*turn_in.ut_int;//修改5增加转向环强度  若电机转的太慢则增大2 否则改21                              
        Motor_Output(L_PWM,R_PWM); //电机输出函数
   
}

}


● 相关图表链接: