编号:
哈尔滨工业大学
大二年度项目结题报告
项目名称:简易智能车
项目负责人:谢启明
学号:1120110323
联系电话:187********电子邮箱:xieqimingHIT@https://www.wendangku.net/doc/9116581888.html,
院系及专业: 电气工程及自动化学院测控技术与仪器
指导教师:赵勃职称:讲师
联系电话:136******** 电子邮箱:hitzhaobo@https://www.wendangku.net/doc/9116581888.html,
院系及专业:电气工程及自动化学院测控技术与仪器
哈尔滨工业大学基础学部制表
填表日期:年月日
一、项目团队成员(包括项目负责人、按顺序)
姓名性别所在院学号联系电话本人签字谢启明男电气工程及其自动化1120110323 187********
魏孙贵男电气工程及其自动化1120110325 150********
何园慧女电气工程及其自动化1120110301 182********
周艾玉女电气工程及其自动化1120110311 151********
二、指导教师意见
签名:
年月日三、项目专家组意见
批准经费:元
组长签名:(学部盖章)
年月日
(一)立项背景
随着机械自动化的不断发展,人们在生活的各个方面都希望能够利用自动化的操作来提高工作效率,使生产发展能够得到不断的提高。近来在轨迹跟踪方面的话题研究不断引起人们的更多关注,国内外更是开展了一系列的智能轨迹跟踪系统的竞赛活动。在实际应用中,具有智能化的机器人在人们无法触及的工作场合下更是大显身手,如各种军事机器人、勘探机器人等。和我们日常生活更为接近的有各种医疗机器人、汽车自动泊位系统、自动驾驶系统等等。
轨迹跟踪系统的设计在机器人领域有着重要的地位,可以说是机器人实现智能化的一个重要指标。任何一个机器人想要实现智能化就必须能够实现对外部环境的自我感知判断并作出相应反应,最终完成人们布置的任务。
本设计是一种基于单片机控制的自动寻迹小车系统,包括小车系统构成软硬件的设计方法。该项目的研究可以使学生掌握单片机和传感器的交互,还有智能寻迹小车的基本原理,掌握单片机的程序设计,熟悉单片机的开发过程与程序的下载、调试流程等。
项目的研究价值在于单片机对传感器的管理及对其反馈信息处理后对电机的精确控制,以及自动避障、相互之间通讯功能的研究和实施。
(二)项目成果
1、焊接调试完成运放模块,可使智能车具有六路电感信号传输能力,其中四路为常用通道,两路为备用通道。
2、测试完成舵机数据,记录了舵机在不同占空比的PWM波输入情况下的转弯参数。
3、测试完成电机数据,记录了电机在不同占空比的PWM波输入情况下的速度参数。
4、焊接完成连接xs128主控板,舵机模块,四路电源,电机模块的支撑电路板和导线连接,各个模块之间连接正常,支架稳定。
5、增加了电压示数器,主控板开关,电机开关等小部件。方便控制智能车,以及对电池电量的掌握,得到了稳定的电压参数和不同电压下造成的电机速度不同的参数。
6、掌握了xs128芯片的锁相环模块,时钟模块,AD转换模块,PWM输出模块等。
7、确定了碳杆的前伸长度,以及传感器的分布。通过实测数据得到了智能车行驶过程中的前瞻程度参数,为程序中的PID算法提供比例设置参数。
9、采用了简单的有线串口传输设置,可以在电脑窗口上得到智能车的行驶数据,为程序中参数的设置提供了参考。
10、提出完善的程序设计思路,控制算法。编写完成完整的xs128程序,能使智能车在简易赛道上低速行驶。
(三)128芯片主程序
1、程序设计思路
接收电感数据,经过AD转换后。先确定四个电感相对于导线的位置,从而算出导线相对于智能车中心线的位置。根据位置关系,确定输出给舵机模块的占空比大小,示意图如图1所示。
跑道信号线
图1
2、控制算法原理
(1)AD采集
从左到右的电感依次编号为1、3、5、7。信号依次输入到AD_value[1]、AD_value[3]、AD_value[5]、AD_value[7]。
(2)AD数据处理
相对于电感的位置,把跑道信号线的位置从左到右依次编号为0、2、4、6、8。找到数值最大的电感编号,以及最大值,采用分类判断的方法,根据相邻两个电感数值的差值和实测数据来判断信号线的位置。
转化AD_value[]为NewAD_value[] 前者为正值,后者为负值。
(3)PID控制,出于稳定性考虑只使用Kp和Kd。PID函数的error根据实测数据得出,由于智能车左右的不对称性,所以左右转弯时的error有所差别。
(4)主函数
根据LineNum提供的信号线位置,来提供不同的Kp和Kd。从而根据PID算出LoadDir ,即提供给舵机模块的占空比。根据LoadDir来决定提供电机模块的占空比来决定电机的速度。
3、主程序
(四)、硬件配置
1、首先对车体进行了组装和一定程度的改装。比如将舵机由卧式改为立式,从而提高舵机的响应速度,减少弯道处智能车处理的反应时间。
2、然后焊接,调试,装配各个模块。在确保各个模块安全的工作前提下,提升整车的系统稳定性和
硬件结构的对称性,为程序的调试和运行提供一个良好稳定的平台。
图2为硬件装配图(由于处于改装期,部分碳杆和主控板暂时取下)。
图2
3、部分硬件模块的作用
(1)四路电源
电源模块,为整个系统的其他模块提供合适而又稳定的电源。如左图电源模块,输入电压7~23V时,能同时提供5V,3.3V,12V,-6V 四路常用电压。独立使用时分别提供600mA,400mA,200mA,120mA的电流。
(2)电机模块
接受128主控板的PWM信号,驱动直流电机完成智能车的加减速控制。
(3)舵机模块
接收128主控板的PWM信号,控制舵机的转向。
(五)项目末期阶段进展情况
1、根据智能车的整体运行姿态,修整了硬件模块以确保充分的对称性和稳定性,从而获得更好的弯道性能。优化了算法和创新程序设计理念,提升系统的准确性,高效性和安全性。
2、学习Labview软件,尝试建立智能车运行数据的窗口反馈,以便更好的获得和分析实时数据。增加蓝牙等数据传输模块,使智能车能得到电脑等其他终端发出的信号,实现远程控制。
3、增加光电编码器,启用xs128芯片上的计数和计时模块,实现速度闭环。能够更好的控制车速,使得在弯道减速,在直线加速的速度变化时间大为减少。速度控制更加准确灵活高效,同时能够进行急刹急停,提高了安全性。
4、在试图改变芯片的过程中,因为学习不足,未能完全掌握KL25,K60等芯片的原理和功能,所以未能更换掉芯片。
(六)项目成果
在2014年的飞思卡尔校内选拔赛中获电磁组第三名的成绩。
(七)人员安排
1、谢启明,组长,负责整个项目的进程和工作安排,同时负责编写和修改xs128程序。
2、何园慧,组员,负责测试智能车在行驶过程中的数据和为行驶过程中出现的相关问题提供解决思路。
3、魏孙贵,组员,负责硬件部分的改进和维修。
4、周艾玉,组员,负责Labview的学习和编程,并初步了解新的芯片如K60,KL25等。
(八)经费使用计划
序号名称型号单价(元)数量总额(元)使用说明
1 车模 A 625 1 625 智能车的机械基础
2 128单片机34 2 68 智能车的核心控制器
3 电机驱动30 1 30 驱动电机
4 舵机驱动1
5 1 15 驱动舵机
5 四路电源20 4 80 为各个模块供电
6 舵机支架70 1 70 固定舵机
7 编码器213.5 1 213.5 检测电机速度
8 固定套件8 4 32 固定碳杆
9 下载器50 1 50 向芯片中下载程序
10 总计1183.5
附录
#include
#include "derivative.h" /* derivative-specific definitions */
//static long AD_value0,AD_value1,AD_value2,AD_value3;
int AD_value[8]; //定义AD函数
int NewAD_value[8];
int LastPwm;
int LastLine=4,NowLine=4;
int MLine,MC;
long a,b,c,d,e,f,g,h;
long int C1,C2,C3,C4;
int i,LoadDIr,I,LoadDir;
int MaxNum,MaxValue,LineNum,m;
float ferror=0,error=0,error1=0,error2=0;
float Kacc=0,Kdiff=0,Kp=9.3,Ki=0,Kd=1;
float k,k1,k2,k3,k4;
float x1,x2,x3,x4;
/***************************锁相环初始化程序*********************************/ void Pll_Init(void) //PLLCLK=2*OSCCLK*(SYNR+1)/(REFDV+1)
{ //锁相环时钟=2*16*(2+1)/(1+1)=48MHz
REFDV=1; //总线时钟=48/2=24MHz
SYNR=2;
while(!(CRGFLG&0x08));
CLKSEL=0x80; //选定锁相环时钟
}
/********************延时子程序**********************************************/ //void Delay(unsigned int loop_times)
// {
// unsigned int loop_i,loop_j;
// for (loop_i=0; loop_i< loop_times; loop_i++)
// {
// for (loop_j=0; loop_j<500;loop_j++)
// {
// ;
// }
// }
// }
//*********************************电机初始化*********************************// void PWM_Init(void) //电机初始化以一个较低的速度行驶
{
PWME_PWME3=0x00;
PWMPRCLK_PCKB = 0x00;
//PWMSCLA=0;
// PWMSCLB=1;
PWMCLK_PCLK3=0;
PWMPOL_PPOL3=0;
PWMCAE_CAE3=0;
PWMCTL_CON23=1;
PWMPER23=1245;
PWMDTY23=300;
PWME_PWME3=1;
}
/****************************舵机初始化程序****************************/
void SERVOPWM_Init(void)
{
PWME_PWME5=0; //PWM1通道使能
PWMCTL_CON45=1; //0和1联合成16位PWM
PWMCLK_PCLK5 = 1; //选择clock SA作时钟源
PWMCNT45 = 0; //计数器清零
PWMPOL_PPOL5=1; //先输出高电平,计数到DTY时,反转电平
PWMPRCLK = 0; //clock A不分频,即clock A=busclok
PWMSCLA = 12; //对clock SA进行分频,PWM clock=clockA/(2*12)=1MHz
//PWMPER01 = 3333; //周期为3.3ms;300Hz
PWMCAE_CAE5=0; //选择输出模式为左对齐输出模式
PWMPER45 = 20000; //周期为20ms;50Hz
//PWMDTY45=2250; //500-2500;
PWME_PWME5=1; //PWM1通道使能
}
/***********************AD初始化**********************************/
void Init_AD_more(void)
{
A TD0DIEN = 0X00; // 禁止数字输入
A TD0CTL1_SRES = 2; //选用12位模数转换
A TD0CTL2 = 0X40; //启动A/D转换,快速清零,禁止中断
// Delay(); //延时
A TD0CTL3=0Xa0; //10100000 转换序列长度为4 右对齐
A TD0CTL4 = 0x07; //AD模块时钟频率为2MHz fA=fBUS/(PRS+1)/2
A TD0CTL5=0X30; //多通道,连续转换,起始通道AD0 AD1,AD2,AD3,
}
/**************************AD采集**********************************/
void AD_get_more(void)
{
while(!ATD0STAT2_CCF0);
{
PORTA_PA0=1; a=A TD0DR0;AD_value[1]=a;
}
while(!ATD0STAT2_CCF1);
{
PORTA_PA1=1; b=A TD0DR1;AD_value[3]=b;
}
while(!ATD0STAT2_CCF2);
{
PORTA_PA2=1; c=A TD0DR2;AD_value[5]=c;
}
while(!ATD0STAT2_CCF3);
{
PORTA_PA3=1; d=A TD0DR3;AD_value[7]=d;
}
}
/**************************AD数据处理**********************************/ void Dir_Ctrl(int AD_value[])
{
MaxValue = AD_value[1];
MaxNum=1;
if(AD_value[3] >= MaxValue)
{
MaxNum = 3;
MaxValue = AD_value[3];
}
if(AD_value[5] >= MaxValue)
{
MaxNum = 5;
MaxValue = AD_value[5];
}
if(AD_value[7] >= MaxValue)
{
MaxNum = 7;
MaxValue = AD_value[7];
}
switch(MaxNum)
{
case 1:
C1=AD_value[1]-AD_value[3];
if(C1>300)
{
LineNum=0;
MLine=0;
}
else
{
LineNum=2;
MLine=1;
}
break;
case 3:
C2=AD_value[3]-AD_value[1];
if(C2>300)
{
LineNum=4;
MLine=3;
}
else
{
LineNum=2;
MLine=1;
}
break;
case 5:
C3=AD_value[5]-AD_value[7];
if(C3>300)
{
LineNum=4;
MLine=3;
}
else
{
LineNum=6;
MLine=2;
}
break;
case 7:
C4=AD_value[7]-AD_value[5];
if(C4<300)
{
LineNum=6;
MLine=2;
}
else
{
LineNum=8;
MLine=1;
}
break;
}
for(I=0;I<9;I++)
{
if(I>LineNum)
{
NewAD_value[I]=-AD_value[I];
}
else
{
NewAD_value[I]=AD_value[I];
}
}
ferror=(1/(float)NewAD_value[1]+1/(float)NewAD_value[3]+1/(float)NewAD_value[5]+1/(float)NewAD_value[ 7]);
error=1000*ferror;
if(error>0)
{
error1=1+0.996*error;
}
else if(error<0)
{
error1=0.987*error;
}
else
{
error1=0.5;
}
}
/****************************主函数*********************************/
void
main(void)
{
Pll_Init();
PWM_Init();
SERVOPWM_Init();
Init_AD_more();
while(1)
{
NowLine=MLine;
AD_get_more();
Dir_Ctrl(AD_value);
Kacc += error1;
if(NowLine { if(LineNum==0) { // Kp=28; // Kd=2.8; Kp=22; Kd=2.2; } if(LineNum==8) { Kp=32; Kd=3.2; } if(LineNum==2) { // Kp=18; Kp=13; Kd=0; } if(LineNum==6) { Kp=22; Kd=0; } if(LineNum==4) { Kp=9.3; Kd=0; } // PWMDTY23=300; } else { Kp=9.3; Kd=0; // PWMDTY23=500; } if(Kacc>30000) { Kacc = 30000; } if(Kacc<-30000) { Kacc = -30000; } Kdiff = error1 - error2; LoadDir = (int)(2275 - (Kp * error1 + Ki * Kacc + Kd * Kdiff)); error2 = error1; if(MaxValue<150) { PWMDTY45=LastPwm; // PWMDTY23=370; } else { if(LoadDir>=2425) { PWMDTY45=2425; PWMDTY23=370; LastPwm=PWMDTY45; } else if (LoadDir<=2125) { PWMDTY45=2125; PWMDTY23=370; LastPwm=PWMDTY45; } else { PWMDTY45=LoadDir; PWMDTY23=420; LastPwm=PWMDTY45; } } LastLine=NowLine; ; } }