智能循迹小车设计报告

电子作品设计报告

         项目名称:­智能循迹小车

       

摘要:本组的智能循迹小车是采用自主设计的车体,以两个直流电机来驱动小车,各个模块自行设计。通过反射式红外光电传感器TCRT5000来采集跑道信息,传送至主控芯片STC12C5A60S2单片机, 进行数据处理后,送进驱动芯片L298N以完成相应的操作,实现小车的自主循迹功能。

关键词:STC12C5A60S2  L298N  反射式红外光电传感器TCRT5000  自动循迹

引言:

随着电子科技的迅猛发展,人们对技术也提出了更高的要求。汽车的智能化在提高汽车的行驶安全性,操作性等方面都有巨大的优势,在一些特殊的场合下也能满足一些特殊的需要。智能小车系统涉及到自动控制,车辆工程,计算机等多个领域,是未来汽车智能化是一个不可避免的大趋势。本文设计的智能小车以STC12C5A60S2单片机为控制核心,用反射式红外光电传感器TCRT5000作为检测元件实现小车的自主循迹前行功能。

一、系统设计

     本组智能小车的硬件主要有以STC12C5A60S2 作为微处理器,小车主要由自动循迹模块,电机驱动模块,前轮转向模块,电源模块,比较器模块组成。电机驱动部分我们采用12V直流电源直接供电,其他部分由3个5V稳压模块供电。

小车硬件系统结构示意图如下:

 

1.1设计要求:

   (1)实现小车沿规定轨迹前进 ;

   (2)电路板自行设计,车体不可采用飞思卡尔车模;

  1.2车体方案论证与选择:

根据比赛设计要求,我们的车模不可使用飞思卡尔或玩具车的整体车模,我们采用自主设计车体。一方面是符合比赛设计要求,另一方面是我们的车体要求不是很难,可以通过自己设计出来,节省大量资金,并且灵活性强。

二、硬件设计及说明

2.1原理图设计

2.1.1 稳压电源:

电源电路为系统提供了基准电源,是整个系统工作稳定性关键所在,所以我们选用了1个LM2940-5.0和2个LM7805来稳定电压输出(5V),使用了电解电容来作为滤波电容。其原理图如下:

2.1.2 基本系统:

基本系统控制电路采用单片机STC12C5A60S2作为微处理器,负责整个电路的资源分配以及对各路信号的采集、分析和处理。配置了12MHZ的外部晶振。单片机控制电路原理图如所示:

2.1.3 电机驱动:

驱动电路主要采用驱动芯片L298N来直接驱动电机,L298N是SGS公司的产品,内部包含4通道逻辑驱动电路。是一种二相和四相电机的专用驱动器,即内含二个H桥的高电压大电流双全桥式驱动器,接收标准TTL逻辑电平信号,可驱动46V、2A以下的电机。。L298N从主控单片机STC12C5A60S2那里接受指令来直接控制电机的工作状态。可以对电机进行正反转,停止的操作,非常方便。其驱动电路原理图如下所示:

2.1.6 循迹部分

主要由10个反射式红外光电传感器TCRT5000和3个LM339N比较器组成。采用TCRT5000型光电管完成系统循迹任务,循迹电路是用以实现小车沿着场地的白色轨迹进行前进和位置校正的,且小车不能偏离该轨迹。在本设计中采用TCRT5000型反射式红外光电传感器完成系统循迹任务,硬件电路实现比较简单,其灵敏度可以通过调节多圈电位器来实现。其电路原理图如下:

2.2 PCB设计

2.2.1 主板PCB图如下:

图1.主板PCB图

2.2.2 循迹板PCB

图2.循迹板PCB图

三、软件设计及说明

系统软件流程图如下图所示:

四、系统测试过程

测试工具:

五、总结

    本组设计的智能循迹小车,符合比赛设计要求,可以以较理想的速度在规定的轨道白色区域前进,并且很好的实现十字路口、S型弯道和上下坡的安全通过。当然我们的小车要想以更快更好的速度通过比赛轨道,还须进一步的改进传感器,软件等的设计。

六、附录

附件1:系统部分测试源程序

#include<STC12C5A60S2.H>

#include"PWM.H"

#include"Control_Wheels.h"

#include"inter.h"

#define uchar unsigned char

#define uint unsigned int

sbit IN1=P1^0;                        //驱动位定义

sbit IN2=P1^1;

sbit IN3=P1^2;

sbit IN4=P1^5;

/***********************************

函数功能:毫妙延时函数

入口参数:z                                                              

***********************************/

void delay_ms(uint r)

{

     uint i,j;

     for(i=0;i<r;i++)

     for(j=0;j<120;j++);

}     

/***********************************

函数功能:电机初始化

入口参数:无                                          ***********************************/

void DianJi_init()

{

     IN1=1;IN2=0;

     IN3=1;IN4=0;

     EN=1;IN5=0;IN6=0;

}

void main()

{   

     PWM_init();

     delay_ms(4000);

     DianJi_init();

     speed();

     Timer_Init();

     while(1)

     {

       Check_Load();

       Control_Wheels();

     }

Control_Wheels.h:         //速度和方向控制函数

sbit IN5=P3^5;              //转向位定义

sbit IN6=P3^6;

sbit EN =P3^7;

/*

sbit X1=P1^6;                             //最外传感器 P16 左边 P17 右边

sbit X2=P1^7;         */

sbit TU1=P3^0;                            //调速位定义

sbit TU2=P3^1;

uchar Load_Size=0;   //赛道类型存储变量

uchar Load_Size2=0;

uchar z=0,y=0;                    //速度调节变量

/************************************

函数功能:速度调节函数

入口参数:无                                                             

************************************/

void speed()

{

     if(TU1==0&&TU2==1)          //一级速度

     {

      z=100;y=100;

     }

     if(TU1==1&&TU2==0)                 //二级速度

     {

       z=80;y=80;

     }

     if(TU1==0&&TU2==0)                 //三级速度

     {

       z=50;y=50;

     }

     if(TU1==1&&TU2==1)                 //四级速度

     {

       z=0;y=0;

     }

     PWM_set(z,y);

}

    

void Check_Load(void)

{

     Load_Size = P2;        //读取P0端口,初步提取赛道信息

     P0 = Load_Size;             //

     Load_Size2=P1;                     

}

 /****************************************

函数功能:处理赛道信息                       传感器排列  左边低4位,右边高4位

入口参数:Load_Size                                              *****************************************/

void Control_Wheels(void)

{                

     if((Load_Size&0xf0)!=0)

     {

       IN5=0;IN6=1;  //左转;

     }

     if((Load_Size2&0x40)==0x40)

     {

       IN5=0;IN6=1;  //左转

     }

     if((Load_Size&0x0f)!=0)

     {

       IN5=1;IN6=0;          //右转

     }

     if((Load_Size2&0x80)==0x80)

     {

       IN5=1;IN6=0;          //右转

     }    

     if(Load_Size==0x00)

     {                                                                                                           

       IN5=0;IN6=0;          //直走

     }

     else

     {;}

}

}

                  

                          

 

第二篇:智能_循迹小车详细制作过程

技 术 报 告





目录

第一章  引言..............................................................................................1

1.1  智能车制作概述 ........................................................................1

1.2  参考文献综述 ............................................................................1

1.3  技术报告内容与结构 ................................................................1

第二章  设计方案概述 ............................................................................3

2.1  总体设计 ....................................................................................3

2.2  具体方案 ....................................................................................3

2.2.1 道路识别模块 ..................................................................3

2.2.2 速度检测模块 ..................................................................4

第三章  模型车整体设计 ........................................................................5

3.1  机械部分的调整 ........................................................................5

3.2  传感器设计与安装 ....................................................................5

3.2.1 光电管安装: ..................................................................5

3.2.2 摄像头安装: ..................................................................6

3.2.3 测速装置 ..........................................................................7

第四章  硬件电路设计 ............................................................................9

4.1  整体介绍 ....................................................................................9

4.2  各模块电路介绍 ..................................................................... 10

第五章  控制算法实现 ......................................................................... 15

5.1  总体软件设计 ......................................................................... 15

5.2  路径识别算法 ......................................................................... 16

5.2.2 基于光电管的模糊控制算法 ....................................... 16

5.2.2 基于CMOS的算法 ........................................................... 18

5.2.3 两者的结合 ................................................................... 20

5.3  速度控制算法 ......................................................................... 20

第六章  调试及主要问题解决 ............................................................. 23

6.1  调试工具 ................................................................................. 23

6.2  调试过程 ................................................................................. 24

6.3 主要技术参数说明 ................................................................. 25 第七章         结论..........................................................................................27 附录A    参考书目....................................................................................... I

附录B  部分程序...................................................................................... II



第一章  引言

1.1  智能车制作概述

本队在小车制作过程中,先对比赛内容,要求与规则进行了详细分析,然后 按照要求制订了几种设计方案,并对几种方案进行比较敲定最后方案。根据方 案完成小车的总体设计和详细设计(包括底层硬件设计和总体软件设计),在完 成 了车模组装和改造后,完成了各个模块的硬件电路设计与安装,并进行了控制 算法的设计和软件实现,最后进行了整车的调试和优化。

1.2  参考文献综述

方案设计过程中参考了一些相关文献,如参考文献所列。例如文献 1 与 2 单片机嵌入式系统在线开发方法。文献 3 与 4 是计算机控制技术,参考了其中 PID 控制策略。文献 5 到 8 是介绍了微处理器 MC9S12DG128 芯片。文献 9 到

11 介绍了 CCD 图像传感器的应用和一些数据处理方法,等等。

1.3  技术报告内容与结构

本文的主要内容框架如下: 第一章:引言。大概介绍了智能车的制作过程,参考文献说明和内容框架。 第二章:设计方案概述。介绍了各种方案,以及选择该方案的原因。 第三章:模型车机械调整。介绍了小车机械结构的调整和传感器的安装步

骤。

第四章:硬件电路设计。这部分是小车的硬件实现,主要给出了小车的总 体结构与各个模块的硬件电路设计。


第五章:控制算法实现。本章详细介绍了各个方案采用的算法。

第六章:调试及模型车技术参数。介绍了调试使用的工具与具体调试过程, 最后给出了整车的技术参数。

第七章:总结。对整个模型车制作过程的总结,指出试验中发现的问题和 进一步改进的方向。


第二章  设计方案概述

2.1  总体设计

由于赛道整体布局未知,因此先保证小车在各种不同环境下能够稳定运行, 再进行速度的提升。故稳定性是设计中首要解决的问题。

常用的寻线方法主要有光电寻线和摄像头寻线,共有三种路径识别策略。 一、光电寻线:由多对红外收发管组成,通过检测接收到的反射光强判断赛道

中心黑道位置。

优点:电路设计简单,信息处理方便。 缺点:一对收发管只能检测一个点的信息,精度有限,前瞻距离远小。过

弯减速剧烈,难以提高整体的运行速度。

二、摄像头寻线:图像采集,动态拾取路径信息。 优点:信息量大,前瞻,能耗低的优点,能提前判弯减速。 缺点:受到的干扰较多,转弯时数据易丢失,处理相对复杂。

三、光电管与摄像头结合寻线:兼顾了光电寻线的抗干扰能力强和摄像头寻线 前瞻性远、信息量大的特点。

难点:光电管与摄像头之间的配合,两者切换的条件。

2.2  具体方案

2.2.1 道路识别模块

使用了 CMOS 摄像头和单排七对红外发射接受二极管。根据比赛环境的不同


可灵活选择各个方案。

在光电管与摄像头结合寻线模式里,使用光电管检测的信息作为整幅图像 处理的第一行,在采集的图像干扰过多或信息量过少时切换到光电管循线的模 式。

2.2.2 速度检测模块

速度传感器由一对光电管和贴在驱动电机齿轮上的纸质圆盘组成,即采用 的是反射式光电传感器。反射式光电传感器的光源有多种,我们选择的是较为 经济的红外发光二极管。


第三章  模型车整体设计

3.1  机械部分的调整

硬件部分的合理安装是模型车能良好发挥的前提条件,这里主要介绍实际 中的几点经验。

首先是舵机的安装,要想使前轮及时地反映舵机的控制,应尽量避免舵机 不动、轮子能转动的情况,具体做法是使舵机输出连接件之间配合紧密,减少 缝隙。前轮外倾角和前轮前束之间有一定的配合,前轮前束大,转向不利,电 机的负荷也变大。

3.2  传感器设计与安装

3.2.1 光电管安装:

基于时间上和调试的考虑,设计使用了 7 对红外发射和接收光电管采取 “一”字形排列的方式,相邻两光电管间隔 20mm。为便于接收管接收路面反射回 的红外光,安装时使发射管和接收管互相有一个倾角。通过给接收管加上一定 长度的黑色套管减少相邻红外光的干扰,制作的光电管如图示:


图 4.1  光电管

为提高光电管的前瞻性,安装时将其抬高置于小车前方并给 30 度的前倾 角,综合抗干扰的因素,确定使发光管距地最大不超 7cm。当采用光电管与摄像 头结合策略时光电管采集的信息作为图像的第一条线,此时光电管应出现在摄 像头的视野中,经试验最终确定安装离地高度 6.5cm。

调试时观察不同接收管在黑线由远及近时的电压变化情况,确定各管的比 较电压的值,配合调整黑管长度,使得检测的数据能灵活反映黑线位置变化。 最后使光电管同处于一片白色的赛道上,将小车水平抬起到一定高度时,看到 所有接收管几乎在同一时刻检测到“黑”的状态,放下时又几乎在同一时刻检 测到全“白”的状态,此时大致调试完成,可以放到赛道上试跑。

3.2.2 摄像头安装:

摄像头有两种,CCD 摄像头和 CMOS 摄像头。CMOS 摄像头采集的图像信 息虽没有 CCD 摄像头优越,但使用电压低,功耗少,故本设计采用 CMOS 摄像 头的方式。摄像头的安装较为复杂,要调整好各个方面。CMOS  摄像头的安装 主要包括高度调整,倾角调整。

A)高度调整 提高摄像头的高度,可以在不改变倾角的条件下增大摄像头可视范围,但

是,随着摄像头高度的提升,小车的重心会不断上移,不利于保持车身的稳定


性。在小车高速过弯时,过高的重心可能产生明显的侧滑现象,甚至翻车。因

此,在保证车身稳定性的前提下,尽可能的增加摄像头的可视范围是摄像头高 度调整的目标。

B)倾角调整 倾角的大小主要关系到摄像头对前方路径的前探量。倾角越大,摄像头的

前瞻性也就越强,这对于高速行驶的小车有利。但是倾角过大造成外界强光射 入摄像头,增加了摄像头“失明”的风险,这就对抗干扰的算法提出了更高的 要求。所以,在保证摄像头正常工作的前提下,适当增加倾角,对提高小车的 行驶效果有利。

综合以上分析,并通过不断的试验调整,最终我们的摄像头安装调试如下: 摄像头高度:36cm

摄像头倾角:40 度

40度


37cm

36cm


图 4.2   实际制作的小车

3.2.3 测速装置

主要有两种简易的测速方案:透射光栅式和光电管对管反射式。反射式传 感器制作简单,只需手工用圆规和直尺画一个反射板,焊接简单的电压比较电


路即可,且效果也能很好的满足要求,因此选用光电管反射传感器。

传感器

反射板

图 4.3  传感器


第四章  硬件电路设计

4.1  整体介绍

智能赛车控制系统采用模块化设计,系统主要由电源模块、电机及其驱动 模块、舵机模块、测速模块、道路识别模块、调试模块和 MC9S12 单片机模块几

大部分构成。智能赛车整体装置结构设计框图如下:

电源模块

道路识


舵机控制信号


别模块                                          舵机

MC9S12单片机

(信号处理和 控制算法实现 )


调试模块

车速信号

速度检测

PWM驱动信号

后轮转动


电机 驱动模块

电机

图 4.1    智能车整体结构图


智能车控制系统根据各部件的正常工作的需要,对配发的标准车模用 7.2V、

1.8A/h的可充电Ni-Cd电源。其中单片机系统,路径识别的光电传感器和速度检测 电路需要 5V电源供电,舵机使用 6V,直流电机直接由电池供电。

考虑到启动和运行时产生的电压下降的现象,我们选用低压差稳压芯片

LM2940,它可以在 500mA 时稳压,最小压差仅为 0.6V。舵机电源使用可调变 压器 NPC565。系统整个供电如图 4.2 所示:

驱动电机

NCP565                    舵机

7.2v镍镉电池

单片机

LM2940

摄像头或

光电管

图4.2  智能车电源分配图

4.2  各模块电路介绍


速度检测电路


系统提供 6V 和 5V 两个直流电源,分别采用低压差稳压芯片 LM2940 和

NCP565 提供,电路图如下所示:


图 4.3   直流电源 6V 和 5V 的稳压电路

直流电机的控制一般由单片机的 PWM 信号来完成,驱动芯片我们采用飞思 卡尔半导体公司的 H 桥驱动芯片 MC33887。

图 4.4    电机驱动电路


图 4.5 同步信号分离电路

统一提供的 MCU 板的引脚分配如下:


调试模块的拨码开关电路:


图 4.6 插座电路


图 4.7 速度角度控制接口和开关接口

相应光电检测速模块电路图:

图 4.8 测速电路

第五章  控制算法实现

5.1  总体软件设计

智能小车的控制是采用模块化的结构,基本思路是:将方向传感器采集来 的道路信息和速度传感器采集来的当前速度值经 CPU 处理,输出 PWM 信号到驱 动舵机和电机。方向控制和速度控制系统分别构成两个闭环系统。在综合控制 算法中,两者可相互影响;比如根据路径识别的结果来控制速度,使得在弯道 上慢速,而在直道上快速。方向控制上我们使用了三种方法:完全基于摄像头 的决策,基于摄像头和光电管的共同决策,完全基于光电管的决策。

程序的总体结构流程图如下:

开始

MCU初始化

数据变量初始化

参数设置(工作模式选择)

模式选择(路径识别传感器选择)

方向控制

速度控制

图 5.1 总程序结构图


5.2  路径识别算法

路径识别模块的流程图如下:

参数设置(工作模式选择)

摄像头光电管共同决策模式

光电管决策模式


摄像头决策模式



图像采集与路径识别

光电管对路径的识别



图像有有效效

有 无效 效

光电管对路径的识别

基于光电管的方向控制

图像采集与路径识别


基于摄像头的方向控制


基于光电管的方向控制


速度控制


基于摄像头的方向控制



速度控制

速度控制


图 5.2 路径识别算法流程图

5.2.2 基于光电管的模糊控制算法

光电传感器获得的路面信息是离散、断续变化的,具有近似性、不完善性 并混杂一定的噪声,模糊控制能保证输出的连续性和平滑性并容纳这种不确定 的输入信息,产生光滑的输出控制量。同时小车的动力学模型复杂难以确定, 是一个典型的时延、非线性不稳定系统,而模糊控制并不依赖于控制系统精确 的数学模型,可以完成输入空间到输出空间的非线性映射。

模糊控制器主要由三部分组成,即模糊化,模糊规则推理及反模糊化。



输入隶属度函数

规则库


输出隶属度函数


模糊输入量                                                                                                模糊输出量                                                                       精确输

出量

模糊化

模糊推理化


反模糊化


传感器

受控对象

传感器

图 5.3 模糊控制器工作图


确定两个模糊输入量为 e,ec,表示赛道位置与模型车中心位置的偏差和偏

差的变化量,模糊输出量为 angle。e 为从-7 到+7,ec 为从-14 到+14,angle 为-37 至+37。各变量使用 11 个语言值{N5,N4,N3,N2,N1,ZE,P1,P2,P3, P4,P5}表示。相应的模糊规则库如下:

表 5.1 模糊规则库


5.2.2 基于 CMOS 的算法

由于设计中摄像头只用于采集道路的灰度信息,且黑白 CMOS 摄像头对路面 信息的采集已经完全能够达到对道路识别的精度要求,所以设计选用黑白 CMOS 摄像头,输出制式 PAL 信号,分辨率为 380 线。

处理时每隔 6 行采集 1 行数据,利用行同步和场同步的间隔时间来完成图 像的处理和智能车的控制。具体为通过查询的方式等待场同步信号,而行同步 信号则通过中断方式获得,在每个行同步信号到来时,采集一定数量的点,并 利用下一个行同步中断到来之前的间隔时间,完成一定的计算量,这里的计算 主要是相对本行的偏差。CMOS 采集图像的为 60*60。

通过试验发现,利用摄像头进行路径识别相对光电管有较大的前瞻性,从 而能提高车速。但是摄像头易受环境的干扰,主要是赛道周围黑色物体和光线 两类干扰,如果对这些外界干扰处理的不好,将严重影响智能车运行的稳定性, 甚至无法完成比赛。

为了抵抗这两种类型的干扰,本设计分别采用了以下抗干扰策略:

1)  针对赛道周围黑色物体的干扰,采用了一种基于连续性判断的寻线策略, 基本思想是:除了距离小车最近的一行外,每一行都以它的上一行作为本行找 线的基准位置,向两边扫描一定的像素,因为相邻两行黑线的中心位置的偏差 一定是小于某个值的,将该值适当放宽一些后,就可以保证快速的找到真正的 路径,同时把赛道周围的黑色干扰滤除。

基于以上分析可知,在计算第 n 行的黑线中心位置时,必须知道第 n-1 行的 黑线中心位置,而通常的摄像头都是从远到近扫描的,为了利用这种寻线策略, 实际中必须先获得较近行的图像信息。

这又有两种方案可供选择,一种常见的方案是将面阵 CMOS 的图像保存到 一个二维数组当中,等待最近的行信息获得后再进行处理。另外一种方案是, 将摄像头倒置安装,优先获取近处的行信息。综合比较两种处理方案不难发现, 第一种方案既浪费存储空间,又将所有行的寻线计算量积累在一个时间段计算

(一帧图像的结束),使用的单片机在短暂的时间内可能难以完成。如果采用第


二种方案,就可以边采集边计算,利用每一个行同步和其他不需采集行的时间

间隙,来完成该行寻线的计算任务。这样,当所有行采完的同时,也基本完成 了图像的处理和路径的识别任务。通过将复杂的计算任务分布开工作的方式, 为单片机的其他控制和运算节约了宝贵的时间。鉴于此,实际采用了第二种方 案(路径识别效果见图 5.4)。

图 5.4  路径识别效果

2)  针对赛道反光和周围直射光线的干扰,采用了以下几种抗干扰策略。

(1)由于赛道黑色引导线可能反光(如图 5.5)导致黑色引导线部分缺失, 可以采用线性拟合来对不完整的图像进行修补。图 5.6 是对图 5.5 进行修补后的 效果图。

(2)当图像缺失的比较严重,或者由于外界强光导致摄像头的完全失明 (如:赛场周围闪光灯的影响,正面直射光的通过赛道反射进入等),摄像头只会 使采集到全空的白数据。这种图像就是无法修补的了,此时可以采用两种方案: 一种方案是利用上一帧有效图像对智能车进行控制,另一种方案是将小车的控 制权转交给依靠其他辅助路径识别设备的决策模块。在我们的智能车设计中综 合使用了这两种方案。

图 5.5    道路反光后效果             图 5.6   修补后效果


5.2.3 两者的结合

这种方案是将光电管和摄像头结合起来的方法。具体方法是将光电管作为 摄像头的第一排,然后判断前面的道路信息是否有效,若无效的话此时切换到 光电管;有效的话继续用摄像头的有效信息。由于判断摄像头失效的条件还未 达到较好的状态,所以这种方法还在进一步探索中。

5.3  速度控制算法

在速度控制上,采用的是位置型数字PID算法和PD算法结合的策略。 数字PID控制关键的两个问题是:其一,速度反馈的精度;其二,PID参数

的配合。如何解决速度反馈精度的问题,关键在于提高速度检测的脉冲数的精 度,减少丢脉冲的个数。基于以上考虑,在选择处理脉冲的方法上,本设计采 用M法。即在固定周期内测量脉冲数。之所以采用M法,原因是:当控制周期较 长时,接受到脉冲数较多,对丢1、2个脉冲不敏感;当间隔周期较短和对象惯 性较大时,可认为脉冲数正比于电机转速,这样后续的地速度处理要也方便一 些,甚至可以直接用脉冲数直接代替车速参加运算。但是尽管如此,在车速很 低的时候,固定周期内测得的脉冲数很少,在这种情况下丢脉冲有较大偏差。

数字PID位置型控制算式为:


T

u(k)=k p [e(k)+

TI


K

e(i) +T D

i =0


e(k ) ? e(k ? 1) ]

T


其中 K p 称为比例增益, KI 称为积分系数, K D 称为微分系数。

当速度偏差大于一定范围时,采用PD控制,以提高动态性能和缩短调试周 期,相应控制算法流程图如下:


获取当前速度

Y

|速度值|>速度偏差域值


N

PID控制

PD控制


Y

采样周期到

N

输出PWM

图 5.7    速度控制算法



第六章  调试及主要问题解决

6.1  调试工具

系统在调试过程中使用到的调试工具如下:

CodeWarrior 4.1 调试软件,Plastid2 仿真软件,BDM 仿真器,直流稳压电源, 信号发生器,数字示波器,多功能数字万用表,串口调试软件。

其中串口调试软件是我们自行开发的工具,可以为摄像头采集的数据进行 分析和底层模块仿真。

软件运行界面如下:

图6.1 串口调试软件运行界面

6.2  调试过程

1)光电管的调整 主要通过调整比较器电压和接受管上套的黑管长度,使得检测的数据能灵

活反映黑线位置变化,出现相邻的光电接收管同时为 1 的状态且状态变化连续。

在确定硬件部分正常工作后,再进行控制算法的验证,针对出现的问题改动规 则库和隶属度函数的形状。语言值越多,角度分得越细,但相应规则库也越大, 使得反应速度变慢,并且没有必要。通过试验给各输入变量 11 个语言值,即 11 个隶属度函数的方式。

2)CMOS 摄像头的调试 由于摄像头的调试较为复杂,为了缩短调试周期,自行开发了摄像头调试

工具软件对摄像头采集的数据进行分析和底层模块仿真,即串口调试工具。在 高层算法上使用了清华大学的新版仿真软件 Plastid2 进行算法仿真验证。通过这 种分层调试的方法,解决了很多在赛车实际运行中无法发现的 Bug,使赛车在短 时间内达到了良好的运行效果。

3)电机的调整

通过设定小车的速度和运行时间,可得电机开环时的相应曲线如图,采样 时间周期是 20mm,纵轴为输入 PWM 脉冲数:

表 6.1    速度开环响应曲线

300

250

200

150

100

50

0

1

-50

可见开环时,小车加速到达稳态的时间约为 3.6s,减速需要时间约为 1s。

以下是加了 PID 控制和 PD 控制后的闭环响应图,纵轴为实测速度(cm/s):


表 6.2  速度闭环响应曲线

120

100

80

60

40

20

0

1  12 23 34 45 56 67 78 89 100 111 122 133 144 155 166 177 188 199 210 221 232 243 254

可见计入闭环控制后响应速度得到了明显提高,调节时间约为 1.2s。

为了检测过弯时的性能,进行了长直道加半径为 50mm 的 90°的弯道的 测试,所得数据绘图如下,  纵轴为实测速度(dm/s):

表 6.3   直道加弯道速度响应曲线

30

25

20

15

10

5

0

1  14 27 40 53 66 79 92 105 118 131 144 157 170 183 196 209 222 235 248

从实际效果来看,小车能做到在入弯前开始减速,基本做到向内侧

入弯,出弯约 10cm 开始加速,效果良好。

6.3  主要技术参数说明

车模参数:

长 29cm,宽 16cm,高 37cm ,重 2 kg

所有电容总容量:1653.78uF

传感器:


方案一:光电管7对

方案二:黑白 CMOS 摄像头 1 个

除了车模原有的驱动电机、舵机之外伺服电机个数:无

赛道信息检测精度:5mm

频率:50H


第七章  结论

设计中在摄像头安装上采用的高度,34cm 和 36cm。根据实验结果看,高 度在解决周围光线带来的影响同时,也使智能车重心过高、运行不稳定。摄像 头的高度固定后,不同的倾角对应视野大小不同,太近判弯不够及时,太远干 扰较多。机械安装时应注意舵机的输出轴长度调整,尽可能提高它的最大转角。 前轮前倾角应尽量为零,以减少过弯的阻力。

使用的简易直射式红外测速模块比较电压要根据不同的比赛环境进行调 试。另外由于小车在速度过快时容易侧滑出赛道,除了在控制上采取减速的策 略,试跑前用湿布擦干净车轮也是很有必要的。

以下是发现的一些问题及相应的改进策略:

(1)由于摄像头采集回的视频信号电压较低,通过比较器测得黑线的数值 为零,因此不便于使用浮动域值消除周围光线干扰,通过连续性算法判断轨迹 的实际位置。调整比较电压值可以抬高检测黑线的数值,以便于在算法中加入 浮动域值,这将在后续工作中进行尝试。

(2)自主设计的测速装置和黑白码盘精度有限,反馈的速度值波动较大, 不宜于参数的整定,以后可以试用旋转编码器进行速度的采集。在舵机的安装 上可试着抬高它的位置,以加长输出力臂,使转向更为灵活。

(3)虽然摄像头能提前判弯,但在过弧度很小的小 s 道时可以不必减速, 采用直冲的策略以节省时间,这也将在以后的工作中进行探索。



附录 A    参考书目

[1]  卲贝贝著 《单片机嵌入式应用的在线开发》 清华大学出版社 2005

[2] Steven F.Barrett,Daniel J.Pack 著  嵌入式系统 2005

[3]  于海生等著 《微型计算机控制技术》清华大学出版社 1999

[4]  张艳兵等著 《计算机控制技术》国防工业出版社 2006

[5] Motorola Inc. PWM_8B8C Block User Guide V01.16 www.motorola.com 14

MAR 2002

[6]  模型车电机特性和 33886 驱动电路 2005

[7] Freesclae HCS12 ECT PWM      www. Freesclae.com    2007

[8] Motorola Inc. MC9S12DT128 Device User Guide V02.09 www.motorola.com

15 October 2003

[9]黄永庆 《基于 CCD 摄像的视觉跟踪误差信号提取》广西大学梧州分校学报

20##

[10]李绍民 刘任平 《全自主足球机器人视觉系统的方案分析与比较》 微计算 机信息 2004

[11]齐国清 胡晓初 《线形 CCD 高速图像采集与处理系统》 大连海事大学学报

20##

[12] 清华 Freescale 单片机与 DSP 应用开发研究中心:第二届“飞思卡尔”杯 全国大学生智能车邀请赛比赛规则 2007

[13] 卓晴,黄开胜,邵贝贝等 《学做智能车》北京航天航空大学出版社 2007


附录 B     部分程序

#include <hidef.h>

#include <mc9s12dg128.h>

#include "printp.h"

#pragma LINK_INFO DERIVATIVE "mc9s12dg128b"

#define MAX 6000

#define STEP 5

#define HANG_DELAY 9

#define LINE_NUM 36

#define COLUMN_NUM 60

#define BLACK_LINEWIDTH 2

#define FAR_LINE_NUM 15

#define NEAR_LINE_NUM 30

#define STATUE_SCAN 0

#define STATUE_FARGAP -1

#define STATUE_NEARGAP 1

#define STATUE_SPEEDGAP 2

#define THRESHOLD_MAX_VARY 2

//#define SPEED_LINE_GAP 3

void ECT_Init(void);

void Clock_Init(void);

void IO_Init(void);

void Motor_Init(void);

void DirectionMotor_Init(void);

int  Get_speed();

void PWM_Speedctrl(int set_speed);

void speed_control();

void direction_control();

Byte get_point(uchar line,uchar column);


char get_gap(uchar line_num);

void turnangle_judgement();

void get_PathRange(); void get_threshold(); void set_paramters();

unsigned char state;

byte count,step;

int dindex;

byte flag,flag1;

byte i;

uchar test;

uint stright_speed = 0;

uint circle_rate = 0;

unsigned int old_TCNT = 0; unsigned int new_TCNT = 0; unsigned int pluse_count; uchar threshold=255;

uchar center_pos = 35;

char start,end;

char angle = 0;

char last_angle = 0;

uchar flag_allwhite = 0;

uchar start_flag;

char last_center[LINE_NUM];

char gap[LINE_NUM];

char last_gap[LINE_NUM];

char gap_far,gap_near;

char last_gapfar = 0;

char last_gapnear = 0;

char near_range,far_range;

char last_near_range,last_far_range;

uint s_speed_a = 145;

uint s_speed_b = 150;

uint s_speed_c = 155;

uint s_speed_d = 160;


uint circle_rate_a = 20;

uint circle_rate_b = 40;

uint circle_rate_c = 80; uint circle_rate_d = 100; Byte Data[MAX];

Byte line[COLUMN_NUM];

void Variable_Init(void)

{

int i;

for(i=0;i<LINE_NUM;i++)

{

last_center[i] = 35;

gap[i] = 0;

last_gap[i] = 0;

}

}

void ECT_Init(void)

{

TIOS = 0xff; TSCR2 = 0x07;

TSCR1 = 0x80;

TIOS_IOS1 = 0; TCTL4_EDG1A = 1; TCTL4_EDG1B = 0;

TIOS_IOS0 = 0; TCTL4_EDG0A = 1; TCTL4_EDG0B = 0;

TIE_C0I = 1;

}

void Clock_Init(void)

{

CLKSEL_PLLSEL = 0x0; REFDV = REFDV_VALUE; SYNR = SYNR_VALUE;

while(!CRGFLG_LOCK); CLKSEL_PLLSEL = 0x1;

CLKSEL_PLLSEL = 0x1;


}

void IO_Init(void)

{

DDRA = 0x00; DDRB = 0xff;

DDRT = 0x00;

DDRK_DDK3 = 1; ATD1DIEN=0xFF;

PORTB_BIT0 = PORTK_BIT0;

PORTB_BIT1 = PORTK_BIT2; PORTB_BIT2 = PORTK_BIT4; PORTB_BIT3 = PORTK_BIT5;

}

void Motor_Init(void)

{

DDRP_DDRP1=1; DDRP_DDRP3=1;

PTP_PTP1=1; PTP_PTP3=1; PWMPRCLK= 0x00;

PWMSCLA = 0x06; PWMCLK_PCLK1 = 1;

PWMDTY1 = 0; PWMPER1 = 255; PWMPOL_PPOL1 = 1;

PWMCAE_CAE1 = 0; PWME_PWME1 = 1; PWME_PWME3 = 0;

}

void DirectionMotor_Init(void)

{

DDRP_DDRP5 = 1; PTP_PTP5 = 1;

PWMPRCLK = 0x00;

PWMSCLA = 0x03; PWMCTL_CON45 = 1;

PWMCLK_PCLK5 = 1;

PWMPOL_PPOL5 = 1;


PWMCAE_CAE5 = 0;

PWME_PWME5 = 1;

}

int Get_speed()

{

static int speed;

speed = (7812/pluse_count)*17;

return speed;

}

void PWM_Speedctrl(int set_speed)

{

static int e[2]={0,0};

static int pwm_speed;

static int old_pwm_speed; static byte pwm_ctrl; static int catch_speed;

static int pi=0; static int ch=1; static int Kp = 5;

static int Ti = 10;

static int Td = 2;

catch_speed = Get_speed();

old_pwm_speed=pwm_speed;

e[0]=e[1];

e[1]=set_speed-catch_speed;

if(catch_speed<(set_speed*3/4)||catch_speed>((set_speed)*5/4))     {

ch=1;

pwm_speed=(Kp*e[1]+Td*(e[1]-e[0]))/2;


else


}

{

if(ch==1)

{


pi=0;

pi=pi+e[1];

pwm_speed=Kp*e[1]/4+(pi/Ti)+Td*(e[1]-e[0])/2;


ch=0;

}

else

{

pi=pi+e[1];

pwm_speed=Kp*e[1]/4+(pi/Ti)+Td*(e[1]-e[0])/2;

ch=0;

}

}

if(pwm_speed<0)

pwm_ctrl = 0;

else if(pwm_speed>220)

pwm_ctrl = 220;

else

pwm_ctrl=pwm_speed; PWMDTY1=255-pwm_ctrl;

}

void speed_control()

{

gap_speedline1,gap_speedline2,gap_speedline3;

gap_speedcontrol= (get_gap(SPEED_LINE_NUM,STATUE_SPEEDGAP)

+get_gap(SPEED_LINE_NUM-1,STATUE_SPEEDGAP)

+get_gap(SPEED_LINE_NUM+1,STATUE_SPEEDGAP))/3;

gap_speedfar = (get_gap(FAR_LINE_NUM,STATUE_FARGAP)

+get_gap(FAR_LINE_NUM-1,STATUE_FARGAP)

+get_gap(FAR_LINE_NUM+1,STATUE_FARGAP))/3;

gap_speednear = (get_gap(NEAR_LINE_NUM,STATUE_NEARGAP)

+get_gap(NEAR_LINE_NUM-1,STATUE_NEARGAP)

+get_gap(NEAR_LINE_NUM+1,STATUE_NEARGAP))/3;

gap_speedline1 = get_gap(SPEED_LINE_NUM1,STATUE_SPEEDGAP); gap_speedline2 = get_gap(SPEED_LINE_NUM2,STATUE_SPEEDGAP); gap_speedline3 = get_gap(SPEED_LINE_NUM3,STATUE_SPEEDGAP); wish_gap=(SPEED_LINE_NUM2-SPEED_LINE_NUM1)*(gap_speedline2-gap_speed


line3)/(SPEED_LINE_NUM3-SPEED_LINE_NUM2)+gap_speedline2;

if((gap_speedline1-wish_gap>SPEED_LINE_GAP)||(gap_speedline1-wish_ga p<-SPEED_LINE_GAP))

{

if(gap_speedline2 == 127) PWM_Speedctrl(0);


else


else

}


PWM_Speedctrl(circle_speed);


int speed;

if(angle>4)


PWM_Speedctrl(stright_speed);


speed = stright_speed-(circle_rate*angle)/100;

else if(angle<-4)

speed = stright_speed-(circle_rate*(-angle))/100;


else


speed = stright_speed; PWM_Speedctrl(speed);


}

void set_paramters()

{

DDRK_DDK0 = 0; DDRK_DDK2 = 0;

DDRK_DDK4 = 0;

DDRK_DDK5 = 0;

if(PORTK_BIT0==0 && PORTK_BIT2==0)

stright_speed = s_speed_a;

else if(PORTK_BIT0==0 && PORTK_BIT2==1)

stright_speed = s_speed_b;

else if(PORTK_BIT0==1 && PORTK_BIT2==0)

stright_speed = s_speed_c;

else if(PORTK_BIT0==1 && PORTK_BIT2==1)

stright_speed = s_speed_d;

if(PORTK_BIT4==0 && PORTK_BIT5==0)


circle_rate = circle_rate_a;

else if(PORTK_BIT4==0 && PORTK_BIT5==1)

circle_rate = circle_rate_b;

else if(PORTK_BIT4==1 && PORTK_BIT5==0)

circle_rate = circle_rate_c;

else if(PORTK_BIT4==1 && PORTK_BIT5==1)

circle_rate = circle_rate_d;

}

void direction_control()

{

int direction_pwm;

char gap_near;

turnangle_judgement();

direction_pwm = turn_angle(angle); PWMDTY45 = direction_pwm;

}

void turnangle_judgement()

{

get_PathRange();

gap_far = (get_gap(FAR_LINE_NUM,STATUE_FARGAP)

+get_gap(FAR_LINE_NUM-1,STATUE_FARGAP)

+get_gap(FAR_LINE_NUM+1,STATUE_FARGAP))/3;

gap_near = (get_gap(NEAR_LINE_NUM,STATUE_NEARGAP)

+get_gap(NEAR_LINE_NUM-1,STATUE_NEARGAP)

+get_gap(NEAR_LINE_NUM+1,STATUE_NEARGAP))/3;

if(FAR_LINE_NUM < far_range)

gap_far = 127;


else


gap_far=(gap[FAR_LINE_NUM]+gap[FAR_LINE_NUM+1]+gap[FAR_LINE_N UM+2]+gap[FAR_LINE_NUM+3])>>2;


if(NEAR_LINE_NUM > near_range)

gap_near = 127;

else

gap_near=(gap[NEAR_LINE_NUM]+gap[NEAR_LINE_NUM-1]+gap[NEAR_LI NE_NUM-2]+gap[NEAR_LINE_NUM-3])>>2;

if(gap_far != 127  && gap_near != 127)

{


angle=(gap_far-gap_near)*6*4/(3*5)+gap_near*5*3/(3*5);

last_gapfar = gap_far;

last_gapnear = gap_near;

}

else if(gap_far == 127 && gap_near != 127)

{

if(last_gapfar > 5)

gap_far = 35;

else  if(last_gapfar < -5)

gap_far = -35;


else


gap_far = 0;


angle=(gap_far-gap_near)*7*4/(3*5)+gap_near*5*4/(3*5);

last_gapnear = gap_near;

}

else if(gap_far != 127 && gap_near == 127)

{

if(last_gapnear>5)

gap_near = 35;

else if(last_gapnear<-5)

gap_near = -35;

else

gap_near = 0;

angle=(gap_far-gap_near)*4*4/(3*5)+gap_far*3*4/(3*5);

last_gapfar = gap_far;

}

else if(gap_far == 127 && gap_near == 127)

{

if(last_gapfar > 5)

gap_far = 35;

else  if(last_gapfar < -5)

gap_far = -35;

else

gap_far = 0;

if(last_gapnear>5)

gap_near = 35;

else if(last_gapnear<-5)

gap_near = -35;


else

gap_near = 0;

angle=(gap_far-gap_near)*3*4/(2*5)+(gap_near)*3*4/(2*5);

}

if((angle-last_angle>=70)||(last_angle-angle>=70))

angle = last_angle;


else


last_angle = angle;


if(angle>40)

angle = 40;

else if(angle<-40)

angle = -40;

}

Byte get_point(uchar line,uchar column)

{

return Data[line*(COLUMN_NUM+1)+column];

}

void get_PathRange()

{

uchar i;

uchar range_width=0; range_width = 0; near_range = 0;

far_range = 60;

for(i=NEAR_LINE_NUM;i>=FAR_LINE_NUM;i--)

gap[i] = get_gap(i);

for(i=NEAR_LINE_NUM;i>=FAR_LINE_NUM;i--)

{

if((gap[i]!=127) && (gap[i-1]!=127))

{

near_range = i;

while((gap[i]!=127) && (i>=FAR_LINE_NUM))

{

i--;


range_width++;

}

if(range_width>=2)

{

far_range = i+1;

break;

}

}

}

last_near_range = near_range;

last_far_range = far_range;

}

char get_gap(uchar line_num)

{

char i;

char lstart,lend,rstart,rend;

char leftline_width = 0;

char rightline_width = 0;

char gap = 0;

char new_threshold;

for(i=0;i<COLUMN_NUM;i++)

{

line[i] = get_point(l,i);

if(get_point(line_num,i)<=THRESHOLD)

{

start = i;

while(get_point(line_num,i)<=THRESHOLD&&i<70)

i++;

end = i-1;

break;

}

}

for(i=last_center[line_num];i<center_pos*2;i++)

{

if(get_point(line_num,i)<=threshold)

{

rstart = i;


while(get_point(line_num,i)<=threshold&&

i<center_pos*2)

{

i++;

rightline_width++;

}

rend = i;

break;

}

}

if(get_point(line_num,center_pos-1)<=threshold&&

get_point(line_num,center_pos)<=threshold)

{

start = lstart;

end = rend;

flag_allwhite = 0;

}

else if(leftline_width>=BLACK_LINEWIDTH)

{

start = lstart;

end = lend;

flag_allwhite = 0;

}

else if(rightline_width>=BLACK_LINEWIDTH)

{

start = rstart; end = rend; flag_allwhite = 0;

}

else

{

gap = 127;

flag_allwhite = 1;

}

if(flag_allwhite == 0)

{

gap = ((start+end)/2)-center_pos;


if((last_gap[line_num]-gap>=20)||(last_gap[line_num]-gap<=-

20))

{

gap = last_gap[line_num];

return gap;

}

last_gap[line_num] = gap;

last_center[line_num] = (start+end)/2;

new_threshold=get_point(line_num,last_center[line_num]

);

if(((new_threshold-threshold)<=THRESHOLD_MAX_VARY)

||((threshold-new_threshold)<=THRESHOLD_MAX_VARY))

threshold = new_threshold;

}

return gap;

}

void get_threshold()

{

uchar i;

uchar temp;

for(i=10;i<50;i++)

{

temp = get_point(i,center_pos);

if(temp<threshold)

threshold = temp;

}

}

void get_centerpos()

{

uchar i;

uchar s,e;

uchar temp = 0;

for(i=10;i<50;i++)

{

if(get_point(40,i)<=threshold)

{

s = i;


while(get_point(40,i)<=threshold && i<50)

{

i++;

temp++;

}

e = i;

}

if(temp>=BLACK_LINEWIDTH)

{

center_pos = (s+e)/2;

break;

}

}

}

int turn_angle(char ang)

{

return 6000+ang*32;

}

void main(void)

{

Byte sPTT;

int index;

uchar statue_getthreshold = 1;

uart_init(); Variable_Init();

IO_Init();

Clock_Init(); ECT_Init();

Motor_Init();

DirectionMotor_Init(); set_paramters(); EnableInterrupts;

sPTT=0; count = 0; index=dindex=0; flag = 0;

state = 0;


for(;;)

{

switch(state) {

case 0:

state = 1;

break;

case 1:

if(PTT_PTT2 == 0) {

while(PTT_PTT2==0);

dindex = 0; count = 0; step = 0;

PORTK_BIT3 = 0;

state = 2; TIE_C1I = 1;

}

break;

case 2:

if(flag == 1)

{

state = 3;

flag = 0;

}

break;

case 3:

PORTK_BIT3 = 1;

if(statue_getthreshold == 1)

{

get_threshold();

get_centerpos();

statue_getthreshold = 0;

}

direction_control(); speed_control(); state = 0;

break;

}

}


}

#pragma CODE_SEG NON_BANKED

#pragma TRAP_PROC

void PT1CaptureEdge(void)

{

DisableInterrupts; TFLG1_C1F = 0x1;

step++;

if(step>=STEP)

{

for(i=0;i<HANG_DELAY;i++)

{

}

count++;

step = 0;

if(count>2)

{

for(i=0;i<COLUMN_NUM;i++) Data[dindex++]=PORTAD1; Data[dindex++]=0xAA;

}

}

if(count>=LINE_NUM )

{

flag = 1; TIE_C1I = 0;

}

EnableInterrupts;

}

#pragma CODE_SEG DEFAULT

#pragma CODE_SEG NON_BANKED

#pragma TRAP_PROC

void PT0CapturePluseWidth(void)

{

DisableInterrupts; TFLG1_C4F = 0x1;

old_TCNT = new_TCNT;

new_TCNT = TCNT;


if(new_TCNT >= old_TCNT)

pluse_count =  new_TCNT-old_TCNT;

else

pluse_count = (65535-old_TCNT)+new_TCNT; EnableInterrupts;

}

#pragma CODE_SEG DEFAULT

#pragma CODE_SEG NON_BANKED

#pragma TRAP_PROC

相关推荐