4.1 软件系统概述
智能小车的软件系统采用模块化的程序结构。系统的软件设计包括小车的状态信息检测、控制算法和执行控制三大部分。其中,状态信息检测部分包括道路信息检测、速度检测和路程检测。道路信息检测由CCD摄像头视频信号采集和处理两部分组成;控制系统分为方向控制系统与速度控制系统。方向控制系统能使智能车沿着导引黑线行驶而不至偏移。速度控制能使智能车在直道上加速行驶而在入弯时刹车减速以尽量提高行驶速度和避免因入弯速度过快而造成的冲出赛道[4]。涉及MC9S12DG128的ADC模块、定时器/计数器模块、PWM模块、外部中断等的使用。开发工具Metrowerks的Code Warrior IDE V3.1编译器,主要用C语言进行代码的编写。调试工具使用清华大学摩托罗拉MCU应用开发中心的BDM调试模块。[5]
在智能车算法设计中可供选择的算法有经典PID算法,模糊控制算法和神经网络算法,前馈控制算法。
几种控制算法的比较:
⑴ PID算法:PID算法的优点是算法理论成熟,不要求有精确的被控对象数学模型。所以采用PID算法可以极大地减少建模工作,而将工作重点转移到PID控制参数的整定上来。并且有非常成熟的参数整定方法可用。PID控制算法的性能稳定可靠,开发风险小。
⑵ 智能控制算法:飞思卡尔HCS12微处理器内置模糊控制指令。使用它可以极大地加快模糊判决速度,减轻CPU的负荷。但是如果采用模糊控制,最后的整定与调试工作将相对PID控制来说变得比较困难。
⑶ 神经网络算法:神经网络算法模拟了人的大脑的判断过程,最主要的优点是容易实现自学习。但是神经网络方法的运算量大,要求的存储单元多。本设计是用微控制器实现的快速运动中的系统。由于S12运算能力以及系统快速性要求等方面的限制,决定了神经网络算法并不是适合本系统的算法。
⑷ 前馈控制方法:由于前馈控制是一种开环控制,在前馈会路中,它不能完全校正对应的干扰对被调参数的影响。解决的方法之一是利用数字计算机建立精确的系统模型;另一种更为有效的方法是前馈控制和反馈控制相结合,构成前馈反馈控制系统,这样的系统既具有前馈控制动作及时的特点,又保持了反馈控制的许多优点。
4.1.1方向控制算法
方向控制采用典型的闭环控制方法,框图如图4.1所示。
对于方向控制,并不要求特别高的控制性能,只要求快速性好,稳定性高。所以将PID算法作为首选算法。[6]
方案选择:考虑到积分环节影响动态性能,所以方向控制采用离散型PD控制算法。

4.1.2 速度控制算法
在车模不打滑的情况下,仅使用方向控制就可以实现车模跟踪黑色导引线的设计目标。但是经过试验,车模的动力非常强劲,如果不进行有效的速度控制,就不可能实现车模的稳定控制。竞赛的评价指标是以车模的行驶速度为主的,所以为提高竞赛成绩就要求尽量提高车模行驶速度。而为了提高车模运行稳定性,就要求车模在行驶过程中不能出现打滑的现象,减小车速却是一个直接的解决打滑问题的方法。所以,车模行驶速度和行驶稳定性之间存在一对矛盾。而解决这一对矛盾的方法就是设计合理的速度控制方案。 电机是一个常用的被控对像,基于电机转速控制的控制方法已相当成熟。对于智能车所使用的直流电机使用PID控制就能达到非常好的控制效果。毕竟电机速度控制器仅是智能车控制系统中的一个小的子系统,没有必要采用过于复杂的控制方法。所以,在本设计中,采用离散型PID算法来控制电机速度器。框图如图4.2所示。

4.2 各功能模块的算法实现
4.2.1 COMS视频成像原理
摄像头分黑白的和彩色的这两种,为达到寻线目的,只需提取探测画面的灰度信息,而不必提取其色彩信息,所以本设计中采用黑白摄像头,相较使用同等分辨率的彩色摄像头而言,这样可减少单片机采样摄像头输出视频信号的负担。一下讲述黑白摄像头采集图像信息的机制、视频信号的相关参数和如何提高采样速度所作的考虑。
摄像头采样机制
摄像头主要由镜头,图像传感芯片和外围电路构成。图像传感芯片又是其最重要的部分,摄像头的指标(如黑白或彩色,分辨率)就取决于图像传感芯片的指标;该芯片要配以合适的外围电路才能工作,将它们制作在一块电路板上,称为“单板”。若给单板配上镜头、外壳、引线和接头,这就构成了通常所见的摄像头。摄像头通常引出三个端子,一个为电源端,一个为地端,另一个就为视频信号端(有的摄像头多出一个端子,那是音频信号端)。电源接多大要视具体的单板而定,目前而言,一般有两种规格,6-9V,或9-12V。视频信号的电压一般不位于0.5V-2V 之间。 摄像头的主要工作原理是:按一定的分辨率,以隔行扫描的方式采样图像上的点,当扫描到某点时,就通过图像传感芯片将该点处图像的灰度转换成与灰度成一一对应关系的电压值,然后将此电压值通过视频信号端输出。具体而言(参见图4.3),摄像头连续地扫描图像上的一行,就输出一段连续的电压视频信号,该电压信号的高低起伏正反映了该行图像的灰度变化情况。当扫描完一行,视频信号端就输出一低于最低视频信号电压的电平(如0.3V),并保持一段时间。这样相当于,紧接着每行图像对应的电压信号之后会有一个电压“凹槽”,此“凹槽”叫做行同步脉冲,它是扫描换行的标志。然后,跳过一行后(因为摄像头是隔行扫描的方式),开始扫描新的一行,如此下去,直到扫描完该场的视频信号,接着就会出现一段场消隐区。此区中有若干个复合消隐脉冲(简称消隐脉冲),在这些消隐脉冲中,有个脉冲,它远宽于(即持续时间长于)其他的消隐脉冲,该消隐脉冲又称为场同步脉冲,它是扫描换场的标志。场同步脉冲标志着新的一场的到来,不过,场消隐区恰好跨在上一场的结尾部分和下一场的开始部分,得等场消隐区过去,下一场的视频信号才真正到来。摄像头每秒扫描25 幅图像,每幅又分奇、偶两场,先奇场后偶场,故每秒扫描50 场图像,每场图像20ms。奇场时只扫描图像中的奇数行,偶场时只扫描偶数行[7]。

摄像头有两个重要的指标:有效像素和分辨率。分辨率实际上就是每场行同步脉冲数,这是因为行同步脉冲数越多,则对每场图像扫描的行数也越多。事实上,分辨率反映的是摄像头的纵向分辨能力。有效像素常写成两数相乘的形式,如“320x240”,其中前一个数值表示单行视频信号的精细程度,即行分辨能力;后一个数值为分辨率,因而有效像素=行分辨能力×分辨率。 值得注意的是,通常产品说明上标注的分辨率不是等于实际分辨率(即每场行同步脉冲数),而是等于每场行同步脉冲数加上消隐脉冲数之和。因此,产品说明上标注的“分辨率”略大于实际分辨率。我们要知道实际的分辨率,就得实际测量一下。
通过S12 单片机的定时器模块对单个脉冲的下降沿和上升沿间隔、两相邻脉冲上升沿间隔进行计时,可得每行信号和每个脉冲持续的时间。实际测得所用摄像头的时序参数见表4.1。

从测得的结果可知,该摄像头扫描的每场中有316 行信号,其中第26 行到310 行是视频信号,第311 行到下一场的第25 行是场消隐信号。在视频信号区,每行信号持续的时间相同,约为64us;每行的行同步脉冲持续时间也相同,约为4.7us。而场消隐区持续的时间约为1480us。 采集速度
普通CCD图像传感器通过行扫描方式,将图像信息转换为一维的视频模拟信号输出。CCD输出的信号变化很快,比如PAL制式的视频信号,每秒钟输出50帧图像信息(分为奇、偶场),每帧图像有320行,每行图像信号时间为64微秒,其中有效的图像信号约为56微妙左右。相比之下,S12的AD转换器采集速度较低:根据S12器件手册,进行10位AD转换所需要的时间为7微秒。这样,采集的图像每行只能有8个像素,水平分辨率很低。另一方面,每场图像可以采集300行左右的图像信息,所以图像垂直分辨率相对较高。从这种水平分辨率低、垂直分辨率高的图像中,我们无法获取具有足够精度的路径信息。为此,我们设计了二值化电路。因为只需要识别黑色赛道和白色背景,所以我们利用该电路把视频模拟信号转换成高低电平的数字信号(高电平代表白色背景,低电平代表黑色赛道),单片机可以直接处理该信号。在图4.4中,上面曲线为行信号,下面曲线为二值信号。由二值信号曲线可以看出,黑线位置偏左。

4.2.2 图像采集功能的设计
视频模块是智能车沿黑线行驶的基础,是智能车的眼睛,而图像采集又是视频模块的基础,采集的数据必需准确、可靠,才能保证智能车正常行驶。 摄像头的模拟视频信号通过LM1881视频分离芯片分离出场同步信号和行同步信号,这两个信号分别接入单片机的两个中断口(PH0和PH1),利用中断控制数据采集的时序。 利用二值化处理电路把模拟视频信号转变为数字信号接入单片机的PA0口,该数字信号即代表了路面的灰度信息。信号处理的方框图如图4.5所示。

采样规划
摄像头采用的是隔行扫描的方式,为方便设计,忽略奇场和偶场在扫描位置上的细微差别,认为奇、偶场的扫描位置相同。由实测结果可知,所用摄像头每场信号的第26 行至第310 行为视频信号,即每场有285 行视频信号,这已远远超出了系统所需的精度要求。 实际没必要对这285 行中的每一行视频信号都进行采样,如此会增大S12 存储和数据处理的负担,甚至会超出S12 的处理能力。再者,这样做是没必要的,事实上,小车的定位系统在纵向上只要有10~20 个像素的分辨能力就足够了。因此,只需对这285 行视频信号中的某些行进行采样就行了。 综合以上考虑,在这285行中采样15行,作为数据处理的基础。 由于用了硬件二值化电路,免去了单片机处理模拟信号的A/D转换时间,又考虑到单片机指令执行时间的限制,通过设置单片机内部PLL寄存器对CPU进行超频处理,实际上每一行采样64个点。 通过以上分析,一幅图像的实际分辨率为15×64。该分辨率精度足够,能满足控制要求。
图像采样程序流程图

每一行数据采集完毕,将其存入save[15][64]中,例如第一行采集完毕,将其数据存入save[0][64]中。如此依次采集15行,此时一幅图像采集完毕。图4.7采集到RAM中的数据。

4.2.3 摄像头黑线位置识别
由于摄像头的视野很大,其干扰也较多。干扰分布的规律为:离摄像头越远,视野宽度越大,干扰越多;离摄像头越近,干扰越少;最近的一个纵向行几乎没有干扰。结合摄像头扫描的规律:从上到下,从左往右。我们发现:越先扫描的纵向行,离摄像头越远,干扰越多,其数据的可靠性越低,这对以后的数据处理和特征提取是非常不利的。因此,我们把摄像头旋转180度。旋转以后,越先扫描的纵向行,离摄像头越近,干扰越少,其数据的可靠性越高。[8] 我们利用superTV视频设备把摄像头采集的图像输出到显示器上以便观察。图4.8为图像示意图。注意到:离摄像头越近,黑线越宽。

定义黑线位置
一个纵向行采集64个点,对应数组save[0][64]的二维下标0到63,将黑线的范围定义在-31到31范围内,负数代表黑线在左边,正数代表黑线在右边。由于将摄像头旋转了180度,则情况刚好相反,即:负数代表黑线在右边,正数代表黑线在左边,零代表黑线居中。
计算黑线位置
基本思路:利用参考点,将纵向行采集到的64个点分为左右两个部分。分别找到左右部分离参考点最近的连续的数值为0(代表黑线)的点,求它们数组下标的平均值。如果左右两部分连续,则把左右平均值相加,否则,在左右平均值中,取离参考点近的值,最后求出的平均值减31即为黑线置。
4.2.4 舵机转向的控制算法
控制说明
脉宽范围:
对应舵机旋转角度,一方面舵机的极限位置;另一方面考虑到车模转向的极限。可以通过测试得到大约40 度左右;
PWM周期:
可选择50-200Hz
舵机PD控制算法
⑴ PID 算法简介

其中Kp为比例增益,Ti为积分时间常数,Td为微分时间常数,u(t)是控制量,e(t)是偏差。比例控制能迅速的反应误差,从而减小误差,但比例控制不能消除稳态误差,Kp的加大,会引起系统的不稳定;积分控制的作用是,只要系统存在误差,积分控制作用就不断地积累,输出控制量以消除误差,因而,只要有足够的时间,积分控制能完全消除误差,积分作用太强会使得系统的超调加大,甚至使系统出现震荡;微分控制可以减小超调量,克服震荡,使系统的稳定性提高,同时加快系统的动态响应速度,减小调整时间,从而改善系统的动态性能。
⑵ 数字PID控制算法
把设定值与反馈值的差定义为控制量,控制量的累加和即为积分量,控制量的差即为微分量。 在舵机的控制中我们去掉了积分项,因为积分会造成较长的调节时间,对动态性能产生不利影响。此外,由于舵机转动有极限,我们还作了控制量的限幅。
舵机PD程序
void duoji_pdcontrl(int set,int act)
{
turncha=set-act;
turnpwm=7000-(kp *turncha +kd_duoji*(turncha-turncha_last));
turncha_last=turncha;
if(turnpwm>8600) turnpwm=8600;
if(turnpwm<5400) turnpwm=5400;
duoji_SetDutyUS(turnpwm);
}
4.2.5 速度PID控制算法
我们用两个PWM口实现对电机的驱动和制动。如图4.10所示,PWM7用作电机驱动,PWM6用作电机制动,电机测速模块输出的模拟量通过AN15的A/D转换模块转换成数字量。

在速度的PID算法中,因长时间出现偏差或偏差较大,计算出的控制量有可能溢出,或小于零,所以要做抗积分饱和处理,通过指定控制量的上下限来避免积分饱和。
速度A/D转换函数
byte ad_speed_GetValue16(word *Values)
{
if (!OutFlg) /* Is output flag set? */
if (ATD1STAT0_SCF) {
ad_speed_OutV = ATD1DR0L; /* Save measured value */
OutFlg = TRUE; /* Measured value is available */
ModeFlg = STOP; /* Set the device to the stop mode */
}
else
return ERR_NOTAVAIL; /* If no then error */
*Values = ((word)(ad_speed_OutV)); /* Save measured values to the output buffer */
return ERR_OK; /* OK */
}
电机PID算法函数
void dianji_picontrl(word set,word act)
{
newn=set;
newm=act;
spdcha=newn-newm;
if(spdcha<-10) dianji_zhidong_SetVal();
else dianji_zhidong_ClrVal();
if(un!=65000) spdsum+=spdcha;
un=kp_dianji*spdcha+spdsum/ki_dianji;
if(un>65000) un=65000;
else if(un<0) un=0;
spdpwm=un;
dianji_qudong_SetRatio16(spdpwm);
}


