智能车竞赛技术报告 | 全向行进组 - 沈阳工业大学 - 找不到北队

Posted 卓晴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了智能车竞赛技术报告 | 全向行进组 - 沈阳工业大学 - 找不到北队相关的知识,希望对你有一定的参考价值。

简 介: 本文设计的智能车系统以沁恒CH32V103R微控制器为核心控制单元,通过车体上方摄像头以及车体前方的电磁传感器检测赛道信息;通过1024线迷你正交解码编码器检测模型车的实时速度,反馈给微控制器计算下一步的运动状态。

学 校:沈阳工业大学
队伍名称:找不着北队 
参赛队员:刘友成   
徐卓涵   
马金宇   
带队教师:耿浩    

 


  国大学生智能汽车竞赛是以智能汽车为研究对象的创意性科技竞赛,是面向全国大学生的一种具有探索性工程实践活动,是教育部倡导的大学生科技竞赛之一。竞赛以“立足培养,重在参与,鼓励探索,追求卓越”为指导思想,旨在促进高等学校素质教育,培养大学生的综合知识运用能力、基本工程实践能力和创新意识,激发大学生从事科学研究与探索的兴趣和潜能,倡导理论联系实际、求真务实的学风和团队协作的人文精神,为优秀人才的脱颖而出创造条件。

  全向行进组竞赛要求在赛事组指定H型车模平台上使用WCH 系列单片机作为核心控制模块,增加各类电磁、红外光电、摄像头、激光、超声传感器器件进行赛道和环境检测,并使用自制电路板,编写相应控制程序,制成一个能自主识别道路的模型汽车。赛事目标是在一定时间内按照规格完成更多任务点,得到更多分数。在这份报告中,我们通过对设计车模的整体思路、电路、算法、调试、车辆参数的介绍,细致地阐明了我们的思想和创意,列如在电路的创新设计,以及算法方面的独特想法,我们也付出了大量的努力在单片机具体参数的调试。这份报告凝聚着我们的心血和智慧,是我们共同努力后的成果。

  在准备比赛的过程中,我们将电气,计算机,机械,传感技术,汽车电子技术,电机控制等多个学科的知识融入小车。在次过程中,我们电路设计、软件编程、系统调试等多方面的能力都有大幅度的提升,同时也锻炼了我们知识融合、实践动手的能力,我们也懂得了坚持不懈的真正含义,在一个个直至天明的夜晚,我们团结一致,从未放弃,解决了一个又一个以前从未见过的问题。相信经历过这样磨砺的我们在以后遇到困难的时候更会迎难而上。

 

第一章 统总体设计


  章主要简要地介绍智能车系统总体设计思路,在后面的章节中将整个系统分为机械结构、控制模块、控制算法等三部分对智能车控制系统进行深入的介绍分析。

1.1系统总体方案的设计

  根据竞赛规则相关规定,全向行进组智能车使用竞赛指定H型车模,允许使用各类电磁、红外光电、摄像头、激光、超声传感器器件进行赛道和环境检测,车模微控制器使用WCH 系列单片机在MounRiver studio软件中开发。小车的位置数据由两个摄像头以及车前的磁传感器采集,通过微控制器决策后发送给电机驱动,电机转速控制采用 PID 控制,通过 PWM 控制驱动电路调整电机的转速,完成智能车速度的闭环控制。

 

第二章 能车机械结构调整与优化


  能车实现功能的基础是小车本身的机械结构,本章将主要介绍智能车车模的机械结构和调整方案。
  由于比赛规则限制,所以本次比赛采用的是H车模。全车采用四个麦克纳姆轮,分别由四个独立的电机驱动,以实现全向行进的功能。

2.1智能车车体机械建模

  • 尺寸
  • 轴距 185mm
  • 前轮距 180mm
  • 后轮距 180mm
  • 总长 250mm
  • 总高 276mm
  • 总重 1.5kg

2.2麦克纳姆轮的安装

  安装方式有多种,主要分为:X-正方形(X-square)、X-长方形(X-rectangle)、O-正方形(O-square)、O-长方形(O-rectangle),这次我们采用的是O-长方形的安装方式。

  麦轮底盘的正逆运动学模型

  我们依据现有资料建立了麦轮底盘的运动学模型。
  四个轮子的着地点形成一个矩形。正运动学模型(将得到一系列公式,让我们可以通过四个轮子的速度,计算出底盘的运动状态;而逆运动学模型得到的公式则是可以根据底盘的运动状态解算出四个轮子的速度。由于底盘的运动可以用三个独立变量来描述:X轴平动、Y轴平动、yaw 轴自转;而四个麦轮的速度也是由四个独立的电机提供的。所以四个麦轮的合理速度是存在某种约束关系的,逆运动学可以得到唯一解,而正运动学中不符合这个约束关系的方程将无解。

  先构建逆运动学模型,由于麦轮底盘的数学模型比较复杂,我们在此分四步进行:
  ①将底盘的运动分解为三个独立变量来描述;
  ②根据第一步的结果,计算出每个轮子轴心位置的速度;
  ③根据第二步的结果,计算出每个轮子与地面接触的辊子的速度;
  ④根据第三部的结果,计算出轮子的真实转速。

一、底盘运动的分解

  刚体在平面内的运动可以分解为三个独立分量:X轴平动、Y轴平动、yaw 轴自转。如下图所示,底盘的运动也可以分解为三个量:

  • Vtx表示 X 轴运动的速度,即左右方向,定义向右为正;
  • Vty表示 Y 轴运动的速度,即前后方向,定义向前为正;
  • ω表示 yaw 轴自转的角速度,定义逆时针为正。

  以上三个量一般都视为四个轮子的几何中心(矩形的对角线交点)的速度。

二、计算出轮子轴心位置的速度

  • r 为从几何中心指向轮子轴心的矢量;
  • V为轮子轴心的运动速度矢量;
  • Vr为轮子轴心沿垂直于 r的方向(即切线方向)的速度分量;

  那么可以计算出:

V=Vt+ω×r

  分别计算 X、Y 轴的分量为:

  同理可以算出其他三个轮子轴心的速度。

三、计算辊子的速度

  根据轮子轴心的速度,可以分解出沿辊子方向的速度 V平行 和垂直于辊子方向的速度 V垂直 。其中 V垂直 是可以无视的而
  其中 u是沿辊子方向的单位矢量。

四、计算轮子的速度

  从辊子速度到轮子转速的计算比较简单:

  结合以上四个步骤,可以根据底盘运动状态解算出四个轮子的转速:

  以上方程组就是O-长方形麦轮底盘的逆运动学模型。

2.3智能车车轮减速齿轮机构调整

  智能车采用四个rs-380电机驱动。由于齿轮传动机构对车模的驱动能力有很大的影响。齿轮安装位置是否恰当,在很大程度上决定电机是否能发挥出最佳性能。所以我们竭尽所能地将传动齿轮轴保持平行。因为齿轮间过松容易打坏齿轮,过紧又会增加传动阻力,浪费动力,我们在不断尝试中找到了最适合的齿轮间间隙。

2.4 编码器的安装

  为了智能车的运行精确,小车采用了四个1024线迷你正交解码编码器。由于车身设计了编码器安装孔位,所以我们选择用原车自带的孔位安装编码器。

2.5智能车重心位置的调整

  由于车模装有四个电机,所以会有较大的质量,为了防止小车在运行时更加稳定,我们将小车的重心尽量保持在小车的正中间。

 

第三章 件系统设计及实现


3.1主控板和驱动板的硬件设计

  电路模块最重要的是稳定可靠,其次需要高效,轻便。

  稳定可靠,我们在电路设计的过程中细致地考虑了各个模块之间可能存在的互相影响,在信号地和功率地之间做了隔离,对各个稳压系统添加了滤波电容,保证了其在工作时的稳定。

  高效,由于智能车有摄像头,电磁传感器等多个模块,所以我们在保证其正常工作的前提下,充分利用了每一个稳压模块。由于有四个电机,我们在权衡之后采用了双电机驱动板的方案,一个电机驱动板驱动两个电机,可以达到几十安的瞬间输出电压。

  轻便,在不削减功能及稳定性的情况下,优化走线,使器件排列整齐,尽可能的缩小板子面积,便于安装,并且使得小车的质量降低。

3.1.1 电源管理模块

  电源模块是小车的心脏,所以电源模块及其重要,关系到整个系统是否能够正常工作。根据比赛规则,我们选用了7.2V 2000mAh的镍铬电池。

  为满足需要,本车模上存在4种供电电压:

  • 镍铬电池即主控板和电机供电(充满时电压在7.8~8.4V)
  • 核心板和无线串口供电使用直流5v,5v电源选用AMS117-5.0芯片。
  • 摄像头、屏幕和编码器使用直流3.3v电压供电,3.3v电源选用AMS117-3.3芯片。

  从稳定性及功能性,以及经济性考虑,AMS117系列LDO芯片稳定性好,结构简单,便于使用。

  • 电机驱动模块使用直流7.2v供电,直接使用电池供电。

▲ 图3.1 电源管理模块原理图

3.1.2 电机驱动模块

  电机驱动电路为两个相同芯片及八个N沟道的功率mos管组成两个H桥,额定工作电流可以达到几十A,保证电机可以发挥出其全部性能。

  1.电机控制芯片选用DRV8701E芯片,工作稳定性能强大,其具有内置的感测放大器能够实现可调节的电流控制。采用9.5VV GS 栅极驱动电压来驱FET。所有外部FET的栅极驱动电流均可通过IDRIVE引脚上的单个外部电阻进行配置。低功耗睡眠模式可将内部电路关断,从而实现极低的静态电流消耗。这种睡眠模式可通过将nSLEEP引脚置为低电平来设定。
  该器件内置以下保护功能:欠压锁定,电荷泵故障,过流关断,短路保护,前置驱动器故障以及过热保护。

▲ 图3.1.2 DRV8701应用图

  2. MOSFET的选择
  选择MOSFET时,主要需要考虑:耐受电压,内阻及封装。由于我们选择的是7.2v的电池作为供电电源。在考虑电机的再发电情况,所以我们将耐压限定在16v以上。权衡功率和大小之后,我们选择了东芝公司的TPH1R403NL。其Vdss为30v,Vgss为20v,Id为60A,符合我们的要求。

  3、驱动电路的原理
  DRV8701E 使用 PH/EN 接口进行控制。 下面的逻辑表(表 1)给出了完整的 H 桥驱动单个有刷直流电机时的状态。 正电流定义为 xOUT1 → xOUT2 方向。

  从而达到驱动电机实现正反转的功能。可以通过设置IDRIVE电阻值或强制将电压施加到IDRIVE引脚来调整H桥输出的上升和下降时间。 如果选择较高的IDRIVE设置,则FET栅极电压将更快地斜坡化。FET栅极斜坡直接影响H桥输出的上升和下降时间。
  我们还在电机驱动模块使用了缓冲芯片SN74HC125PWR,使得从微控制器来的信号更为稳定。

  该部分原理图如图所示

▲ 图3.2 电机驱动模块原理图

3.1.3单片机及其他电路部分设计

  我们从核心板上引出管脚为各个模块备用

  • 测速模块:由于我们采用了四个编码器测定速度,使数据更为准确,也让我们实时的监测车的状态,可以随时做出判断,这样很大程度的方便了对车的调试。
  • 陀螺仪模块:我们采用了ICM-20602陀螺仪,能实时监测小车的平衡状态,使小车运行更为稳定。
  • 摄像头模块:由于识别路径使用摄像头方案,所以我们也预留了摄像头的管脚。

 

第四章 件系统设计及实现


4.1底层初始化

  ```python
  DisableGlobalIRQ();
  board_init(); //务必保留,本函数用于初始化MPU 时钟 调试串口
  PID_Init(); //pid初始化
  dc_Init(); //电感初始化
  icm20602_init_spi();//陀螺仪spi初始化
  encoder_init(); //编码器初始化
  pwm_Init(); //pwm初始化
  DIR_IO_Init();//电机方向初始化
  systick_delay(1000000);//延时主机开机时间与副机错开一起开机
  systick_delay(1000000);
  systick_delay(1000000);
  systick_delay(1000000);
  systick_delay(1000000);
  systick_delay(1000000);
  systick_delay(1000000);
  systick_delay(1000000);
  systick_delay(1000000);
  camera_Init();//摄像头初始化
//串口的抢占优先级一定要比外部中断的抢占优先级高,这样才能实时接收从机数据
//串口的抢占优先级一定要比外部中断的抢占优先级高,这样才能实时接收从机数据
//串口的抢占优先级一定要比外部中断的抢占优先级高,这样才能实时接收从机数据
  uart_init(UART_3, 460800, UART3_TX_B10, UART3_RX_B11);
//串口3初始化,波特率460800
  uart_rx_irq(UART_3, ENABLE);
//默认抢占优先级0 次优先级0。
  gpio_interrupt_init(A0, RISING, GPIO_INT_CONFIG);
//A0初始化为GPIO 上升沿触发
  nvic_init(EXTI0_IRQn, 1, 1, ENABLE);
//EXTI0优先级配置,抢占优先级1,次优先级1
  gpio_interrupt_init(A2, RISING, GPIO_INT_CONFIG);
//A2初始化为GPIO 上升沿触发
  nvic_init(EXTI2_IRQn, 2, 2, ENABLE);
//由于主机无多余定时器中断,只能用副核的定时器中断触发主核外部中断


## <font  face=黑体 color=#7a37ab>4.2 传感器采集处理算法</font>
本车传感器使用了总钻风摄像头和ADC电感总钻风灰度摄像头为了更好识别赛道首先先进行二值化,但是为了提升车摄像头识别的鲁棒性,应找到动态阈值,所以我采用了大津法求动态阈值,将采集的图像处理成为黑白摄像头,通过从中间往两边寻找黑白界限中间点随上一个中点值变化提取边界。算出摄像头宽度,斜率,中线。
## <font  face=黑体 color=#7a37ab>4.3寻线行驶算法实现</font>
### <font  face=宋体 color=teal>4.3.1 定位算法</font>
屏幕中线一条线上的每一个点与实际图像采集每一个点做差求出误差判断出的车的位置车身是否偏离中线或者车头是否歪了。误差用pid处理一下防止误差突变过大;
### <font  face=宋体 color=teal>4.3.2 基于增量式PID的速度控制</font>
对位置式加以变换,可以得到PID算法的另一种实现形式(增量式):

<center><b>Δu_n=u_n-u_(n-1)=k_p [(e_n-e_(n-1))+1/T_i  e_n+T_d/T(e_n-2e_(n-1)+e_(n-2))]    </b></center>
<br>

在实际代码实现时,处理成
             ![](https://img-blog.csdnimg.cn/4c94f94bce5a47ac80c5878a0f20bc49.png#pic_center =560x)

将测速模块得到的单位时间脉冲数给vi_FeedBack,vi_Ref为设定速度。
                       ![](https://img-blog.csdnimg.cn/32c02a5ce13f4fd0826d67f52e09e0d2.png#pic_center =560x)

                     
                      
这里设计High,Middle,Low作为设定速度值(vi_Ref),分别对应直道,弯道,最低速度(由传感器状态确定)。位于直道时,设定速度为最大。为提高稳定性,也设置相应的调节死区和调节范围。 
 
### <font  face=宋体 color=teal>4.3.3基于位置式PID的串级PID</font>

在车行驶需要转弯时串上陀螺仪对应的角速度作为实际角速度然后将摄像头处理计算误差作为目标值输出的值给整个车的角速度使车的转弯更加丝滑并且转弯角度精准

<center><b>speed[0]=PID_Calc(&stPID_Distance,0.115,0,0.01,-Current*280, icm_gyro_z );//角速度环</b></center>
<br>

**缺点也很明显**
其实带来好处的同时就会带来缺点,缺点就是PID十分难调,因为你的pid是一环套一环,首先你出了问题,现象不容易看出来是哪个环的问题,主要是角速度环和角度环 ,然后就是怎么调整,而且中间某个环的参数没调好,后面的都不好使,这就带来了很多挑战和难题。

我该怎么调?

在串级pid中,内环是直接输出的,对于这一点来说,外环粗调就ok,内环精调。

## <font  face=黑体 color=#7a37ab>4.4弯道与直道策略分析</font>
在直道的时候车通过图像可以判断出来是直路;可以加速行驶当遇见弯路的时候误差值会大于一个值然后进行减速当然速度不同是也要改变循迹时候的PID数值才会更合适;弯道可以大点给P可以将车过弯改变成内切。

## <font  face=黑体 color=#7a37ab>4.5环岛的策略制定	</font>
在我的环岛处理中我运用了连续标志位,首先是遇见环岛,进入环岛,出环岛,经过环岛只有把每个步骤的补线写的足够准确才能很丝滑的进入进出如图;
 
显识别A点为遇见环岛标志位连接AB使车能直线经过至环岛中间,寻找C点将B对称点与C 连接这是进入环岛的标志,出环岛寻找A点即为出环岛标志位,连接A和B的对称点当车出环岛以后在检测C点为过环岛标志位连接BC经过环岛连接可以用曲线,直线效果也很好。
## <font  face=黑体 color=#7a37ab>4.6十字路口的策略制定</font>

 
十字路口如果直线通过不处理也是可以的但如果不是直线预见比如斜入十字路口应该连接AC和BD根据正常连续的边线算出斜率能更稳的进入十字路口,
不会出现左拐或者右拐。识别断点的时候可以通过判断赛道宽度的突变即可判断出十字路口的断点
## <font  face=黑体 color=#7a37ab>4.7三岔路口的策略制定</font>
 
遇见三岔路口时摄像头所识别到的赛道宽度会突然变宽同时赛道的斜率通过最小二乘法为1.732,限定一个范围值确保成功率但是限定的值也不要过于宽松以免误判。通过定时器积分控制转向角度。转过去之后切换横向循迹,再次识别到三岔路口转向回来切换正常循迹即可。
## <font  face=黑体 color=#7a37ab>4.8屏幕按键调参</font>
由于调试参数的时候频繁下载会很浪费时间把参数都输出在屏幕上由于本人屏幕是isp的屏幕大小用四个按键实现了屏幕翻页屏幕选择参数确认取消调节参数大小等功能。使用非常的方便源码我会放在最后。uint8 page = 4;
```python
&emsp;&emsp;uint8 show_clear;
&emsp;&emsp;uint8 edit;
&emsp;&emsp;uint8 options_first = 1;
&emsp;&emsp;uint8 options_second = 0;
//拨码开关状态变量

//开关状态变量
&emsp;&emsp;uint8 key1_status = 1;
&emsp;&emsp;uint8 key2_status = 1;
&emsp;&emsp;uint8 key3_status = 1;
&emsp;&emsp;uint8 key4_status = 1;

//上一次开关状态变量
&emsp;&emsp;uint8 key1_last_status;
&emsp;&emsp;uint8 key2_last_status;
&emsp;&emsp;uint8 key3_last_status;
&emsp;&emsp;uint8 key4_last_status;

//开关标志位
&emsp;&emsp;uint8 key1_flag;
&emsp;&emsp;uint8 key2_flag;
&emsp;&emsp;uint8 key3_flag;
&emsp;&emsp;uint8 key4_flag;
/*---------------------------  按键扫描  --------------------------------------------*/
/*	@	沈阳工业大学
/*	@	SUT_MEIC_ZWX
/*-----------------------------------------------------------------------------------*/
&emsp;&emsp;void Key_process(void)
{

  //保存按键状态
&emsp;&emsp;key1_last_status = key1_status;
&emsp;&emsp;key2_last_status = key2_status;
&emsp;&emsp;key3_last_status = key3_status;
&emsp;&emsp;key4_last_status = key4_status;
  //读取当前按键状态
&emsp;&emsp;key1_status = gpio_get(KEY1_PIN);
&emsp;&emsp;key2_status = gpio_get(KEY2_PIN);
&emsp;&emsp;key3_status = gpio_get(KEY3_PIN);
&emsp;&emsp;key4_status = KEY4_PIN;
  //检测到按键按下之后  并放开置位标志位
&emsp;&emsp;if(key1_status && !key1_last_status)    key1_flag = 1;
&emsp;&emsp;if(key2_status && !key2_last_status)    key2_flag = 1;
&emsp;&emsp;if(key3_status && !key3_last_status)    key3_flag = 1;
&emsp;&emsp;if(key4_status && !key4_last_status)    key4_flag = 1;

	//屏幕调参------------------------------------------------------------------------------------------------
&emsp;&emsp;if(edit)
		{
&emsp;&emsp;if(page==Page_1)//第一页
			{
&emsp;&emsp;if(options_second)
				{
&emsp;&emsp;if(key4_flag)
					{
&emsp;&emsp;key4_flag = 0;//使用按键之后,应该清除标志位
&emsp;&emsp;options_second = 0;
					}
&emsp;&emsp;else if(options_first==1)
					{
&emsp;&emsp;if(key1_flag)
						{
&emsp;&emsp;key1_flag = 0;//使用按键之后,应该清除标志位
&emsp;&emsp;P_tiaojie = P_tiaojie+0.001;
						}
&emsp;&emsp;if(key2_flag)
						{
&emsp;&emsp;key2_flag = 0;//使用按键之后,应该清除标志位
&emsp;&emsp;P_tiaojie = P_tiaojie-0.001;
						}
					}
&emsp;&emsp;else if(options_first==2)
					{
&emsp;&emsp;if(key1_flag)
						{
&emsp;&emsp;key1_flag = 0;//使用按键之后,应该清除标志位
&emsp;&emsp;pid_9 = pid_9+0.01;
						}
&emsp;&emsp;if(key2_flag)
						{
&emsp;&emsp;key2_flag = 0;//使用按键之后,应该清除标志位
&emsp;&emsp;pid_9 = pid_9-0.01;
						}
					}
&emsp;&emsp;else if(options_first==3)
					{
&emsp;&emsp;if(key1_flag)
						{
&emsp;&emsp;key1_flag = 0;//使用按键之后,应该清除标志位
&emsp;&emsp;pid_end = pid_end+0.001;
						}
&emsp;&emsp;if(key2_flag)
						{
&emsp;&emsp;key2_flag = 0;//使用按键之后,应该清除标志位
&emsp;&emsp;pid_end = pid_end-0.001;
						}
					}
&emsp;&emsp;else if(options_first==4)
                    {
&emsp;&emsp;if(key1_flag)
                        {
&emsp;&emsp;key1_flag = 0;//使用按键之后,应该清除标志位
&emsp;&emsp;pid_else = pid_else+0.001;
                        }
&emsp;&emsp;if(key2_flag)
                        {
&emsp;&emsp;key2_flag = 0;//使用按键之后,应该清除标志位
&emsp;&emsp;pid_else = pid_else-0.001;
                        }
                    }
&emsp;&emsp;else if(options_first==5)
                    {
&emsp;&emsp;if(key1_flag)
                        {
&emsp;&emsp;key1_flag = 0;//使用按键之后,应该清除标志位
&emsp;&emsp;Dd = Dd+0.001;
                        }
&emsp;&emsp;if(key2_flag)
                        {
&emsp;&emsp;key2_flag = 0;//使用按键之后,应该清除标志位
&emsp;&emsp;Dd = Dd-0.001;
                        }
                    }
				}
				else
				{
&emsp;&emsp;if(key4_flag)
					{
&emsp;&emsp;key4_flag = 0;//使用按键之后,应该清除标志位
&emsp;&emsp;edit = 0;
&emsp;&emsp;options_first = 1;
					}
&emsp;&emsp;else if(key1_flag)
					{
&emsp;&emsp;key1_flag = 0;//使用按键之后,应该清除标志位
&emsp;&emsp;options_first++;
					}
&emsp;&emsp;else if(key2_flag)
					{
&emsp;&emsp;key2_flag = 0;//使用按键之后,应该清除标志位
&emsp;&emsp;options_first--;
					}
&emsp;&emsp;else if(key3_flag)
					{
&emsp;&emsp;options_second = 1;
&emsp;&emsp;key3_flag = 0;//使用按键之后,应该清除标志位
					}
&emsp;&emsp;options_first = (options_first > 5) ? 5 : options_first;
&emsp;&emsp;options_first = (options_first < 1) ? 1 : options_first;
				}

			}
&emsp;&emsp;else if(page==Page_2)//第二页
			{
//					if(options_second)
//					{
//						if(key4_flag)
//						{
//						key4_flag = 0;//使用按键之后,应该清除标志位
//						options_second = 0;
//						}
//						else if(options_first==1)
//						{
//							if(key1_flag)
//							{
//							  key1_flag = 0;//使用按键之后,应该清除标志位
//							  Motor_Kp = Motor_Kp+0.001;
//							}
//							if(key2_flag)
//							{
//							  key2_flag = 0;//使用按键之后,应该清除标志位
//							  Motor_Kp = Motor_Kp-0.001;
//							}
//						}
//						else if(options_first==2)
//						{
//							if(key1_flag)
//							{
//							  key1_flag = 0;//使用按键之后,应该清除标志位
//							  Motor_Ki = Motor_Ki+0.01;
//							}
//							if(key2_flag)
//							{
//							  key2_flag = 0;//使用按键之后,应该清除标志位
//							  Motor_Ki = Motor_Ki-0.01;
//							}
//						}
//						else if(options_first==3)
//						{
//							if(key1_flag)
//							{
//							  key1_flag = 0;//使用按键之后,应该清除标志位
//							  Motor_Kd = Motor_Kd+0.001;
//							}
//							if(key2_flag)
//							{
//							  key2_flag = 0;//使用按键之后,应该清除标志位
//							  Motor_Kd = Motor_Kd-0.001;
//							}
//						}
//					}
//					else
//					{
//						if(key4_flag)
//						{
//						key4_flag = 0;//使用按键之后,应该清除标志位
//						edit = 0;
//						options_first = 1;
//						}
//						else if(key1_flag)
//						{
//						key1_flag = 0;//使用按键之后,应该清除标志位
//						options_first++;
//						}
//						else if(key2_flag)
//						{
//						key2_flag = 0;//使用按键之后,应该清除标志位
//						options_first--;
//						}
//						else if(key3_flag)
//						{
//						options_second = 1;
//						key3_flag = 0;//使用按键之后,应该清除标志位
//						}
//						options_first = (options_first > 3) ? 3 : options_first;
//						options_first = (options_first < 1) ? 1 : options_first;
//					}
			}
&emsp;&emsp;else if(page==Page_3)//第三页
			{
			}
&emsp;&emsp;else if(page==Page_4)//第四页
			{
			}
		}
		else
		{
&emsp;&emsp;if(key1_flag)
			{
&emsp;&emsp;key1_flag = 0;//使用按键之后,应该清除标志位
&emsp;&emsp;show_clear = 1;
&emsp;&emsp;page++;
			}
&emsp;&emsp;if(key2_flag)
			{
&emsp;&emsp;key2_flag = 0;//使用按键之后,应该清除标志位
&emsp;&emsp;show_clear = 1;
&emsp;&emsp;page--;
			}
&emsp;&emsp;if(key3_flag)
			{
&emsp;&emsp;edit = 1;
&emsp;&emsp;key3_flag = 0;//使用按键之后,应该清除标志位
			}
&emsp;&emsp;page = (page > 4) ? 4 : page;
&emsp;&emsp;page = (page < 1) ? 1 : page;
&emsp;&emsp;if(key4_flag)
			{

&emsp;&emsp;key4_flag = 0;//使用按键之后,应该清除标志位
			}
		}

}

/*---------------------------  屏幕显示  --------------------------------------------*/
/*	@	沈阳工业大学
/*	@	SUT_MEIC_ZWX
/*-----------------------------------------------------------------------------------*/
&emsp;&emsp;void Sut_show_page_1(void)
{

	//显示页数--------------------------------------------
&emsp;&emsp;ips114_showstr(100,0,"Page 1");
	//显示标题-------------------------------------------
&emsp;&emsp;ips114_showstr(10,2," Servo PID ");
	//内容------------------------------------------------
&emsp;&emsp;ips114_showstr(10,3,"P_tiaojie:");  				ips114_showfloat(90,3,P_tiaojie,2,3);	   if(edit&&options_first==1){if(options_second)ips114_showstr(150,3,"< >");else ips114_showstr(150,3," * ");}else ips114_showstr(150,3,"   ");
&emsp;&emsp;ips114_showstr(10,4,"pid_9:");   					ips114_showfloat(90,4,pid_9    ,2,3);      if(edit&&options_first==2){if(options_second)ips114_showstr(150,4,"< >");else ips114_showstr(150,4," * ");}else ips114_showstr(150,4,"   ");
&emsp;&emsp;ips114_showstr(10,5,"pid_end:");   					ips114_showfloat(90,5,pid_end  ,2,3);      if(edit&&options_first==3){if(options_second)ips114_showstr(150,5,"< >");else ips114_showstr(150,5," * ");}else ips114_showstr(150,5,"   ");
&emsp;&emsp;ips114_showstr(10,6,"pid_else:");                   ips114_showfloat(90,6,pid_else  ,2,3);     if(edit&&options_first==4){if(options_second)ips114_showstr(150,6,"< >");else ips114_showstr(150,6," * ");}else ips114_showstr(150,6,"   ");
&emsp;&emsp;ips114_showstr(10,7,"Dd:");                         ips114_showfloat(90,7,Dd  ,2,3);           if(edit&&options_first==5){if(options_second)ips114_showstr(150,7,"< >");else ips114_showstr(150,7," * ");}else ips114_showstr(150,7,"   ");
}

&emsp;&emsp;void Sut_show_page_2(void)
{

	//显示页数------------------------
&emsp;&emsp;ips114_showstr(100,0,"Page 2");
	//显示标题----------------------------
&emsp;&emsp;ips114_showstr(10,2," Motor speed ");
	//内容-------------------------------
//	ips114_showstr(10,3,"zq:");  					ips114_showint16(60,3,slave_encoder_left);
//	ips114_showstr(10,4,"yq:");   					ips114_showint16(60,4,slave_encoder_right);
//	ips114_showstr(10,5,"zh:");   					ips114_showint16(60,5,encoder_data[1]);
//	ips114_showstr(10,6,"yh:");	                    ips114_showint16(60,6,encoder_data[2]);
&emsp;&emsp;ips114_showstr(10,7," Current:");               ips114_showfloat(70,7, Current,2,3);
&emsp;&emsp;ips114_showstr(10,3,"icm_gyro_x:");             ips114_showfloat(120,3,icm_data.gyro_z ,4,3);
&emsp;&emsp;ips114_showstr(10,4,"pitch:");                  ips114_showfloat(120,4,eulerAngle.pitch,4,3);
&emsp;&emsp;ips114_showstr(10,5,"roll:");                   ips114_showfloat(120,5,eulerAngle.roll,4,3);
&emsp;&emsp;ips114_showstr(10,6,"yaw:");                    ips114_showfloat(120,6,eulerAngle.yaw,4,3);
//	ips114_showstr(10,6,"pid_else:");               ips114_showfloat(90,6,pid_else  ,2,3);
//	ips114_showstr(10,7,"Dd:");                     ips114_showfloat(90,7,Dd  ,2,3);
//    ips114_showstr(10,3,"meetRingFlag:");                      ips114_showint16(120,3,meetRingFlag);
//    ips114_showstr(10,4,"ringSide:");                     ips114_showint16(120,4,ringSide);
//    ips114_showstr(10,5,"leaveRingFlag:");                     ips114_showint16(120,5,leaveRingFlag);
//    ips114_showstr(10,6,"passRingFlag:");                      ips114_showint16(120,6,passRingFlag);
}

&emsp;&emsp;void Sut_show_page_3(void)
{

	//显示页数------------------------
&emsp;&emsp;ips114_showstr(100,0,"Page 3");
	//显示标题----------------------------
&emsp;&emsp;ips114_showstr(10,2," ADC raw");											//	ips114_showstr(140,2," ADC dispose  ");
	//内容-------------------------------
&emsp;&emsp;ips114_showstr(0,4,"ADC_1:");											//			ips114_showstr(120,4,"ADC_1:");
&emsp;&emsp;ips114_showint16(60,4,ADC[1]);                	  // ips114_showuint16(120+6*8,4,Sut_answer_adc[0]);
&emsp;&emsp;ips114_showstr(0,5,"ADC_2:");	                          //ips114_showstr(120,5,"ADC_2:");
&emsp;&emsp;ips114_showint16(60,5,ADC[2]);                  //  ips114_showuint16(120+6*8,5,Sut_answer_adc[1]);
&emsp;&emsp;ips114_showstr(0,6,"ADC_3:");	                         // ips114_showstr(120,6,"ADC_3:");
&emsp;&emsp;ips114_showint16(60,6,ADC[3]);                //    ips114_showuint16(120+6*8,6,Sut_answer_adc[2]);
&emsp;&emsp;ips114_showstr(0,7,"ADC_4:");	                          //ips114_showstr(120,7,"ADC_4:");
&emsp;&emsp;ips114_showint16(60,7,ADC[4]);                 //   ips114_showuint16(120+6*8,7,Sut_answer_adc[3]);
//	ips114_showstr(0,4,"black_l:");                                           //          ips114_showstr(120,4,"ADC_1:");
//	ips114_showint16(60,4,black_l);                    // ips114_showuint16(120+6*8,4,Sut_answer_adc[0]);
//	ips114_showstr(0,5,"black_z:");                             //ips114_showstr(120,5,"ADC_2:");
//	ips114_showint16(60,5,black_z);                  //  ips114_showuint16(120+6*8,5,Sut_answer_adc[1]);
//	ips114_showstr(0,6,"black_r:");
//	ips114_showint16(60,6,black_r  );
}

&emsp;&emsp;void Sut_show_page_4(void)
{

	//显示页数------------------------
&emsp;&emsp;ips114_showstr(100,0,"Page 4");
	//显示标题----------------------------
&emsp;&emsp;ips114_showstr(100,1," Camera ");
	//内容-------------------------------

&emsp;&emsp;for(int a=0; a<MT9V03X_H; a++)      //屏幕画线显示
	        {
&emsp;&emsp;ips114_drawpoint((uint16)Mid_Line[a]+35,(uint16)a+35,BLUE);  //找到的中线显示
	        }

&emsp;&emsp;ips114_displayimage032_zoom1(mt9v03x_image[0], MT9V03X_W, MT9V03X_H, 35, 35, MT9V03X_W, MT9V03X_H);
&emsp;&emsp;ips114_showstr(10,6,"left:");                     ips114_showint16(60,6,leftdistance );
&emsp;&emsp;ips114_showstr(115,6,"right:");                     ips114_showint16(165,6,rightdistance);
//            ips114_showstr(10,6,"k_huandao:");                     ips114_showfloat(90,6,k_huandao,2,3);
           // ips114_showstr(110,6,"k_right:");                    ips114_showfloat(175,6,k_right,2,3);
&emsp;&emsp;ips114_showstr(10,7,"slowflag:");                      ips114_showint16(90,7,slowflag);
}

 

第五章 发环境和调试方法


章主要介绍设计中所需要用到的开发环境以及智能车制作时的一些调试方法。

5.1 开发工具

程序的开发是在MounRiver Studio下进行的,包括源程序的编写、编译和链接,并最终生成可执行文件。

5.2 调试过程

5.2.1 上位机系统

要分析车模在赛道行驶的实时情况,必须采集小车在行驶过程中各个功能模块的实时数据,我们采用无线串口模块和1.14寸IPS液晶屏模块,然后用上位机分析。它是调试的必备工具,包括软件和硬件部分

硬件方面:
上位机通过无线串口用来接收单片机传来的实时数据,1.14寸IPS液晶屏用
来显示摄像头图像的情况。

 

第六章


2020年11月中旬第16届规则出来我们备赛开始,起初的时候什么都不懂大一新生刚接触单片机没多久,从配置底层初始化的问题开始,不知道与困难纠缠了多少个日日夜夜,虽然很苦但是也提高了自己找到问题分析问题的能力。我们也记不清像比赛的那天早上的朝阳我们是第多少次看见了。经过了这次比赛我们三个都变了好多,都变得细心了,变得耐心了,一个齿轮我们可以蹲在那里调上大半天;今年临期比赛的时候车突然出问题了一点点从屏幕功能摄像头功能开始坏后来才发现是芯片寿命到了;今年是我们学校第二年正式参加全国大学生智能车竞赛,由于我们大一经验不足,经费也不是太充足,但是我们从来没有想要放弃的念头,经验不足,我们熬夜来补,经费不足,我们从自己本来就不多的生活费里抽,苦了我们可以,苦了我们的车不行!我们从未设想今天的我们能获得这么好的奖项,和顶尖大佬站在了同一个领奖台上。我们只是怀揣着对智能车那份炽热的爱而去坚持去做这件事其中的日子过的很开心很充实。

最后感谢全国大学生智能车竞赛的主委会,如果没有你们,像我们这种普通学校的学生可能永远也不会接触到智能车,不会有这个机会与全国高校同台竞技。你们提供了一个平台,一个可以让每一个大学生圆梦的平台,你们圆了无数有志大学生的竞赛梦,如果可以的话,我想替所有想说出这句话的大学生们说一声:谢谢!同时也感谢学校领导对此比赛的大力支持,为我们提供了优越的调车环境;感谢所有为了这个比赛殚精竭虑的老师们对我们的信任与鼓励;感谢每天对我们微笑的门卫大爷;感谢每天为我们打扫卫生的保洁阿姨。这个奖项有你们所有人的努力!

 

第七章 型车的主要技术参数


  • 赛车基本参数 长 250cm
  • 宽 205m
  • 高 27.6cm
  • 车重 1.5kg
  • 功耗 空载 28W
  • 带载 大于30W
  • 电容总容量 916uF
  • 传感器 编码器 4个
  • 陀螺仪 1个
  • 10mH的电感 3个
  • 摄像头 2个
  • 除了车模原有的驱动电机、舵机之外伺服电机个数 0
  • 赛道信息检测 精度(近/远) 300/1500mm
  • 频率 20ms

■ 附录A:程序源代码

■ 中断程序

&emsp;&emsp;void EXTI2_IRQHandler(void)
{
&emsp;&emsp;if(SET == EXTI_GetITStatus(EXTI_Line2))
     {
&emsp;&emsp;EXTI_ClearITPendingBit(EXTI_Line2);
&emsp;&emsp;get_icm20602_gyro_spi();
         //ICM_getEulerianAngles();
&emsp;&emsp;encoder_get();
&emsp;&emsp;dc_get();

&emsp;&emsp;if( flag==0 &&  goflag==0)//出库程序
         {
&emsp;&emsp;go_out();
         }
&emsp;&emsp;if( flag==0 && sanchaflag==0 && goflag==1)//正常走
         {
&emsp;&emsp;seek_pid();

         }
&emsp;&emsp;if(flag==0 && sanchaflag==1 && entertimes==0)//进入右三岔
         {
&emsp;&emsp;trans(25);

&emsp;&emsp;if(flag==0 && sanchaflag1==1)//出去右三岔
             {
&emsp;&emsp;trans1(50);
             }
           }

&emsp;&emsp;if(flag==0 && sanchaflag==1 && entertimes==1)//进入左三岔
         {
&emsp;&emsp;trans3(25);

&emsp;&emsp;if(flag==0 && sanchaflag1==1 )//出去左三岔
             {
&emsp;&emsp;trans2(5);
             }
         }
&emsp;&emsp;if(flag==1 && stoptimes==1)//第二次斑马线入库
         {
&emsp;&emsp;come_out();
         }
&emsp;&emsp;if(flag==1 && stoptimes==0)//第一次斑马线直行
         {
&emsp;&emsp;goalone();
       }

     }


● 相关图表链接:

以上是关于智能车竞赛技术报告 | 全向行进组 - 沈阳工业大学 - 找不到北队的主要内容,如果未能解决你的问题,请参考以下文章

智能车竞赛技术报告 | 全向行进组 - 东北林业大学- 进取号E

智能车竞赛技术报告 | 双车接力组 - 沈阳航空航天大学 - 精神小车成双 - 双轮车

智能车竞赛技术报告 | 双车接力组 - 沈阳航空航天大学 - 精神小车成双 - 三轮车

智能车竞赛技术报告 | 专科基础组 - 沈阳职业技术学院 - 秋名山菜鸟队

第十六届智能车竞赛备战新进展

智能车竞赛技术报告 | 单车拉力组 - 沈阳航空航天大学 - 青梅绿茶队