整体框架如右图;
【初始化算法】
v1.锁相环的设置
#define BUS_CLOCK //总线频率
//初始化锁相环(16M模板)
void pll_init()
{
CLKSEL&=0X7F;//关闭锁相环
PLLCTL&=0X8F;//控制寄存器,关闭锁相环电路
CRGINT&=0XDF;//清除一些标志位
//锁相环选择
#if(BUS_CLOCK==40000000)
SYNR=0X44;
#elif(BUS_CLOCK==32000000)
SYNR=0X43;
#elif(BUS_CLOCK==24000000)
SYNR=0X42;
#endif
REFDV=0X81;
PLLCTL=PLLCTL|0X70;//开启锁相环电路
asmNOP;
while(!(CRGFLG&0X08));
CLKSEL|=0X80;//开启锁相环
}
v2.脉冲宽度调制(PWM)初始化
1) 通道选择PWMEx//使能PWMCTL_CON//是否级联
2) 时钟设置PWMCLK//时钟选择PWMPRCLK//预分频PWMSCLA/B//比例因子
3) 系统设置PWMPOL_POLx//极性寄存器PWMCAEx//中心对齐设置
4) Pwm配置PWMPER//周期PWMDTY//占空比
v3.定时中断及输入捕捉通道的初始化
设定预分频系数;定时器溢出中断使能;定时器使能。
v4.A/D转换模块初始化
将模拟的视频电压信号转换成对应的数值,以便于后面的黑线提取算法实现。
v5.外部中端的初始化
用于捕捉视频信号的行同步信号,产生外部中断以进行图像采集。
【图像采集算法】
v考虑到实际赛道只是在白色KT板上布置黑色引导线,路径识别只需大致提取出黑色引导线即可,不必每行采集。因此,我们可以采用隔行采集思想来压缩图像的数据。
【黑线提取算法】
v1.二值化算法:设置一个阈值value将数据预期比较,大于它就是1小于它就是0。记下第一次和最后一次出现像素值小于阈值时的像素点的列号,算出两者的平均值,以此作为该行上目标引导线的位置。
v2.直接边缘检测算法:首先找到从白色像素到黑色像素的下降沿和从黑色像素到白色像素的上升沿(也用阈值比较寻找),然后计算上升沿和下降沿的位置差,如果大于一定的标准值,即认为找到了黑线,并可求平均值算出黑线的中心点。
v3.跟踪边缘检测算法:利用跑道黑色目标线是连续的线。若已寻找到某行的左边缘,则下一次就在上一个左边缘附近进行搜寻。这种方法的特点是始终跟踪每行左边缘的附近,去寻找下一列的左边缘,所以称为“跟踪”边缘检测算法
【图像滤波算法】
v在调试过程中会出现两段黑线情况,这种图像信息比较复杂,这时可能存在三种路况:
§(1)赛道比较密集时,检测到多条赛道;
§(2)大“S”弯道;
§(3)“十”字交叉道。
v另外,由于智能车上安装的摄像头相对于赛道存在一定的倾斜角度,因此会造成采集到的赛道图像具有一定的梯形失真,即图像中的赛道远端窄、近端宽,因而也会对路径的正确识别产生影响。对于这种失真,可以通过对每行提取的赛道位置添加一个线性修正值来消除,一般通过实验的方法确定线性补偿的系数。
v偏差大的数据要去掉。
【控制策略及控制算法】
v1.赛道参数的计算
偏差计算偏差量linepos[j]数组存放Offset
最远行黑线位置linepos[topline]
黑线平均位置averlinepos
全白行行数whiteline_sum
曲率
v2.转向控制
(1)分段比例控制
(2)前馈补偿控制
v3.速度控制
(1)模糊控制设定速度
(2)PID控制调整速度
【摄像头简单程序】
//信号线A0
//行同步接PT2
//场同步接PT1
#define lie_end260 /////列结尾
#define hang_end100 //////行结尾
#define lie32//51 //////列
#define delay(num) /////延时函数
{
unsigned int i,j;
for(i=0;i<num;i++)
for(j=0;j<48;j++);
}
unsigned char c_lie=0,g_lie=0;/////你要采集的行列数组计数
unsigned int lie_count=0,hang_count=0;///摄像头行列计数
unsigned char shuju[lie][hang_end];/////存放数据的数组
unsigned int get_n[]={ 16,29,41,52,62,71,79,86,92,98,/////////////////存放要采集的行数
103,108,112,116,120,124,128,132,135,138,
141,144,147,150,153,156,159,162,165,168,
170,172,174,176,178,180,182,184,186,188,
190,192,194,196,198,200,202,204,206,208,
210,211,212,242,243,245,246,247,248,249,250};
#define uchar unsigned char
#define uint unsigned int;
void chaopin(void); ///锁相程序
void TIM_init(void);/////定时器程序(行场中断)
void shijian(void);
void atd_init(void);
void pwm_init(void);
#pragma CODE_SEG NON_BANKED
voidinterrupt 10 IC2ISR(void) { //行中断
TFLG1_C2F=1;
if(lie_count==get_n[c_lie]) {//定距采集图像的判断条件
delay(1); //黑线中心矫正,确保不采集到消隐信号
for(hang_count=0;hang_count<=hang_end;hang_count++){//读取一行的数据
shuju[c_lie][hang_count]=PORTA_PA0;//采集数据的接口
}
c_lie++; //二维数组行自加
}
lie_count++; //摄像头行自加
}
void interrupt 9 IC1ISR(void){ //场中断,各数据清零
TFLG1_C1F=1;
hang_count=0;
lie_count=0;
c_lie=0;
}
#pragma CODE_SEG DEFAULT
///////////输入捕捉初始化///////////////////////
void TIM_init(void)
{
PACTL=0X50;
PACNT=0X0000;
TIOS=0x00;//定时器通道0,1为输入捕捉
TSCR1=0x80;//定时器使能
TCTL4=0x18;//通道1捕捉下降沿通道2捕捉上升沿
TIE=0x06;//通道1,2中断使能
TFLG1=0xFF;//清中断标志位
}
void shijian(void) {
PITCFLMT_PITE=0;
PITCE_PCE0=1;
PITLD0=9999;//1毫秒
PITMTLD0=5;
PITMUX=0X00;
PITINTE_PINTE0=1;
PITCFLMT_PITE=1;
}
void chaopin(void)
{
CLKSEL=0X00;
PLLCTL_PLLON=1;
SYNR =0xc0 | 0x07;
REFDV=0xc0 | 0x01;
POSTDIV=0x00;
_asm(nop);
_asm(nop);
_asm(nop);
_asm(nop);
while(!(CRGFLG_LOCK==1));
CLKSEL_PLLSEL =1;
}