智能车课程设计.docx
《智能车课程设计.docx》由会员分享,可在线阅读,更多相关《智能车课程设计.docx(14页珍藏版)》请在冰豆网上搜索。
智能车课程设计
二○一四~二○一五学年第一学期
信息科学与工程学院
技术报告书
课程名称:
智能汽车设计与实践
班级:
自动化1204班
学号:
20129157043
姓名:
田野
指导教师:
章政
二○一四年十二月
对红外寻迹型智能汽车
1、制作技术的整体方案
智能汽车竞赛是在规定的模型汽车平台上,使用STC12微控制器作为核心控制模块,通过增加红外传感器、电机驱动电路以及编写相应软件,制作一个能够自主识别道路的模型汽车,按照规定路线行进,以完成时间最短者为优胜。
制作智能汽车所涉及的专业知识包括控制、模式识别、传感技术、汽车电子、电气、计算机、机械等多个学科。
所有电路进行模块化分为:
电源接口模块,传感器模块,测速模块,电机驱动模块,数据传输与上位机模块等。
然后通过接口连接在一起,实现工作稳定的智能车硬件电路。
通过使用传感器,编码电机,无线模块,稳压管等作为重要的任务器件。
实现了赛道识别,速度测控,赛车数据传输,电源稳压,速度控制等功能。
相关知识:
1.单片机是一种集成电路芯片,是采用超大规模集成电路技术把具有数据处理能力的中央处理器CPU、随机存储器RAM、只读存储器ROM、多种I/O口和中断系统、定时器/计数器等功能(可能还包括显示驱动电路、脉宽调制电路、模拟多路转换器、A/D转换器等电路)集成到一块硅片上构成的一个小而完善的微型计算机系统,
2.舵机内部结构
–舵盘、齿轮组、位置反馈电位计、直流电机、控制电路板,等。
•工作原理
–脉宽信号给定参考位置,舵机内部电路通过反馈控制调节舵盘角位。
–舵盘角位由PWM控制信号的脉宽决定。
•三线连接方式
–红线:
电源线+6V–蓝线:
地线
–黑线:
PWM控制信号
3.红外传感器
光电传感器一般有两个部分组成:
发射管和接收管。
发射管发射光线,光线经过赛道的反射,由接收管接受,用过不同的光强接收管的状态不同,实施赛道信息的采集,应为白色和黑色对于光线反射的系数不同,放射会傀儡的光线的强度不一样,被不同的接收单元接收后表现出不同的反应状态(电阻的变化,电流电压的变化等)
2、设计思路
1.硬件设计部分
A.单片机及其接口
B.传感器
C.红外管比较器
D.L298电机驱动
E.电源开关
F.单片机、红外管、舵机模块供电
2.软件设计部分
//晶振12MHz1T模式总线频率12MHz,一个指令1/12us
#include"STC12C5A60S2.H"//STC12C5A60S2的头文件
#defineucharunsignedchar//宏定义
#defineuintunsignedint
#defineT0_HIGH0xff//T0计时器寄存器初值
#defineT0_LOW0x7d//溢出计数120个,120*(1/12)定时周期10us
//为了保证主程序正常运行,定时器计数最好不要小于80
#defineMOTOR_MAX_PWM_COUNT100//PWM计数器最大值10us*100=1ms,1000Hz
#defineSERVO_MAX_PWM_COUNT2000//10us*2000=20ms,50HZ//舵机控制高电平0.5~2.5ms对应PWM的50~250
//舵机控制频率在50~100Hz之间,这里选50Hz
#defineMOTOR_MAX_PWM100//电机PWM最大最小值
#defineMOTOR_MIN_PWM50//
#defineSERVO_LEFT_MAX_PWM90//min90//舵机左打最大角度时的PWM
#defineSERVO_RIGHT_MAX_PWM150//max150//这个值需要自己根据舵机实际角
度调试
#defineSERVO_MID_PWM120//舵机中心值
//注意,舵机打角过大会打在底盘上,请立即断电,以免
损害舵机
#defineERROR_HISTORY_NUM3
//#defineTHRESHOLD170//区分红外管状态的阀值,红外管的AD值小于这个值时
为白,大于为黑
//具体情况需要根据电路确定
//阀值大小可用万用表测出红外管电压的最大和最小值后
确定
//阀值`相当于比较电压
sbitLEFT_MOTOR_PWM_PORT=P3^7;//电机PWM控制端口
sbitRIGHT_MOTOR_PWM_PORT=P3^6;
sbitSERVO_PWM_PORT=P3^5;//舵机PWM控制端
//--------------------------
bitcontrol_period_finished=0;//控制周期结束标志位,控制周期选择20ms
//也可自己确定控制周期,但是要保证主程序在控制周
期内可以运行完
charmotor_PWM_counter=0;//生成电机PWM的计数器
charleft_motor_PWM=0;//左右电机的PWM占空比//由于数值在128以内,所以定义为char
charright_motor_PWM=0;
intservo_PWM_counter=0;//生成舵机PWM的计数器
intservo_PWM=0;//舵机PWM//超过char型变量的范围
inttemp=0;
interror=0;//本次偏差
interror_array[3];
interror_history[ERROR_HISTORY_NUM-1]={0};
intservo_P=50;
intservo_I=10;
intservo_D=40;
intPID_out=0;//PID输出
intP2H=0;
intlasterror=0;//历史偏差
intpreverror=0;
charspeed_expect=70;//给定速度
charspeed_counter=0;
//-----------------------------------------------------------------------
voidsys_init(void)//系统初始化
{
//------IO口设置------------
P0M1=0x00;//推挽输出
P0M0=0x00;
P0=0xff;
P1M1=0x00;//准双向口
P1M0=0x00;
P1=0xff;//初始化为高电平
P2M1=0x00;//指示灯,设置为输出
P2M0=0x00;
P2=0xff;
P3M1=0x04;//模拟PWM,设置为输出
P3M0=0xfb;
P3=0x00;
LEFT_MOTOR_PWM_PORT=0;//PWM口设为低电平,电机不转
RIGHT_MOTOR_PWM_PORT=0;
left_motor_PWM=0;//占空比设置为0
right_motor_PWM=0;
servo_PWM=SERVO_MID_PWM;//舵机打角到中心
//------定时器设置------------
AUXR=AUXR|0x80;//定时器0不分频
TMOD=0x11;//定时器方式1
TH0=T0_HIGH;//定时器赋初值
TL0=T0_LOW;
TR0=1;//定时器运行
ET0=1;//开定时器中断
IT0=1;
EX0=1;
EA=1;//开总中断
}
//-----------------------------------------------------------------------
intABS(inti)//绝对值函数
{
if(i>=0)returni;
elsereturn-i;
}
//-----------------------------------------------------------------------
voiddelay(unsignedinti)//延时函数
{
unsignedcharj;
for(;i>0;i--)
for(j=0;j<250;j++);
}
//------------------------------------------------------------------------
intjudge_sign(inta)//判断误差误差绝对值大于1位正
{
if(error<=-16||error>=16)
a=1;
elseif(error<-12||error>=12)
a=-1;
else
a=0;
returna;
}
//-----------------------------------------------------------------------
voidget_black_position(void)//寻找黑线位置
{
P2H=P0&0xc0;
P2H=P2H<<2;
P2H=P2H+P2;
switch(P2H&0x3ff)
{
case0x001:
error=26;break;//0000000000010x001//右
case0x003:
error=24;break;//0000000000110x003
case0x002:
error=21;break;//0000000000100x002
case0x006:
error=18;break;//0000000001100x006
case0x004:
error=15;break;//0000000001000x004
case0x00c:
error=12;break;//0000000011000x00c
case0x008:
error=10;break;//0000000010000x008
case0x018:
error=7;break;//0000000110000x018
case0x010:
error=5;break;//0000000100000x010
case0x030:
error=3;break;//0000001100000x030
case0x020:
error=0;break;//0000001000000x020//中
case0x060:
error=-3;break;//0000011000000x060
case0x040:
error=-7;break;//0000010000000x040
case0x0c0:
error=-10;break;//0000110000000x0c0
case0x080:
error=-14;break;//0000100000000x080
case0x180:
error=-18;break;//0001100000000x180
case0x100:
error=-21;break;//0001000000000x100
case0x300:
error=-24;break;//0011000000000x300
case0x200:
error=-26;break;//0010000000000x200//左
case0x000:
error=lasterror;break;//0000000000x000
default:
error=lasterror;break;//其他情况时,保持上一次偏差
}
}
//-----------------------------------------------------------------------
voidservo_control(void)//舵机控制
{
chari=0;
if(ABS(error-lasterror)>200)//如果两次的偏差过大,则保持上一次的偏差
error=lasterror;//防止不确定情况(如红外管冲出跑道)造成的偏差跳变
//根据偏差计算舵机角度输出
PID_out=(servo_P*error//比例
+servo_I*lasterror//积分
+servo_D*preverror)/100//微分
;//这里使用乘以一个大的系数再除以一个数的方法
//将小数计算转换成整数计算,如*0.1可转换为*10/100。
以减轻单片机的负担
servo_PWM=SERVO_MID_PWM+PID_out;//控制舵机
if(servo_PWMservo_PWM=SERVO_LEFT_MAX_PWM;//防止舵机超过极限值
if(servo_PWM>SERVO_RIGHT_MAX_PWM)
servo_PWM=SERVO_RIGHT_MAX_PWM;
preverror=lasterror;
lasterror=error;
error_array[0]=error;
for(i=2;i>0;i--)
{
error_array[i]=error_array[i-1];
}
}
//-----------------------------------------------------------------------
voidmotor_control(void)//电机控制
{
intstate=0;
inti;
for(i=0;i<3;i++)
{
state=state+judge_sign(error_array[i]);
}
switch(state)
{
case0:
speed_expect=70;break;
case3:
speed_expect=35;break;
case-3:
speed_expect=35;break;
default:
break;
};
left_motor_PWM=speed_expect+PID_out;//速度控制
right_motor_PWM=speed_expect-PID_out;//可以直接给定,也可以根据赛道情况计算得出
if(left_motor_PWM>MOTOR_MAX_PWM)//限幅
left_motor_PWM=MOTOR_MAX_PWM;
if(left_motor_PWMleft_motor_PWM=MOTOR_MIN_PWM;
if(right_motor_PWM>MOTOR_MAX_PWM)
right_motor_PWM=MOTOR_MAX_PWM;
if(right_motor_PWMright_motor_PWM=MOTOR_MIN_PWM;
}
//-----------------------------------------------------------------------
voidmain(void)
{
sys_init();//初始化;
while
(1)
{
KeyScan();
get_black_position();//判断黑线位置
servo_control();//控制舵机
motor_control();//控制电机
LCD_write_int(65,4,speed_counter);
while(control_period_finished==0);//等待控制周期20ms到达,保证每次控制的时间间隔都相同
{
control_period_finished=0;//标志位清零
//temp=temp++;
//if(temp>100)
//speed_counter=0;
}
}
}
//-----------------------------------------------------------------------
voidTIME_BASE(void)interrupt1using1//定时器生成PWM//不清楚的可以参考PWM的定义
{
TH0=T0_HIGH;//赋初值
TL0=T0_LOW;
motor_PWM_counter++;//计数器+1,每+1表示10us
servo_PWM_counter++;
if(motor_PWM_counter>MOTOR_MAX_PWM_COUNT)//PWM比较、生成
{
motor_PWM_counter=1;//从1开始计数
}
if(servo_PWM_counter>SERVO_MAX_PWM_COUNT)//PWM比较、生成
{
servo_PWM_counter=1;//从1开始计数
control_period_finished=1;//20ms控制周期到达,标志位置1,这里借用了舵机控制周期20ms(50Hz),
//如果更改主程序控制周期,可定义一个类似于servo_PWM_counter的计数器计时
}
if(left_motor_PWM>=motor_PWM_counter)//左右PWM
LEFT_MOTOR_PWM_PORT=1;//端口输出高电平
else
LEFT_MOTOR_PWM_PORT=0;//端口输出低电平
if(right_motor_PWM>=motor_PWM_counter)
RIGHT_MOTOR_PWM_PORT=1;
else
RIGHT_MOTOR_PWM_PORT=0;
if(servo_PWM>=servo_PWM_counter)//舵机PWM
SERVO_PWM_PORT=1;
else
SERVO_PWM_PORT=0;
}
voidexint()interrupt0
{
EX0=0;
speed_counter++;
EX0=1;
}
三、问题与调试
最初部分是焊接原件,通过比照电路图说明,将各个原件焊接上去,这是考验的我们的焊板子的能力,自动化的学生必然会遇到很多焊接的问题。
而红外探测的时候则是看着pcb原理图焊接的,自己设计联系最终做成的稳定的w行探测电路。
将原始程序修改一部分之后烧到单片机中,发现舵机无法自动对中,经过老师的测试后发现是舵机问题,舵机坏掉了,更换舵机后再次进行调中,这次总算成功了。
接着是上调经跑道的测试,程序中比较重要的两个参数是PID和error,P是比例,error为偏差,error乘以一个参数是舵机调整的角度,先在固定跑道上测试红外灯、传感器以及舵机的转向,发现舵机始终不能在中线上,就讲error=0的从五六号灯改到七号灯,使舵机的转向正常,能辨识到中间。
随后就是修改PID,舵机转向过于灵敏,此时就将P值改小,而用参数D提高响应做一个辅助作用。
此时却发现一侧电机会时不时的在摩擦力过大时停止转动,当时感觉是pwm波的最小值的问题,虽然不了解具体原因,修改最小值为50之后能就不会再出现电机停止的问题,但是再改小之后仍会发生,所以最小值只能用50。
最后,赛车可以正常的跑完室内赛道,但是冲出跑道的时候无法停止,速度闭环最终还是没有写出。
在最后的比赛时,车子由于出现问题,最后只是以很慢的速度跑完全程,留下遗憾。
4、心得体会
这次做车的过程让我了解到传感器的使用,以及舵机电机的pwm控制机理,通过编程了解我们专业的控制过程,通过算法实现对智能车的PID控制以及反馈控制,使我们的专业知识与实践充分结合,对我们以后的学习也会有更大的好处。