开放性实验报告
——避障机器人设计
系 别:智能科学与技术
姓 名:唐继鹏
姚武浩
姜飞鹏
郑光旭
指导老师:袁立行、王曙光、亢红波
时 间:2011.9.16——2012.4.28
目 录
1 系统功能介绍... 1
2 设计任务与要求... 1
3 系统硬件设计... 1
3.1系统总体设计框图... 1
3.2寻线模块(ST188) 2
3.3电机控制模块... 3
3.4单片机最小模块... 4
3.5数码管显示模块... 5
4 系统软件实现... 6
4.1 设计思路... 6
4.2 软件程序流程图... 7
4.3程序代码见附录Ⅰ... 7
5 调试结果... 7
6 实验总结... 8
附录Ι... 10
附录Ⅱ... 18
附录Ⅲ………………………………………………………………19
1 系统功能介绍
本设计以单片机作为控制核心,电路分为最小系统模块,黑线检测模块,电机驱动模块,数码管显示模块。黑线检测模块采用反射式关电传感器st188,并且接相应的三级管来规划传感器的输出,当输出高电平为正常情况。电机为伺服电机,给定脉宽为1.5ms的信号电机保持不动,给定脉宽为1.7ms的信号电机正向转到给定脉宽为1.3ms的信号电机逆向转到。数码管动态显示机器人行进过程所用的时间。
2 设计任务与要求
u 熟悉51系列单片机的原理及应用。
u 掌握ST188设计电路和传感器的使用。
u 掌握直流电机的驱动方法。
u 掌握动态数码管显示的方法。
u 设计机器人的硬件电路及软件程序。
u 制作机器人的硬件电路,并调试软件,最后实现机器人的自动测量黑线。
3 系统硬件设计
3.1系统总体设计框图
该系统中51单片机作为主微控芯片,其外多个I/O口作为通用I/O口接受传感器的信号并输出相应的控制信号。
系统硬件总体设计框图如下图3.1-1所示。
图3.1-1系统硬件总体设计框图
3.2寻线模块(ST188)
该系统中的寻线模块我们采用的是ST188传感器。ST188是一个无限红外模块,它有一个发射管(白色)和一个接收管(黑色),一般情况下接收管能收到发射管发送的红外光,但当遇到吸光介质(如黑色物体)时接收管便不能收到发射管的红外光。由于这种现象,加上合适的硬件电路(如图3.2-1),我们可以引出一条信号线,当一切正常时,信号线处于一种状态,但当遇到吸光介质时信号线便处于另一种状态,利用这种不同状态的差异我们便可以通过微控制器来实现机器人的寻线行驶。ST188详细资料见附录Ⅱ
下图3.2-1是该系统中我们的ST188外接硬件电路图:
图3.2-1 寻线模块电路图
图中R1为发射管的限流电阻,若R1阻值过大,则发射管功率会大幅降低,所以其阻值在50-200欧之间。R4为发光二极管的保护电阻。R2,R3,RV1为起分流的作用,其阻值可根据情况而定。其工作原理是通过R2,R3,RV1来确定输出信号的门限值,当发射管E端V高于RV1上的压降时,由于运放的饱和特性,输出低电压0V:当V低于RV1上的电压时,输出电压为5V。图中的通过发光二极管指示是否有信号输出。
实际硬件中我们可以通过调节滑动变阻器的R5电阻值来选取理想的反射距离,从而提高ST188传感器的灵敏度。
本设计中我们利用ST188来控制机器人寻线。由以上叙述可知,为使机器人寻线稳定,最好选择差异较大的环境,例如在白地板上贴上黑线,可使ST188寻线模块工作更加灵敏稳定。
3.3电机控制模块
本次实验采用的伺服电机的工作模式如下所示:
通过I/O口给电机的信号输入如图3.3-1所示的信号电机保持静止,这个信号称为电机的零标定信号,这个指令由时间间隔为20ms脉宽为1.5ms的一系列脉冲组成。
图3.3-1电机控制信号(静止状态)
通过I/O口给电机的信号输入如图3.3-2所示的信号电机将全速逆时针旋转,这个指令由时间间隔为20ms脉宽为1.3ms的一系列脉冲组成。
图3.3-2电机控制信号(逆时针旋转状态)
通过I/O口给电机的信号输入如图3.3-3所示的信号电机将全速逆时针旋转,这个指令由时间间隔为20ms脉宽为1.7ms的一系列脉冲组成。
图3.3-3电机控制信号(顺时针旋转状态)
3.4电机驱动模块
电机驱动芯片L298N是SGS公司的产品,内部包含4通道逻辑驱动电路。是一种二相和四相电机的专用驱动器,即内含二个H桥的高电压大电流双全桥式驱动器,接收标准TTL逻辑电平信号,可驱动46V、2A以下的电机。其引脚排列如图1中U4所示,1脚和15脚可单独引出连接电流采样电阻器,形成电流传感信号。L298可驱动2个电机,OUT1、OUT2和OUT3、OUT4之间分别接2个电动机。5、7、10、12脚接输入控制电平,控制电机的正反转,ENA,ENB接控制使能端,控制电机的停转。也利用单片机产生PWM信号接到ENA,ENB端子,对电机的转速进行调节。
L298N的逻辑功能:
表1 SHARP GP2D12实物图
外形及封装:
L298N实物图
由于一片L298N可以直接驱动两个电机,但是为了加大驱动力,我们采用两路并联的方式来驱动电机
3.5单片机最小模块
整个实验的控制器件是51单片机,它在实验中起了核心作用,采用内部时钟方式,给它的XTAL1和XTAL2引脚外接晶振,这样就构成了自激振荡器并在单片机内部产生时钟脉冲信号,给晶振的每个角又接了一个30PF的电容,让晶振快速起振并可以达到12M稳定频率,给单片机的RST口按键开关使之构成复位电路。具体电路如图3.4-1所示
图3.4-1单片机最小模块
3.5数码管显示模块
由于时钟电路显示的内容是变化的,因此本实例采用动态显示
实验时数码管采用的是共阳极的数码管,4个数码管的段选相应并联在一起,由一个8位的I/O控制,动态显示时,各位数码管轮流通,要使其稳定显示必须采用扫描的方式,即在某一时刻只选通以位数码管,并送出相应的段码,在另一时刻选通另一位数码管,并送出此想相应的段码,依次规律循环,即可使各位数码管显示将要显示的字符,虽然这些字符是不不同的时刻分别显示的,但由于人眼存在暂留效应,只要每位显示时间足够短就可以给人不同的显示感觉。
采用动态显示方式时,采用三极管的放大作用,以增加led的亮度。具体电路图如3.5-1所示。其中数码管的ds1端的各位1、2、3、4、5、6、7接I/O的P2口,位选端接I/O的P1口。
图3.5-1数码管硬件电路
4 系统软件实现
4.1 设计思路
在程序中用定时器0用用于输出机器人电机所需的脉冲波形,定时器1用于数码管显示。计数器0,1初始化后,进入while循环,在while循环中等待定时器1中断并相应的相应时间。否则等待定时器0输出脉冲波形。由于中断1只是为了显示时间,而0中断影响到机器人的行进与否,所以在程序中设置1中断的优先级高于0中断。从而使从而使I/O口输出稳定的脉冲波形。
4.2 软件程序流程图
图4.2-1系统软件程序流程图
4.3程序代码见附录Ⅰ
5 调试结果
开放性试验使我掌握了不少知识,在实验开始之前我什么都不会,通过壁障机器人的训练使我掌握了51单片机,基本电路的设计和分析。但本次试验对我印象最深的是我自己在调试程序的时候出现的问题,开始小车应该在驱动和程序的控制下应该调速,但事实是车根本没有减速的迹象并且是全速前进。我检查自己的程序感觉程序是没有问题的,然后自然的把问题想到了驱动上,但驱动不是我自己焊接的,根本不知道错误从哪里找。焊接驱动的同学回家了,没办法看驱动电路。只能是我自己看电路但自己对电路根本就没有多接触,当时自己检查电路图不知从何开始,整整检查了一天感觉没有问题感觉已经尽力了。晚上回到宿舍自己想了半天还是没有找到问题。第二天回到实验室问题还是没有找到,但就在自己已经没有精力在检查的时候无意间看到了程序又看了一会ST188然后就突然感觉问题找到了,自己看看了循迹模块然后感觉中间的灯没有亮,那就是意味这他给51的管脚一直是低电平是自己的程序一直就没进入其他程序,所以就出现了全速前进的问题。还有一次在给壁障机器人调试程序时他根本就不遍历所有的道路,自己给51已经下了一百多次程序,还是没有找到问题还是。回到宿舍睡觉,下午原本打算不去了,但自己心里还是在想再试试。来到实验室,我的第三个程序便成功遍历了所有的道路。通过上面的经历使我自己明白了很多,只要自己有足够的耐心和毅力就一定能过实现你要完成的事情。
6 实验总结
附录Ι
程序代码如下:
#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit ENA=P1^0; //左轮使能端
/*左轮电压*/
sbit d0=P1^1;
sbit d1=P1^2;
/*右轮电压*/
sbit d2=P1^3;
sbit d3=P1^4;
sbit ENB=P1^5; //右轮使能端
/*循迹两侧传感*/
sbit right_red=P0^2; //右侧
sbit left_red=P0^1; //左侧
sbit redlight=P0^3; //红外
sbit goright=P0^0; //拐弯检测
/********************向前***********************/
void gohead()
{
d0=1;
d1=0;
d2=1;
d3=0;
}
//左转
void turnleft()
{
d0=0;
d1=0;
d2=1;
d3=0;
}
//右转
void turnright()
{
d0=1;
d1=0;
d2=0;
d3=0;
}
//倒转
void turnback()
{
d0=1;
d1=0;
d2=0;
d3=1;
}
/*延时函数*/
void delay_ms(uint i)
{ uint j;
for(;i>0;i--)
for(j=110;j>0;j--);
}
/*循迹模块*/
void xunjin()
{
int i;
if((left_red==0)&&(right_red==0)&&(goright==0))
{
gohead();
for(i=20;i>0;i--)
{
if(i>16)
{
ENA=1;
ENB=1;
delay_ms(6);
}
else
{
ENA=0;
ENB=0;
delay_ms(5);
}
}
}
else if((left_red==0)&&(right_red==1))
{
turnright();
for(i=20;i>0;i--)
{
if(i>17)
{
ENA=1;
ENB=0;
delay_ms(4);
}
else
{
ENA=0;
ENB=0;
delay_ms(5);
}
}
}
else if((left_red==1)&&(right_red==0))
{
turnleft();
for(i=20;i>0;i--)
{
if(i>17)
{
ENA=0;
ENB=1;
delay_ms(4);
}
else
{
ENA=0;
ENB=0;
delay_ms(5);
}
}
}
else if(goright)
{
gohead();
for(i=20;i>0;i--)
{
if(i>17)
{
ENA=1;
ENB=1;
delay_ms(7);
}
else
{
ENA=0;
ENB=0;
delay_ms(5);
}
}
while(1)
{ turnright();
for(i=20;i>0;i--)
{
if(i>17)
{
ENA=1;
ENB=0;
delay_ms(4);
}
else
{
ENA=0;
ENB=0;
delay_ms(5);
}
}
if(right_red==1) break;
}
}
}
//避障程序
void goback()
{
while(1)
{ uint i;
turnback();
for(i=20;i>0;i--)
{
if(i>17 )
{
ENA=1;
ENB=1;
delay_ms(5);
}
else
{
ENA=0;
ENB=0;
delay_ms(5);
}
}
if( right_red==1)
{
break;
}
}
}
/*主程序*/
void main()
{
while(1)
{
xunjin(); //循迹
if(!redlight) //判断
{
goback();
}
}
}
数码管显示程序:
#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit d1=P1^0;
sbit d2=P1^1;
sbit d3=P1^3;
uchar code DSY_CODE[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //4位一体共阳极数码管//
uint k=0;
uchar int_time,second;
void delay(uchar x)
{
uchar i ;
for(;x>0;x--)
for(i=0;i<120;i++);
}
void showtime()
{
d1=0;
P2=DSY_CODE[k%10]; //显示各位//
delay(2);
P2=0Xff ;
d1=1;
d2=0 ;
P2=DSY_CODE[k/10%10]; //显示十位//
delay(2);
P2=0Xff ;
d2=1;
d3=0;
P2=DSY_CODE[k/100]; //显示百位//
delay(2);
P2=0X00 ;
d3=1;
}
void main()
{
TMOD=0x01;
TR0=1;
EA=1;
ET0=1;
IT0=0;
P2=0xc0;
TH0 =(65535 - 50000)/256;
TL0 = (65535 - 50000)%256;
while(1)
{
showtime();
}
}
void timer0() interrupt 1
{
int_time++;
if(int_time == 20)
{
int_time = 0;
k++;
if(k == 999)
k = 0;
}
TH0 = (65535-50000)/256;
TL0 = (65535-50000)%256;