单片机交流
直播中

1652711011.026500

16年用户 11294经验值
私信 关注
[问答]

如何利用C51单片机实现循迹灭火机器人的设计?

如何利用C51单片机实现循迹灭火机器人的设计?

回帖(1)

李桂芝

2021-11-1 11:54:07
一、作品摘要

       本设计由电机驱动模块、红外循迹模块、火焰识别模块、灭火模块以及MCU 控制模块五大部分构成。本设计采用深圳宏晶科技有限公司的STC89C52RC单片机作为小车的控制核心,实现对各个模块的通讯和控制。循迹部分由集成式红外探头组成,将采集到的数据处理后反馈至单片机。寻火部分由火焰传感器模块组成。灭火部分由升压威廉希尔官方网站 和风扇组成。电机由以L298N为核心部件的威廉希尔官方网站 驱动。该小车具有按照指定的轨迹巡线,发现火源进行灭火的功能。基于稳定的硬件威廉希尔官方网站 设计以及精确可靠的软件算法,小车能够实现预期功能。
二、系统设计步骤

(1)根据设计要求,确定控制方案;
(2)将各个模块进行组装并进行简单调试;
(3)画出程序流程图,使用C语言进行编程;
(4)将程序烧录到单片机内;
(5)进行调试以实现控制功能。

三、方案设计

3.1   小车主体设计

3.1.1   购买玩具小车进行改装

       采用玩具小车来改装,加入自己的控制系统即可,这样的优势是,省去了制作车体的功夫。另外小车主体布局也比较合理,可以较好地完成任务。
3.1.2   自己设计小车主体结构

       自己设计制造小车主体结构,能够按照布局设计思路来完成小车主体结构的调整,保证威廉希尔官方网站 部分和机械部分的全面协,可以合理地安放传感器。但是自己设计的小车难免会外表粗糙,费时费力。
       综合考虑各种利弊,兼顾小车制作周期问题,选择了购买小车主体结构,从而缩短小车的制作周期。

3.2   电机驱动模块

       鉴于价格和功能的考虑,我们选择了直流电机,通过PWM控制小车的速度以及方向。电机驱动部分有以下两种方案:
3.2.1   使用MOSFET构成H桥式驱动威廉希尔官方网站

       利用PWM波形来控制小车的速度,再用单片机两个I/O口控制电机旋转方向,此威廉希尔官方网站 驱动功率比较大,小车的转速比较快。
3.2.2   使用直流电机驱动芯片L298N

       L298N作为集成芯片,一块芯片能够输出两路PWM波形,控制两个电机,而且还带有控制使能端。用该芯片作为电机驱动,操作方便,稳定性好,性能优良。相对于由MOSFET构成的H桥式驱动威廉希尔官方网站 来说具有威廉希尔官方网站 焊接简单,焊接完成后不易出差错的优点。二者价格上差别不大,所以我们优先选择了方案(2)。

3.3   红外循迹模块

       每一路的传感器的红外发射管不断发射红外线,当发射出的红外线没有被反射回来或被反射回来但强度不够大时,红外接收管一直处于关断状态,此时模块的TTL输出端为高电平,相应指示二极管一直处于熄灭状态;当被检测物体出现在检测范围内时,红外线被反射回来且强度足够大,红外接收管导通,此时模块的TTL输出端为低电平,指示二极管被点亮。黑线检测威廉希尔官方网站 ,可以将红外探头放在车的底盘上,这样检测比较精准。在连接威廉希尔官方网站 时,要做成可以调节探测距离的威廉希尔官方网站 ,完成之后调节传感器使得小车能够准确探测到黑线,从而做出正确的动作。
       鉴于各种循迹模块均大同小异,选择采用性价比较高的FC-123红外循迹传感器。

3.4   火焰识别模块

       火焰检测有温度传感器、烟雾传感器、红外传感器、紫外传感器以及CCD传感器。综合论证这几种传感器,因本设计使用蜡烛模拟火源,对环境温度影响小,烟雾少,排除了温度传感器、烟雾传感器。考虑到易用性,排除了CCD传感器,从而主要考虑以下两种方案。
3.4.1   使用紫外传感器识别火焰

       紫外线传感器只对185~260NM狭窄范围内的紫外线进行响应,而对其它频谱范围的光线不敏感,利用它可以对火焰中的紫外线进行检测。具有灵敏度高,检测及时准确、抗干扰性强的特点。主要缺点是价格是红外传感器的8-10倍。
3.4.2   使用红外传感器识别火焰

       红外火焰传感器可以用来探测火源或其它一些波长在700纳米~1000纳米范围内的热源。利用它可以对燃烧时发出大量红外光进行检测。价格低廉,但是容易受到外界光的干扰。综合考虑,采用红外传感器识别火焰,并采取相应措施排除干扰。
       综合考虑各种因素,兼顾火焰识别模块的成本问题,选择用红外传感器识别火焰。

3.5    灭火模块

3.5.1   用水灭火

       水可以很好的将蜡烛浇灭。但是不管是挤压喷水还是使用水泵喷水,在喷水的远近和广度难以控制,并且使用大电流电机对电源的冲击相当大,难以保证系统的稳定性。
3.5.2   用风扇灭火

       虽然风能助长火势,但是在火源比较小的情况下,风将可燃物的温度降到燃点之下,实现灭火。
       采用风扇已经可以满足模拟灭火需求,而且选用风扇在硬件制作和软件编程上更简单、更容易操控。

3.6    灭火模块

       电源部分,可以使用几节5号电池串联,但是这样电池使用效率比较低,而且5号电池功率不够大,容量也太小,不能长时间供电,最后决定使用4节锂电池(3.7V 18650锂电池串联而成),为电机和风扇供电,再利用降压模块来产生5V的直流电压,为威廉希尔官方网站 中的各个芯片提供正常工作电压。

四、机器人的设计与组成

4.1    1路循迹模块

       TCRT5000传感器的红外发射二极管不断发射红外线,当发射出的红外线没有被反射回来或被反射回来但强度不够大时,红外接收管一直处于关断状态,此时模块的输出端为低电平,指示二极管一直处于熄灭状态;被检测物体出现在检测范围内时,红外线被反射回来且强度足够大,红外接收管饱和,此时模块的输出端为高电平,指示二极管被点亮。
  

       火焰传感器对太阳光有反应,并且对火焰光特别敏感。可检测一定范围内的光源,探测角度为60度左右,可用于火焰预警、火焰识别。
       公共端、常闭、常开三个端口相当于一个双控开关。继电器线圈有电时,公共端与常开端导通;无电时,公共端与常闭端导通。
       可以通过调节电位器来设定传感器对火焰感应的强度。当火焰超过阀定值,继电器吸合,公共端与常开端导通;当火焰低于阀定值,继电器断开,公共端与常闭端导通。
  

       L298N作为集成芯片,一块芯片能够输出两路PWM波形,控制两个电机,而且还带有控制使能端。用该芯片作为电机驱动,操作方便,稳定性好,性能优良。
       具备大容量滤波电容,续流保护二极管,可以提高可靠性。
       采用标准逻辑电平信号控制;具有两个使能控制端,在不受输入信号影响的情况下允许或禁止器件工作有一个逻辑电源输入端,使内部逻辑威廉希尔官方网站 部分在低电压下工作。
  
       主要是由外壳、威廉希尔官方网站 板、驱动马达、减速器与位置检测元件所构成,如滚转运动等都是靠舵机相互配合完成的。转动角度:0-180°。
  
       采用8cm×8cm规格的风机,以简单的风机转动,达到利用空气熄灭蜡烛火焰的效果。转速参考:4000±10%RPM,噪音参考:18DB,风量参考:18.17-25.97CFM。
  

       具备了DC取电口/ISP下载口/RS232串口/USB转串口等这几个必需的实验接口;8路LED灯,红外线接收头可用于红外遥控解码;已集成USB转串口威廉希尔官方网站 ,可用一根USB线就可完成下载烧写及供电,即可当STC编程器使用。具备51/AVR双复位威廉希尔官方网站 ,以及18B20单总线温度传感器接口。
  
       这是由手工焊制而成的直流继电器模块,可以控制并驱动12V直流风机。
       特点:1.采用松乐—继电器控制;2.信号输入端有低电平信号时,公共端和常开端会导通;3.继电器可以直接控制各种设备和负载;4.有一个常开和一个常闭触点。
  

图4.7   直流继电器  
五、编程思路

  



图5.0.1   程序控制示意图 5.1    循迹部分

       循迹主要解决以下几种情况:(左右情况刚好相反,现以其中一种情况为例介绍说明)

         



图1  情况一     
         



图2  情况二   
         



图3  情况三   
5.2    火焰识别部分

       因为火源位于轨迹两侧,所以火焰识别模块只需布置在小车两侧即可满足寻火。同时在每一侧各布置3个并排的火焰识别模块,这样可以提高小车灭火的容错性,从而达到 灭火要求。
  



图5.2.1   火焰识别部分结构示意图 5.3    灭火部分

       舵机安装在红色部分的位置,当任意一侧的任一个或多个火焰识别模块检测到火源时,舵机会根据信号反馈转向检测到的方向,同时继电器常开端吸合,风机打开,开始灭火。当火源被扑灭后,由于火焰识别模块未检测到火源,继电器常开端断开,风机停止工作,舵机复位,小车继续循迹。
  



图5.3.1   灭火部分结构示意图 六、程序

6.1    循迹灭火机器人.c

#include
#include
#define uint unsigned int
#define uchar unsigned char


//火焰识别模块输入I/O口
***it relay1=P2^0;
***it relay2=P2^1;
***it relay3=P2^2;
***it relay4=P2^3;
***it relay5=P2^4;
***it relay6=P2^5;


***it fan=P2^7;//风扇+继电器信号端
***it duoji=P2^6;//舵机信号端


//定义小车驱动模块输入IO口
***it EN1=P0^5;
***it IN1=P0^1;
***it IN2=P0^2;
***it IN3=P0^3;
***it IN4=P0^4;
***it EN2=P0^0;


#define Left_1_led        P1_3         // 左传感器
#define Left_2_led        P1_2         // 左传感器        
#define Right_2_led       P1_0         //右传感器
#define Right_1_led       P1_1         //右传感器

#define Left_moto_pwm          P0_5         //PWM信号端
#define Right_moto_pwm          P0_0          //PWM信号端

#define Left_moto_go      {IN1=0,IN2=1;}    //左电机向前走
#define Left_moto_back    {IN1=1,IN2=0;}         //左边电机向后转
#define Left_moto_Stop    {EN2=0;}          //左边电机停转                     
#define Right_moto_go     {IN3=0,IN4=1;}        //右边电机向前走
#define Right_moto_back   {IN3=1,IN4=0;}        //右边电机向后走
#define Right_moto_Stop   {EN1=0;}               //右边电机停转  


uchar pwm_val_left  =0;//变量定义
uchar push_val_left =0;//左电机占空比N/20
uchar pwm_val_right =0;
uchar push_val_right=0;//右电机占空比N/20


bit Right_moto_stop=1;
bit Left_moto_stop =1;
uint time=0;
   
/************************************************************************/       
//延时函数       
void delay(uint k)
{   
        uint x,y;
        for(x=0;x                 for(y=0;y<2000;y++);
}


/************************************************************************/
//前速前进
void  run(void)
{
        push_val_left=3.5;         //速度调节变量 0-20。。。0最小,20最大
        push_val_right=3.5;
        Left_moto_go ;   //左电机往前走
        Right_moto_go ;  //右电机往前走
        delay(1);       
}


//后退函数
void  backrun(void)
{
        push_val_left=3.5;         //速度调节变量 0-20。。。0最小,20最大
        push_val_right=3.5;
        Left_moto_back;   //左电机往前走
        Right_moto_back;  //右电机往前走
}


//左转
void  leftrun(void)
{         
//        push_val_left=5;
        push_val_right=3.5;
        Right_moto_go ;  //右电机往前走
        Left_moto_Stop ;  //左电机停止
}


void  leftrun1(void)
{         
//        push_val_left=5;
        push_val_right=4;
        Right_moto_go ;  //右电机往前走
        Left_moto_Stop ;  //左电机停止
}


void  leftrun2(void)
{         
//        push_val_left=5;
        push_val_right=5;
        Right_moto_go ;  //右电机往前走
        Left_moto_Stop ;  //左电机停止
}


void  leftrun3(void)
{         
//        push_val_left=5;
        push_val_right=5.5;
        Right_moto_go ;  //右电机往前走
        Left_moto_Stop ;  //左电机停止
}


//右转
void  rightrun(void)
{
        push_val_left=3.5;
//        push_val_right=6;
        Left_moto_go  ;   //左电机往前走
        Right_moto_Stop   ;  //右电机       
}


void  rightrun1(void)
{
        push_val_left=4;
//        push_val_right=6;
        Left_moto_go;   //左电机往前走
        Right_moto_Stop;  //右电机       
}


void  rightrun2(void)
{
        push_val_left=5;
//        push_val_right=6;
        Left_moto_go  ;   //左电机往前走
        Right_moto_Stop   ;  //右电机       
}


void  rightrun3(void)
{
        push_val_left=5.5;
//        push_val_right=6;
        Left_moto_go  ;   //左电机往前走
        Right_moto_Stop;  //右电机       
}


//停止函数
void  stop(void)
{
        fan=0;               
        Right_moto_Stop;  //右电机
        Left_moto_Stop;  //左电机停止       
}


/************************************************************************/
/*                    PWM调制电机转速                                   */
/************************************************************************/
/*                    左电机调速                                        */
/*调节push_val_left的值改变电机转速,占空比            */
void pwm_out_left_moto(void)
{  
   if(Left_moto_stop)
   {
    if(pwm_val_left<=push_val_left)
               {
                     Left_moto_pwm=1;
//                     Left_moto_pwm1=1;
                   }
        else
               {
                 Left_moto_pwm=0;
//                     Left_moto_pwm1=0;
                   }
        if(pwm_val_left>=20)
               pwm_val_left=0;
   }
   else   
          {
                        Left_moto_pwm=0;
//          eft_moto_pwm1=0;
                  }
}




void xunji()//循迹函数
{
        fan=1;
                                  //有信号为0  没有信号为1
        if(Left_1_led==1&&Left_2_led==1&&Right_2_led==1&&Right_1_led==1)                        //检测信号1111
                run();         //调用前进函数
        else
        {                          
            if(Left_1_led==1&&Left_2_led==0&&Right_2_led==0&&Right_1_led==1)                //检测信号1001
                        run();      //调用前进函数


                if(Left_1_led==1&&Left_2_led==1&&Right_2_led==0&&Right_1_led==1)            //右边检测到红外信号1101
                        rightrun();             //调用小车右转函数


                if(Left_1_led==1&&Left_2_led==1&&Right_2_led==0&&Right_1_led==0)            //右边检测到红外信号1100
                        rightrun1();         //调用小车右转函数1


                if(Left_1_led==1&&Left_2_led==1&&Right_2_led==1&&Right_1_led==0)            //右边检测到红外信号1110
                        rightrun2();     //调用小车右转函数2


                if(Left_1_led==1&&Left_2_led==0&&Right_2_led==0&&Right_1_led==0)            //右边检测到红外信号1000
                        rightrun3();         //调用小车右转函数3
       
                 if(Left_1_led==1&&Left_2_led==0&&Right_2_led==1&&Right_1_led==1)                //左边检测到红外信号1011          
                        leftrun();             //调用小车左转函数


                 if(Left_1_led==0&&Left_2_led==0&&Right_2_led==1&&Right_1_led==1)                //左边检测到红外信号0011          
                        leftrun1();             //调用小车左转函数1


                 if(Left_1_led==0&&Left_2_led==1&&Right_2_led==1&&Right_1_led==1)                //左边检测到红外信号0111          
                        leftrun2();             //调用小车左转函数2


                 if(Left_1_led==0&&Left_2_led==0&&Right_2_led==0&&Right_1_led==1)                //左边检测到红外信号0001          
                        leftrun3();             //调用小车左转函数3


            if(Left_1_led==0&&Left_2_led==0&&Right_2_led==0&&Right_1_led==0)                //检测信号0000       
                        stop();          //调用小车停止函数
                        //run();         //调用前进函数
        }         
}


void xunhuo()//灭火函数
{
        if(relay1==0||relay2==0||relay3==0||relay4==0||relay5==0||relay6==0)
        {
                djmain();
                if(relay1==0||relay2==0||relay3==0){angle=9; }
                if(relay4==0||relay5==0||relay6==0){angle=3; }
                stop();
                TR1=0;
        }
        else
        {       
                angle=6;       
                xunji();
       
        }
}


void init()
{
        fan=1;
        TMOD=0X01;
        TH0= 0XFc;                  //1ms定时
        TL0= 0X18;
        TR0= 1;
        ET0= 1;
        EA = 1;                     //开总中断
}


/******************************************************************/
/*                    右电机调速                                  */  
void pwm_out_right_moto(void)
{
        if(Right_moto_stop)
    {
    if(pwm_val_right<=push_val_right)
              {
               Right_moto_pwm=1;
//                   Right_moto_pwm1=1;
                   }
        else
              {
                   Right_moto_pwm=0;
//                   Right_moto_pwm1=0;
                  }
        if(pwm_val_right>=20)
               pwm_val_right=0;
   }
   else   
          {
             Right_moto_pwm=0;
//           Right_moto_pwm1=0;
              }
}
      
/***************************************************/
///*TIMER0中断服务子函数产生PWM信号*/
void timer0()interrupt 1   using 2
{
     TH0=0XFc;          //1Ms定时
         TL0=0X18;
         time++;
         pwm_val_left++;
         pwm_val_right++;
         pwm_out_left_moto();
         pwm_out_right_moto();
}


void main()//主函数
{       
        init();
        while(1)        //无限循环
        {
                xunhuo();         
        }
}                                                                          
#include
#define uint unsigned int
#define uchar unsigned char


***it dj=P3^6;         //与舵机相连的信号口
uchar djpwm;                //舵机的pwm
uchar angle=6;        //控制舵机角度的变量,默认为45度,范围2到10,对应0到180度


//***********************************************************************************//
       
/*        void djdelay(uint z)
        {
            uint x,y;
            for(x=z;x>0;x--)
                    for(y=110;y>0;y--);
        }*/




void Timer1_Init(void)
{
        TMOD=0x20;
        TH1=6;        //设定为0.25触发一次定时器中断
        TL1=6;
        ET1=1;
        EA=1;
        TR1=1;
}


//主函数
void djmain()
{
        Timer1_Init();        //定时器一中断初始化      
       
}
//***********************************************************************************//
//定时器1中断
void Time1_Isr() interrupt 3
{
        djpwm++;        //判断自加
        if(djpwm==angle)        //与角度变量比较
        {
                dj=0;        //接舵机IO置0
        }
        if(djpwm==80)        //0.25*80=20ms???
        {
                djpwm=0;        //清零
                dj=1;        //接舵机IO置一
        }
}
举报

更多回帖

发帖
×
20
完善资料,
赚取积分