0
点赞
收藏
分享

微信扫一扫

【IoT】红外避障小车


言​

随着生产自动化的发展需要,机器人已经越来越广泛地应用到生产自动化上,随着术的发展,机器人的传感器种类也越来越多,其中红外传感器已经成为自动行走和驾驶的重要部件。

红外的典型应用领域为自主式智能导航系统,机器人要实现自动避障功能就必须要感知障碍物,感知障碍物相机器人一个视觉功能。智能避障是基于红外传感系统,采用红外传感器实现前方障碍物检测,并判断障碍物远近。而利用红外对不同颜色物体反射强弱差别又可以实现循迹功能。

由于时间和水平有限,我们暂选最基本的避障,循迹功能作为此次设计的目标。

本设计通过小车这个载体再结合由STC89C52为核心的控制板可以达到其基本功能,再辅加由漫反射式光电开关组成的避障电路,基于PWM技术的转速控制、电源电路、电机驱动电路就可以完善整个设计。​

1.【摘 要】:本文提出一种智能避障,循迹小车的设计方法,利用红外技术检测障碍物,轨迹信息,采用STC89C52单片机进行实时控制,实现智能避障,智能小车采用前轮驱动,两轮各用一个直流电机控制,避障,循迹用的传感器采用红外漫反射式传感器。

【关键词】: 避障 循迹 光电开关 差分控制

PWM LCD 测速


2. 功能概述

智能小车采用前轮驱动前轮左右两边各用一个电机驱动分别控制两个轮子的转动从而达到转向的目的后轮是万向轮起支撑的作用避障部分,将3个红外线光电传感器分别装在车体的左中右当车的左边的传感器检测到障碍物时主控芯片控制右轮电机停止左轮转动车向右方转向当车的右边传感器检测到障碍物时主控芯片控制左轮电机停止转动车向左方转向当前面有障碍物时规定车右转。而当小车同时有两个传感器接收到信号时,采用倒退方式转弯以避免碰到障碍物,于此同时测定速度并显示,在避障小车前进的同时从LCD点阵液晶显示器上显示小车当时速度和行驶的路程。

循迹部分,采用七个红外传感器置于车身前下方,中间五个主要用于循迹普通道路,外边两个略比中间的靠前,主要用来检测直角弯道。车向左偏时右拐,右偏时左拐,左右拐又分为校正和转弯两档。遇到直角时极易冲出跑道,故给车施加一个反向脉冲。行驶过程中显示屏显示车速及路程。

3.硬件设计

如下图所示,是本次设计智能小车的电路框图。以STC89C52为电路的中央处理器,来处理传感器采集来的数据,处理完毕之后以便去控制电机驱动电路来驱动电机。电源部分是为整个电路模块提供电源,以便能正常工作。



【IoT】红外避障小车_单片机

【IoT】红外避障小车_红外_02



4. 避障电路

(1) 障碍物探测方案的选择

方案一:脉冲调制的反射式红外线发射接受器。由于采用该有交流分量的调制信号,则可大幅度减少外界干扰;另外红外线接受官的最大工作电流取决于平均电流。如果采用占空比小的调制信号,再品均电流不变的情况下,顺势电流很大(50100mA),则大大提高了信噪比。并且其反应灵敏,外围电路也很简单。它的优点是消除了外界光线的干扰提高了灵敏度。

方案二:采用超声波传感器,如果传感器接收到反射的超声波,则通知单片机前方有障碍物,如则通知单片机可以向前行驶。市场上很多红外光电探头也都是基于这个原理。这样不但能准确完成测量,而且能避免电路的复杂性

由以上两种方案比较可知。方案要比方案优势大,市场上很多红外观点探头也都基于这个原理。其电路简单,工作可靠,性能比较稳定。从而避免了电路的复杂性,因此我先用方案二作为小车的监测系统。

避障电路采用漫反射式光电开关进行避障。光电开关是集发射头和接收头于一体的检测开关,其工作原理是根据发射头发出的光束,被障碍物反射,接收头据此做出判断是否有障碍物。当有光线反射回来时,输出低电平;当没有光线反射回来时,输出高电平。单片机根据接收头电平的高低做出相应控制,避免小车碰到障碍物,由于接收管输出TTL电平,有利于单片机对信号的处理。

光电开关工作原理:

光电开关是通过把光强度的变化转换成电信号的变化来实现控制的。
光电开关在一般情况下,有三部分构成,它们分为:发送器、接收器和检测电路。



【IoT】红外避障小车_红外_03





【IoT】红外避障小车_红外_04



避障电路功能表:

传感器

避障电路输出(上升沿动作)

待执行命令

左转信号(P2.1)

右转信号(P2.0

0

0

0


后右转

0

0

1


右转

0

1

0


右转

0

1

1


右转

1

0

0


左转

1

0

1


右转

1

1

0


左转

1

1

1



前进

注解(“0”表示有障碍物; “1”表示无障碍物)

【IoT】红外避障小车_红外_05


(2)信号检测模块

小车循迹原理小车在画有黑线的白纸

红外探测法,即利用红外线在不同颜色的物理表面具有不同的反射性质的特点。在小车行驶过程中不断地向地面发射红外光,当红外光遇到白色地面时发生漫发射,反射光被装在小车上的接收管接收;如果遇到黑线则红外光被吸收,则小车上的接收管接收不到信号,再通过LM324作比较器来采集高低电平,从而实现信号的检测。避障亦是此原理。电路图如图3.4。

市面上有很多红外传感器,在这里我选用TCRT5000型光电对管。

【IoT】红外避障小车_单片机_06


图3.4循迹原理图


4. 单片机电路

本设计的主控芯片选择STC89C52负责检测传感器的状态并向电机驱动电路发出动作命令。复位电路采用手动复位。


【IoT】红外避障小车_单片机_07

单片机电路如下:




5. 电机转速控制电路

转速控制采用基于PWM技术的脉冲调制技术,通过单片机输出两列PWM信号,经过l298N对电机进行速度调控。

6. 电源电路

本系统所有芯片都需要+5V的工作电压,而干电池只能提供的电压为15V的倍数的电压,并且随着使用时间的延长,其电压会逐渐下降,故采用了一个12v蓄电池,再用LM7805稳压芯片。L7805能提供最大1A的电流,足以满足芯片供电的要求。虽然微处理器和微控制器不需要支持电路,功耗也很低,但必须要加以考虑。


电源电路拟定为:

【IoT】红外避障小车_智能车_08


7.电机驱动电路

市场上用很多种类的小电压直流电动机,很方便的选择到。主要有普通电动机、和步进电动机。

方案一:采用步进电机,步进电动机的一个显著的特点就是具有快速启动和停止能力,能够达到我们所要求的标准。如果负荷不超过步进电机所能提供的动态转矩值,就能够立即是步进电机启动或反转。其转换灵敏度比较高。正转、反转控制灵活。但是步进电机的价格比较昂贵,对于我们的现状相差太远。

方案二:采用普通的直流电机。直流电机具有优良的调速特性,调速平滑、方便。调整范围广;过载能力强,能承受频繁的冲击负载,可实现频繁的无极快速启动、制动和反转。能满足各种不容的特殊运行要求。

由于普通直流电机价格适宜,更易于购买,并且电路相对简单,因此采用直流电机作为动力源


本设计采用L298N驱动使电机正反转从而做到前进,左转右转。

【IoT】红外避障小车_智能车_09


驱动电路(参考文献[4]

电机驱动一般采用H桥式驱动电路,L298N内部集成了H桥式驱动电路,从而可以采用L298N电路来驱动电机。通过单片机给予L298N电路PWM信号来控制小车的速度,起停。其引脚图如3.2,驱动原理图如图3.3。



【IoT】红外避障小车_智能车_10


图3.2 L298N引脚图



【IoT】红外避障小车_智能车_11


图3.3 电机驱动电路



【IoT】红外避障小车_红外_12




源程序:

#include<reg52.h>

#include <intrins.h>

#include <string.h>

#define Busy 0x80 //用于检测LCM状态字中的Busy标识

#define LCM_Data P0

#define uchar unsigned char

sbit LCM_RS=P2^2; //1602寄存器选择

sbit LCM_RW=P2^1; //读/写控制

sbit LCM_E=P2^0;


sbit LLT=P1^7;//避障口

sbit RLT=P2^7;

sbit MLT=P3^4;


sbit S1=P1^0; 传感器信号输入端口

sbit S2=P1^1;

sbit S3=P1^3;//INT

sbit S4=P1^5;//LLT

sbit S5=P1^6;//RLT

sbit S6=P1^2;

sbit S7=P1^4;//OUT


sbit LH=P2^3; 电机1 左轮

sbit LL=P2^4;


sbit RH=P2^5; 电机2 右轮

sbit RL=P2^6;


sbit ENA=P3^6;//电机左轮使能

sbit ENB=P3^7;//电机右轮使能



sbit key1=P3^0;

sbit key2=P3^1;

sbit key3=P3^2;

sbit key4=P3^3;

/******************************************************

* 名 称:引脚定义

* 功 能:引脚定义

* 入口参数:无

* 出口参数:无

*******************************************************/




unsigned char

character1[][8]={{0x2,0x02,0x2,0x02,0x1F,0x02,0x06,0x7},{0x00,0x0F,0x8,0x08,0xF,0x08,0x08,0x0F},

{0x00,0x1C,0x4,0x4,0x1C,0x4,0x4,0x1C},{0xA,0xA,0x2,0x02,0x02,0x02,0x02,0x2},{0x19,0x09,0x8,0x08,0x8,0x0A,0x0C,0x08},

{0x2,0x4,0x18,0x10,0x8,0x4,0x2,0x03}};



int C1=0,C2=0,C3;//计数单位

static int SU0=0,SU1=0,SU2=0,SU=0;

static int SU3=0,V=0,V0=0,V1=0;




int tmp1=0,tmp2=0;//左右占空比调整tmp/T

int SPEED1,SPEED2;


uchar count=0; //初始化计数变量

uchar T=90; //pwm信号周期T*100us

/***********************************************************************

测距模块儿

***********************************************************************/


void delay10us() //延时,>10us

{

_nop_( );

_nop_( );

_nop_( );

_nop_( );

_nop_( );

_nop_( );

_nop_( );

_nop_( );

}


int mainceju()

{


char T;

int START,END,longth;

S3=0;S4=0;//初始化接口值

S4=1; //开始发射脉冲

delay10us(); //延时

while(!S3); //等待返回信号

START=(TH2*256+TL2);//开始计时

while(S3); //等待返回信号结束

END=(TH2*256+TL2);//关闭计时器


T=(TH0*256+TL0); //计算返回脉冲时间

lnotallow=340*T/20000;//计算测距结果厘米




return(longth);




}




/*****************************************************************************************************

循迹模块儿

****************************************************************************************************/

/******************************************************

*名 称elay(long int Delay_time)

*功 能:延时

*入口参数:Delay_time

*出口参数:无、

*说 明: 延时

******************************************************/


void delay(long int Delay_time)//延时函数

{

int i;

while(Delay_time)


{

for(i=0; i<150;i++)

{

_nop_();

_nop_();

_nop_();

_nop_();

}

Delay_time--;

}

}


//-----------------------------------------------

void correct_left()//向左校正,赋值

{

tmp1=T-30;

tmp2=T-15;

LH=1;

LL=0;

RH=1;

RL=0;

}

//------------------------------------------------

向右校正,赋值

{

tmp1=T-15;

tmp2=T-30;

LH=1;

LL=0;

RH=1;

RL=0;

}

//--------------------------------------------------

void turn_left()//左转,赋值

{

tmp1=0;

tmp2=T-25;

LH=0; 转弯时一个正转,一个反转,

LL=0;

RH=1;

RL=0;

}

//---------------------------------------------------

void turn_right()//右转,赋值

{

tmp1=T-25;

tmp2=0;

LH=1; 转弯时一个正转,一个反转,

LL=0;

RH=0;

RL=0;

}

//-----------------------------------------------------

void straightL() //慢直走,赋值

{

tmp1=T-40; //左右电机占空比初始化,调节直线运动速度

tmp2=T-40;

LH=1;

LL=0;

RH=1;

RL=0;

}


//-----------------------------------------------------

void straight() //直走,赋值

{

tmp1=T-10; //左右电机占空比初始化,调节直线运动速度

tmp2=T-10;

LH=1;

LL=0;

RH=1;

RL=0;

}

//-----------------------------------------------------

void back() //后退

{

tmp1=T-20; //左右电机占空比初始化,调节直线运动速度

tmp2=T-20; //鉴于左右轮电机内部阻力不同,故占空比取不同值,这组值需要单独写程序取值

LH=0;

LL=1;

RH=0;

RL=1;

}


//-----------------------------------------------------

void stop() //停车

{

tmp1=0;

tmp2=0;

LH=0;

LL=0;

RH=0;

RL=0;

ENA=0;

ENB=0;



}





/******************************************************

* 名 称:void turn()

* 功 能:路径控制

* 入口参数:int Position

* 出口参数:无

******************************************************/


void turn ()

{





if(!(S1|S2|S3|S4|S5|S6|S7))

{

_nop_();

_nop_();

back();

delay(20);

if((!S1)&(!S2)&S4&(!S6)&(!S7))

{

if(S4&S5&S6);

else

back();


}



}//后退寻线




//全白后退寻线




if(S1&S2&S3&S4&S5&S6&S7)

{

delay(1);

stop();

back();

delay(1);



}//全黑,停止



if( (S1&S3&(!S7))||(S1&S4&(!S7))||(S2&S4&(!S7)) )//遇到左直角

{

back();

delay(5);


turn_left();

delay(5);

while( (S1&S3&(!S7))||(S1&S4&(!S7))||(S2&S4&(!S7)) )

turn_left();

//delay(50);

}


if( (S5&S7&(!S1))||(S4&S7&(!S1))||(S4&S6&(!S1)) )//遇到右直角

{

back();

delay(5);

turn_right();

delay(5);

while( (S5&S7&(!S1))||(S4&S7&(!S1))||(S4&S6&(!S1)) )

turn_right();

//delay(50);


}





if((!S1)&(!S2)&S4&(!S6)&(!S7))

{


_nop_();

_nop_();

_nop_();

_nop_();





if(S3&S4&S5)//避免死循环

{

back();

delay(20);

if(S3&S4)

{

turn_left();

delay(5);

}

if(S4&S5)

{

turn_right();

delay(5);

}



}


else

straight();


}//全速速前行




if(!(S4|S5|S6|S7))

{


_nop_();

_nop_();

_nop_();


if((!S1)&S3)

correct_left(); //校正


if( ((!S3)&S2)||(S1&(!S3)) )

turn_left(); //左拐


if(S1&S2&S3)//遇到左直角

{

back();

delay(5);

while(S1&S2&S3)

turn_left();

delay(5);



}



}






if( !(S1|S2|S3|S4))

{




_nop_();

_nop_();

_nop_();

_nop_();


if(S5&(!S7))

correct_right();//校正



if( ( (!S5)&S6 )||((!S5)&S7) )

turn_right(); //右拐


if(S5&S6&S7)//遇到右直角

{

back();

delay(5);

while(S5&S6&S7)

turn_right();

delay(5);



}




}

}


/****************************************************************************************************

避障模块儿

*****************************************************************************************************/


void Rback()

{


RH=0;

RL=1;

LH=0;

LL=0;

}

void Lback()

{


RH=0;

RL=0;

LH=0;

LL=1;

}

void mainbizhang()

{



if((!LLT)&MLT&(!RLT))//010

{

Rback();

delay(20);

}

if((LLT)&(!MLT)&(!RLT))//100

turn_left();


if((!LLT)&(!MLT)&(RLT))//001

turn_right();


if((!LLT)&(!MLT)&(!RLT))//000

{

Rback();

delay(15);

}




if((!LLT)&(MLT)&(RLT))//011

turn_right();


if((LLT)&(!MLT)&(RLT))//101

turn_left();


if((LLT)&(MLT)&(!RLT))//110

turn_left();


if((LLT)&(MLT)&(RLT))//111

straight();




}


/*****************************************************************************************************

测速显示子程序

*****************************************************************************************************/

//=====================================================================================

//延时程序

//=====================================================================================

void Delay5Ms()

{

unsigned long int TempCyc = 5000;

while(TempCyc--);

}





uchar ReadStatusLCM()


{


char i;

uchar busy;

LCM_RS = 0;

LCM_RW = 1;

LCM_E = 1;

for(i=0;i<100;i++);

busy=(P0&0x80);

LCM_E = 0;

return(busy);

}



//=====================================================================================

//读写子程序

//=====================================================================================


//读数据

unsigned char ReadDataLCM()

{

while (ReadStatusLCM());


LCM_RS = 1;

LCM_RW = 1;

LCM_E = 1;

return(LCM_Data);

}


//读状态


//写数据

void WriteDataLCM(unsigned char WDLCM)

{char i;

while (ReadStatusLCM());


LCM_Data = WDLCM;

LCM_RS = 1;

LCM_RW = 0;

LCM_E=0;

LCM_E = 1;

若晶振速度太高可以在这后加小的延时

for(i=0;i<100;i++);//延时

LCM_E =0;

}


//写指令

void WriteCommandLCM(unsigned char WCLCM,BuysC) //BuysC为0时忽略忙检测

{

char i;

while(ReadStatusLCM());

LCM_Data = WCLCM;

LCM_RS = 0;

LCM_RW = 0;

LCM_E = 0;

LCM_E = 1;

for(i=0;i<100;i++);

LCM_E = 0;


}


//=====================================================================================

//初始化子程序

//=====================================================================================


void LCMInit(void) //LCM初始化

{


LCM_Data = 0;

WriteCommandLCM(0x38,0); // 三次显示模式设置,不检测忙信号

Delay5Ms();

WriteCommandLCM(0x38,0);

Delay5Ms();

WriteCommandLCM(0x38,0);

Delay5Ms();

WriteCommandLCM(0x38,1); // 显示模式设置,开始要求每次检测忙信号

Delay5Ms();

WriteCommandLCM(0x08,1); // 关闭显示

Delay5Ms();

WriteCommandLCM(0x01,1); // 清屏

Delay5Ms();

WriteCommandLCM(0x06,1); // 显示光标移动设置

Delay5Ms();

WriteCommandLCM(0x0c,1); // 显示开及光标设置

Delay5Ms();

}



//=====================================================================================

//按指定位置显示一个字符

//=====================================================================================


void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData)

{

Y &= 0x1;

X &= 0xF; //限制X不能大于15,Y不能大于1

if (Y) X |= 0x40; //当要显示第二行时地址码+0x40;

X |= 0x80;

算出指令码

WriteCommandLCM(X, Y); //这里不检测忙信号,发送地址码

WriteDataLCM(DData);

}


//=====================================================================================

//按指定位置显示一串字符

//void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData)

//说明: x(0-15):x参数 y(0-1):y参数 DData(字符串):要显示的内容(英文、数字、符号)

//=====================================================================================


void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData)

{

unsigned char ListLength,j;

ListLength = strlen(DData);

Y &= 0x1;

限制X不能大于15,Y不能大于1

坐标应小于0xF

{

for(j=0;j<ListLength;j++)

{

显示单个字符

X++;

}

}

}


//=====================================================================================

//显示自定义字符

//void mychar(char xx,char yy,unsigned char *character,unsigned char saveto)

//说明:xx(0-15):为x参数.yy(0-1):y参数.character:要显示的字符的列表地址,在程序前面有定义

//saveto(1-7)为字符保存的RAM,每屏最多显示7个自定义字符

//(0x00-0x0h是自定义字符)

//=====================================================================================



//=====================================================================================

//主函数

//=====================================================================================

void mychar(char xx,char yy,unsigned char *character,unsigned char saveto)

{

unsigned char add = (saveto<<3) | 0x40;

临时变量,每一行的值

for(o=0;o<8;o++)


{

t=*(character+o);

WriteCommandLCM(add+o, 0);

WriteDataLCM(t);

}


显示字符

}//====




void main1602()

{


char m,n;

char k=0,l=1;


LCMInit();//1602初始化

delay(400);

for(m=0;m<2;m++)

for(n=0;n<3;n++,k++,l++)

{


mychar(n+13,m, character1[k],l);


}


// WriteCommandLCM(0x01,1); //清屏*/


DisplayListChar(0,0,"V=00.0m/s");

DisplayListChar(0,1,"S=000.0m");


}


/////////////////////////////////////////////////////////////////////////////


void refresh()//刷新屏幕

{




//SU=(TH1*256+TL1)/1000;

SU=(TH1*256+TL1)/100;


if(SU!=0)

V=(TH1*256+TL1)/10-SU3;

//if()

//V=SU*10/C3;

SU3=(TH1*256+TL1)/10;

SU0=SU%10;

SU1=(SU%100)/10;

SU2=SU/100;

V0=(V)%10;

V1=(V)/10;

SU0=SU0|0x30;;

SU1=SU1|0x30;

SU2=SU2|0x30;

V0=V0|0x30;

V1=V1|0x30;






DisplayOneChar(2,0,V1);

DisplayOneChar(3,0,V0);

DisplayOneChar(3,1,SU2);

DisplayOneChar(4,1,SU1);

DisplayOneChar(6,1,SU0);


}

void averrage()

{


V=SU/C3;

V0=(V)%10;

V1=(V)/10;

V0=V0|0x30;

V1=V1|0x30;

DisplayOneChar(2,0,V1);

DisplayOneChar(3,0,V0);




}



/*********************************************************************************************

1602测速模块儿子程序

***************************************************************************************************/



/******************************************************

*名 称:void begin()

*功 能:初始化

*入口参数:无

*出口参数:无

*说 明: 初始化各个参数

*******************************************************/



void begin()

{


key1=1;key2=1;

key3=1;key4=1;

TMOD=0X52;


TH1=0; /* 装入定时器的初值,计数100次溢出 */

TL1=0;

TH0=0x9B; /* 装入定时器的初值,计数100次溢出 */

TL0=0x9B; /*装入时间常数*/


EA=1; /* 开中断 */

ET1=1;

ET0=1;/* 定时器1允许中断 */

ET2=1;

TR2=1;

TR1=1; /* 启动定时器1 */


/* 定时器0允许中断 */

TR0=1;

RCAP2H=(65536-10000)/256;

RCAP2L=(65536-10000)%256;


LH=0;

LL=0;

RH=0;

RL=0;

ENA=0;

ENB=0;



}

/******void scan()

{

if(!key1)

{

delay(15);

if(!key1)

// while(1)

// {

//begin();//初始化

//main1602();


do{turn();

} while(key1&key2&key3&key4);


// }


}



if(!key2)

{

delay(15);

if(!key2)

//while(1)

//{

//begin();//初始化

//main1602();


do{mainbizhang();

}while(key1&key2&key3&key4);

//}

}


if(!key3)

{

delay(15);

if(!key3)


//{

// ET0=0;

// ET1=0;

do{averrage();

}while(key1&key2&key3&key4);

// }


}

if(!key4)

{

delay(15);

if(!key4)

// {

do{stop();

}while(key1&key2&key3&key4);


// ET0=0;

// ET1=0;

//}

}

}*/


/******************************************************

* 名 称:void timer0() interrupt 1

* 功 能: T0中断服务程序

* 入口参数:无

* 出口参数:无

*******************************************************/





void timer1() interrupt 5

{

TF2=0;

C2++;

if((C2%100)==0)

{

C3++;//每秒刷新一次

refresh();

}

//scan();


}



void timer0() interrupt 1 /* T0中断服务程序 */


{




if(count==0)

{

SPEED1=tmp1;

SPEED2=tmp2;

}

if(count<SPEED1) ENA=1;

else ENA=0; /* 产生电机1的PWM信号 */


if(count<SPEED2) ENB=1;


else ENB=0; /* 产生电机2的PWM信号 */


count++;

if(count>=T) count=0; /* 1个PWM信号由100次中断产生 */

}


void count0() interrupt 3

{

TH1=0/256; /* 装入定时器的初值,计数100次溢出 */

TL1=0%256; /*装入时间常数*/


C1++;

//s=x96000/48/4*3*13/2


}




void main()

{


begin();//初始化

main1602();//显示模块儿初始化

while(1)

{

if(key1==0)

{delay(1);

if(key1==0)


do turn();while(key1&key2&key3&key4);}

if(key2==0)

{

delay(1);

if(key2==0)


do mainbizhang();

while(key1&key2&key3&key4);

}

if(key3==0)

{

delay(1);

if(key3==0)


do averrage();while(key1&key2&key3&key4);

}

if(key4==0)

{

delay(1);

if(key3==0)



do stop();

while(key1&key2&key3&key4);

}



}


}​

举报

相关推荐

0 条评论