小车循迹原理Word下载.docx
《小车循迹原理Word下载.docx》由会员分享,可在线阅读,更多相关《小车循迹原理Word下载.docx(21页珍藏版)》请在冰豆网上搜索。
![小车循迹原理Word下载.docx](https://file1.bdocx.com/fileroot1/2023-1/25/5e4aa9fb-80c6-4a04-8577-3ebffbde6693/5e4aa9fb-80c6-4a04-8577-3ebffbde66931.gif)
图中循迹传感器共安装4个,全部在一条直线上。
其中InfraredMR与InfraredML为第一级方向控制传感器,InfraredSR与InfraredSL为第二级方向控制传感器。
小车行走时,始终保持黑线(如图2中所示的行走轨迹黑线)在InfraredMR和InfraredML这两个第一级传感器之间,当小车偏离黑线时,第一级探测器一旦探测到有黑线,单片机就会按照预先编定的程序发送指令给小车的控制系统,控制系统再对小车路径予以纠正。
若小车回到了轨道上,即4个探测器都只检测到白纸,则小车会继续行走;
若小车由于惯性过大依旧偏离轨道,越出了第一级两个探测器的探测范围,这时第二级动作,再次对小车的运动进行纠正,使之回到正确轨道上去。
可以看出,第二级方向探测器实际是第一级的后备保护,从而提高了小车循迹的可靠性。
4.软件控制
其程序控制框图如图3。
小车进入循迹模式后,即开始不停地扫描与探测器连接的单片机I/O口,一旦检测到某个I/O口有信号,即进入判断处理程序(switch),先确定4个探测器中的哪一个探测到了黑线,如果InfraredML(左面第一级传感器)或者InfraredSL(左面第二级传感器)探测到黑线,即小车左半部分压到黑线,车身向右偏出,此时应使小车向左转;
如果是InfraredMR(右面第一级传感器)或InfraredSR(右面第二级传感器)探测到了黑线,即车身右半部压住黑线,小车向左偏出了轨迹,则应使小车向右转。
在经过了方向调整后,小车再继续向前行走,并继续探测黑线重复上述动作。
由于第二级方向控制为第一级的后备,则两个等级间的转向力度必须相互配合。
第二级通常是在超出第一级的控制范围的情况下发生作用,它也是最后一层保护,所以它必须要保证小车回到正确轨迹上来,则通常使第二级转向力度大于第一级,即level2>
level1(level1、level2为小车转向力度,其大小通过改变单片机输出的占空比的大小来改变),具体数值在实地实验中得到。
专家点评:
根据本文所讲述的方法,我们可以较容易地做出按照一定轨迹行走的智能电动小车。
但是按照该方法行走的小车如果是走直线,有可能会是蛇形前进。
为了使小车能够按轨迹行走的更流畅,可以在软件编程时运用一些简单的算法。
例如,在对小车进行纠偏时,适当提前停止纠偏,而不要等到小车完全不偏时再停止,以防止小车的过冲。
电源电路:
由于本系统需要电池供电,我们考虑了如下几种方案为系统供电。
方案1:
采用10节1.5V干电池供电,电压达到15V,经7812稳压后给支流电机供电,然后将12V电压再次降压、稳压后给单片机系统和其他芯片供电。
但干电池电量有限,使用大量的干电池给系统调试带来很大的不便,因此,我们放弃了这种方案。
方案2:
采用3节4.2V可充电式锂电池串联共12.6V给直流电机供电,经过7812的电压变换后给支流电机供电,然后将12V电压再次降压、稳压后给单片机系统和其他芯片供电。
锂电池的电量比较足,并且可以充电,重复利用,因此,这种方案比较可行。
但锂电池的价格过于昂贵,使用锂电池会大大超出我们的预算,因此,我们放弃了这种方案。
方案3:
采用12V蓄电池为直流电机供电,将12V电压降压、稳压后给单片机系统和其他芯片供电。
蓄电池具有较强的电流驱动能力以及稳定的电压输出性能。
虽然蓄电池的体积过于庞大,在小型电动车上使用极为不方便,但由于我们的车体设计时留出了足够的空间,并且蓄电池的价格比较低。
因此我们选择了此方案。
综上考虑,我们选择了方案3。
这个黑呼呼的东西,让我们可爱的小车变得很难看。
稳压模块:
采用两片7812将电压稳压至12V后给直流电机供电,然后采用一片7809将电压稳定至9V,最后经7805将电压稳至5V,给单片机系统和其他芯片供电,但7809和7805压降过大,使7809和7805消耗的功率过大,导致7809和7805发热量过大,因此,我们放弃了这种方案。
采用两片7812将电压稳压至12V后给直流电机供电,然后采用2576将电压稳至5V。
2576的输出电流最大可至3A,完全满足系统要求。
综上考虑,我们选择了方案2。
稳压模块如下图:
(左图:
稳压模块)
循迹传感器模块
用光敏电阻组成光敏探测器。
光敏电阻的阻值可以跟随周围环境光线的变化而变化。
当光线照射到白线上面时,光线发射强烈,光线照射到黑线上面时,光线发射较弱。
因此光敏电阻在白线和黑线上方时,阻值会发生明显的变化。
将阻值的变化值经过比较器就可以输出高低电平。
但是这种方案受光照影响很大,不能够稳定的工作。
因此我们考虑其他更加稳定的方案。
用红外发射管和接收管自己制作光电对管寻迹传感器。
红外发射管发出红外线,当发出的红外线照射到白色的平面后反射,若红外接收管能接收到反射回的光线则检测出白线继而输出低电平,若接收不到发射管发出的光线则检测出黑线继而输出高电平。
这样自己制作组装的寻迹传感器基本能够满足要求,但是工作不够稳定,且容易受外界光线的影响,因此我们放弃了这个方案。
用RPR220型光电对管。
RPR220是一种一体化反射型光电探测器,其发射器是一个砷化镓红外发光二极管,而接收器是一个高灵敏度,硅平面光电三极管。
RPR220采用DIP4封装,其具有如下特点:
∙塑料透镜可以提高灵敏度。
∙内置可见光过滤器能减小离散光的影响。
∙体积小,结构紧凑。
∙当发光二极管发出的光反射回来时,三极管导通输出低电平。
此光电对管调理电路简单,工作性能稳定。
此我们选择了方案3。
安装后效果如下图:
下图是电压比较器:
电设小车循迹模块
2007-10-1414:
06
//包含所需头文件
#include<
ioM16v.h>
macros.h>
#include"
time1_init.h"
motor.h"
#defineahead1
#definebackwards0
#definecompare(x,y)(x<
y?
1:
0)
#definemid0X17
/*****************************初始化函数********************************/
//端口初始化
voidport_init(void)
{
PORTA=0x00;
DDRA
=0x00;
PORTB=0x00;
DDRB
=0x08;
PORTC=0x00;
DDRC
PORTD=0x00;
DDRD
}
voidtimer0_init(void)
TCCR0
//停止定时器
TCNT0
//初始值
OCR0
=0x17;
//匹配值
TIMSK|=0x00;
//中断允许
=0x7D;
//启动定时器
voidadc_init(void)
//adc转换初始化
ADCSRA=0x00;
//禁止AD转换
ADCSRA|=BIT(ADIF);
ADMUX=0X46;
SFIOR|=0x00;
ACSR=0x80;
//禁止模拟比较器
ADCSRA=0xE7;
voidinit_devices(void)
CLI();
//禁止所有中断
MCUCR
MCUCSR=0x80;
//禁止JTAG
GICR
port_init();
timer0_init();
timer1_init();
adc_init();
SEI();
//开全局中断
/**********************************************************************/
/*****选择前端传感器用ucharstart_head_sensor(void)*****************************
选择后端传感器用ucharstart_back_sensor(void)
/*****使用角度传感器用uintcord_sensor(void)********************************************/
uintsensor_head[3],sensor_back[3],cord;
//存储6个传感器AD转换的值
ucharoffset;
//黑线偏移小车中心轴的距离
uintsensor_compare_head[3]={300,300,300},sensor_compare_back[3]={300,300,300};
//判断黑线是否位于传感器下的阈值
ucharstart_head_sensor(void)
uchari,j=0,sum=0;
ADMUX=0X40;
ADCSRA=0xC7;
while(ADCSRA&
BIT(ADSC));
for(i=0;
i<
3;
i++)
ADMUX=0X40+i;
//启用前端传感器0,1,2通道
ADCSRA=0xC7;
while(ADCSRA&
sensor_head[i]=ADC;
}
for(i=3;
i;
i--)
if(compare(sensor_head[i-1],sensor_compare_head[i-1]))
{
sum+=i-1;
j++;
}
if(j)
offset=sum*2/j;
ADCSRA=0xE7;
returnoffset;
ucharstart_back_sensor(void)
ADMUX=0X43;
ADMUX=0X43+i;
sensor_back[i]=ADC;
for(i=3;
if(compare(sensor_back[i-1],sensor_compare_back[i-1]))
if(j)offset=sum*2/j;
ADCSRA=0XE7;
//角度传感器滤波函数
uint
cord_sensor(void)
uchari;
uintmax=0,min=1023,sum=0;
5;
ADCSRA|=BIT(ADIF);
while(!
(ADCSRA&
BIT(ADIF)));
cord=ADC;
sum+=cord;
max=(max>
cord)?
max:
cord;
min=(min<
min:
return(sum-max-min)/3;
voiddirec_ctrl(ucharx,uchary)
if(y)
if(x==0)OCR0=mid+3;
if(x==4)OCR0=mid-3;
if(x==2)OCR0=mid;
elseOCR0=mid+x-2;
voidmenmber_path(void)
ucharj;
uinti;
uintmax_head[3]={0,0,0},min_head[3]={1023,1023,1023},max_back[3]={0,0,0},min_back[3]={1023,1023,1023};
for(i=4000;
start_head_sensor();
for(j=0;
j<
j++)
max_head[j]=(max_head[j]>
sensor_head[j])?
max_head[j]:
sensor_head[j];
min_head[j]=(min_head[j]<
min_head[j]:
}
start_back_sensor();
max_back[j]=(max_back[j]>
sensor_back[j])?
max_back[j]:
sensor_back[j];
min_back[j]=(min_back[j]<
min_back[j]:
}
for(j=0;
sensor_compare_head[j]=(max_head[j]+min_head[j])/2;
sensor_compare_back[j]=(max_back[j]+min_back[j])/2;
/***********************前端同时检测到黑线判断函数****************************************/
ucharhead_sensor_all(void)
if(compare(sensor_head[0],sensor_compare_head[0])
&
&
compare(sensor_head[1],sensor_compare_head[1])&
compare(sensor_head[2],sensor_compare_head[2]))
return1;
else
return0;
ucharback_sensor_all(void)
if(compare(sensor_back[0],sensor_compare_back[0]-30)
compare(sensor_back[1],sensor_compare_back[1]-30)&
compare(sensor_back[2],sensor_compare_back[2]-30))
/**********************前端循迹函数**************************************************/
voidsearch_path_ahead(ucharspeed)
motor_autorun(ahead,speed);
while
(1)
{
if(head_sensor_all())
motor_stop();
return;
{
direc_ctrl(offset,1);
/**********************后端循迹函数*******************************************/
voidsearch_path_backward(ucharspeed)
motor_autorun(0,speed);
if(back_sensor_all())
else
direc_ctrl(offset,0);
#include<
reg51.h>
#defineTH0_TL0(65536-1000)//设定中断的间隔时长
unsignedcharcount0=0;
unsignedcharcount1=0;
bitFlag=1;
//电机正反转标志位,1正转,0反转
sbitKey_add=P1^4;
//电机减速
sbitKey_dec=P1^5;
//电机加速
sbitKey_turn=P1^6;
//电机换向
sbitPWM1=P3^6;
//PWM通道1
sbitPWM2=P3^7;
//PWM通道2
unsignedcharTime_delay;
//函数声明
voidDelay(unsignedcharx);
voidMotor_speed_high(void);
voidMotor_speed_low(void);
voidMotor_turn(void);
voidTimer0_init(void);
/******************************************************************************/
voidDelay(unsignedcharx)//延时处理
Time_delay=x;
while(Time_delay!
=0);
voidTimer0_int(void)interrupt1using1//定时0中断处理
TR0=0;
TL0+=(TH0_TL0+9)%256;
TH0+=(TH0_TL0+9)/256+(char)CY;
TR0=1;
if(Time_delay!
=0)//延时函数用
Time_delay--;
if(Flag==1)//电机正转
PWM1=0;
if(++count1<
count0)
PWM2=1;
PWM2=0;
if(count1>
=100)
count1=0;
else//电机反转
PWM1=1;
}//反转
voidMotor_speed_high(void)//按键处理加pwm占空比,电机加速
if(Key_add==0)
Delay(10);
count0