基于51单片机的循迹,避障小车

摘要

课题基于51单片机的开发指南,主要包含了小车机械结构、电路板的电控部分、程序编写设计、具体场地调试等几个方面。较为成功地完成了小车指定路线的循迹工作,以及以避障为主的几项拓展内容。

基于课题设计的视角,该课题是嵌入式系统实践的一个入门项目,在完成项目的过程中,我们能清楚地把握机械、电控、软件等三方面的缺一不可和协调性,大大开拓了我们的视野,同时也增加了我们的项目经验。在自学的过程中,一方面提高了个人对不同学科领域的交叉融合学习,另一方面也增强了自学能力。

1.PWM原理解释

1.1PWM的含义及相关名词

首先我们先来了解一下PWM的含义,PWM称为脉冲宽度调制技术,所谓脉冲,可以联想一下心电图或者是脉搏跳动式的短暂起伏的电压或电流。而宽度调制,就可以联想到对应的图像。

1.2PWM的相关名词

占空比:指高电平在一个周期中所占的比例。简单来说,拿上图作为示范,可以理解为高电平时间与总脉冲时间的比值,或上图的可变脉冲宽度和恒定脉冲周期的比值。

而第二种理解方法的由来,我们可以借助PWM的图解来进行理解。

1.3PWM的理解简图

如图,图中共有三条横线,从上往下可以依此理解为PWM的最大值,PWM的设定值,PWM 的最小值。而我们的单片机是属于数字输出的类型,因此我们可以规定,在设定值以下部分,从PWM的最小值开始向上计算,每计算一次,输出一次0的数字型号。直到斜线与设定值直线交点为止;同理,设定值以上的部分,每计算一次,输出一次1的数字型号,直到斜线和最大值的交点为止。

  可能有同学会问,之类的计算指的是什么。这里的计算指的是每一个值与设定值进行大小比较的这一个过程。

  举个例子,假设min=0,set=10,max=100。

则过程为:0<10,输出0信号;1<10,输出0信号,2<10,输出0信号,以此类推11>10,输出1信号以此类推。而这里可以不需要考虑10和set的比较。

1.4PWM设定值,最小值,最大值的作用

  结合图像可以理解,最小值和最大值决定斜线的上限和下限,说的通俗一点,就是这个斜线向左下和右上的延伸长度,也就是所说的恒定的脉冲周期。而设定值则是调整占空比的关键,也是小车调速的关键因素,也就是说,占空比决定了整个图像。

  注意:斜线的斜率是随意的,思考PWM的相关元素与斜率的关系并没有太大的意义。

1.5服务中断函数

  注:此部分为循迹小车调速的最核心部分

  有些同学可能只知道PWM需要用到服务中断函数,但是不知道它的含义和作用到底是什么,下面将一一论述。

  首先,我们要了解中断的含义,我们借助书上的图解

可以看出,主程序在进行的过程中,遇到了一个优先级较高的另一个程序部分,而这一程序部分就是服务中断函数里的程序内容,此时就需要把原有的主程序进行过程给中断,去执行服务中断函数内的内容。

  还有一个问题,在服务中断函数中有TH和TL值的设定这一过程,书上默认是采用16进制的格式,这其实是换算过后的结果。

我们的晶振为12MHz,因此计算较为方便。之类的N可以表示为一种特殊的延时时间,因此,可以理解为每隔这么长的时间,执行服务中断函数内的内容。

2. 项目技术方案

总体设计方案

2.1机械结构设计:

(1)主要外形:考虑到两个橡皮轮和万向轮形成的三角形结构首选矩形底板,其次考虑到小车底板的成本问题,因此将前端设计成半圆型。  

(2)小车层数:通过对几块主要电路板的尺寸测量,为了较为方便地安装、更换电池、控制开关,设计为两层结构。

(3)载重考虑:考虑到小车后端只有一个万向轮,按照传统方案设计,在小车转向时,由于传感器过于灵敏,可能会导致小车出现颠簸的情况,因此将主控板和电源驱动板设计在小车后端,增加后端重量。

(4)拓展考虑:考虑到后期可能会增加一些拓展功能,因此将小车结构设计得较大。

2.2电控设计:

电控设计主要体现在接线上,通过对电路原理图的学习,并在纸上大致画了各个接口的接线,最终在安装过程中,通过调整电路板的朝向,使得接线较为便利,尽可能避免使用杜邦线延长接线的情况。并且尽可能将线都安排啊在中间层,以使得小车整体较为美观。

3.3软件设计:

(1)前置工作:首先明确项目的主要目标为循迹的完成,其次将其分解为各个小问题,如电机转速、方向控制、传感器判断的各个情况等。

(2)在程序的设计和编写过程中,应当尽可能考虑到所有可能出现的情况。同时,注重将理论转为实际的过程。

(3)问题解决:当遇到实际与预期不符合,优先考虑算法问题,考虑是否存在功能冲突的情况。   

3.详细设计方案

3.1机械设计方案     

(1)如图1所示,是循迹小车第二层的设计方案,主要用于安装主控板、电源驱动板、蜂鸣器、显示器连接。设计为两层主要有两个方面原因:一个是考虑到电路板,电池盒的尺寸都较大,设计为两层结构可以更方便的安排各个电路板的位置;另一个方面是为了后续可以更好的增加拓展部分。

(2)如图2所示,是循迹小车第一层的设计方案,主要安装超声波云台、舵机、超声波传感器、电机驱动板、电池盒;万象被安装在底板的背面。

(3)如图3所示,是电机与底板的连接装置,设计为L型主要是根据三角形的稳定性,可以考虑通过增加加强筋的方式进行稳固。

(5)载重考虑:由于两个前轮和万向轮形成三角形的结构,且重量主要集中在中部,导致整个车的重心位于两层中间位置,不会出现由于速度过快导致的颠簸问题。

(6)设计考虑:考虑到更加方便调节循迹红外线传感器灵敏度这一因素,将前度底板高度设计较高。

(7)优点分析:由于循迹红外线传感器的灵敏度调节不太好把控,因此对灵敏度调节方法进行了改善。将原来的用尼龙柱固定高度转换为长螺丝搭配螺母的方法,最大程度上改善了灵敏度调节不方便的问题。将改变电阻调节灵敏度转换为调节红外线发射部分离地距离。

3.2电控设计方案

(1)如图1所示,为循迹红外传感器的原理图,主要电子元件为光耦和比较器,当检测到黑线时,光耦未被触发,电压为5v状态进入比较器,发光二极管不发光;当检测到白色部分时反之。

(2)如图2所示,为电机驱动板原理图,主要元件为L298N芯片,可以看见配有IN1-4、OUT1-4、ENA和ENB接口,主要用于控制电机的转向,EN接口用于控制电机的开关。左侧为6个主要由光耦组成的部分,主要用于PWM波的控制。

(3)如图3所示,为电源驱动板,主要由AMS1117-5.0芯片组成,用于控制电源的开关和稳定电压输出为5v的作用。当开关闭合时,两个发光二极管会同时发光。

3.3单片机程序设计方案

首先声明:此次项目设计使用的是KEIL2软件,此后会逐渐学习KEIL5的使用。

·红外循迹部分

首先规定一个全局变量count=0,用于计数。声明左右传感器分别为left_sensor, right_sensor。当检测到黑线时,传感器输出高电平,当检测到白线时,传感器输出低电平。之后立刻开始判断,如果两个传感器都是低电平,则为前进,否则进行下一个判断;当左传感器为高电平,右传感器为低电平,则小车偏左,进行右转,否则进行下一个判断;当左传感器为低电平,右传感器为高电平,则小车偏右,进行左转,否则进入下一个判断。当左右传感器都为低电平,则检测到了十字路口,先进行count+1,之后前进,接着再次判断,如果count值为12,则返回count+1,进行循环,直到count值不为12,小车停止。执行完毕后返回初始检测部分

//头文件
#include<reg52.h>
#include<intrins.h>
//宏定义
#define uint unsigned int
#define uchar unsigned char
#define ulong unsigned long
//全局变量
uint i,j,time_ms,time;		
uint dis;
ulong dis_time;

uchar pwm_left_front_low=0;
uchar pwm_left_front_set=0;
uchar pwm_left_front_high=255;

uchar pwm_right_front_low=0;
uchar pwm_right_front_high=255;
uchar pwm_right_front_set=0;
//引脚声明
sbit Trig=P0^0;
sbit Echo=P0^1;

sbit IN1=P1^0;
sbit IN2=P1^1;
sbit ENA=P1^6;

sbit IN3=P1^3;
sbit IN4=P1^2;
sbit ENB=P1^7;

sbit Servo=P2^0;
sbit beep=P0^3; 
//函数声明
void InitTimer0();
void distance();

void pwm_left_front_print(); 	
void pwm_right_front_print();

void front();
void avoid();
void stop();

void delay_ms(time_ms);
void delay(time);
void delay100us();

void BEEP();
//主函数
void main()
{			
	InitTimer0();
	avoid();
}
//100微秒延时
void delay100us(void)   
{
    uchar a,b;
    for(b=1;b>0;b--)
        for(a=47;a>0;a--);
}
//距离计算函数
void distance()
{
		Trig = 0;//关闭发射端(初始化)
        Trig = 1;//开启
		delay100us();//延时100微秒(手册)
		Trig = 0;
		
		while(!Echo);
		TR1 = 1;
		while(Echo);
		TR1 = 0;
		
		dis_time = TH1 * 256 + TL1;
		dis = (dis_time * 1.7)/100;//距离计算
		/*初始化(方便下一次测距)*/
		TH1 = 0;
		TL1 = 0;
}
//定时器初始化
void InitTimer0()
{
TMOD = 0x11;//模式3
EA=1; //总中断
ET1=1;  
TR1=1;
TR0=1;
ET0=1;
TH1=0;
TL1=0;
TH0=(65536-75)/256;
TL0=(65536-75)%256;
}//服务中断函数
void T0_time() interrupt 1
{
    TH0=(65536-75)/256;
    TL0=(65536-75)%256;
    pwm_left_front_low++;
    pwm_right_front_low++;
    pwm_left_front_print();
    pwm_right_front_print();
}
//PWM输出
void pwm_left_front_print()
{
  if(pwm_left_front_low<=pwm_left_front_set)
  {
    ENA=0;
  }
  else 
  {
    ENA=1;
  }
  if(pwm_left_front_low>=pwm_left_front_high)
  {
    pwm_left_front_low=0;
  }
}

void pwm_right_front_print()
{
  if(pwm_right_front_low<=pwm_right_front_set)
  {
    ENB=0;
  }
  else 
  {
    ENB=1;
  }
  if(pwm_right_front_low>=pwm_right_front_high)
  {
    pwm_right_front_low=0;
  }
}
//前进和后退
void front()
{
  pwm_left_front_set=50;
  pwm_right_front_set=50;
  IN1=1;
  IN2=0;
  IN3=1;
  IN4=0;
}

void stop()
{
  IN1=0;
  IN2=0;
  IN3=0;
  IN4=0;	
}
//蜂鸣器
void BEEP()
{
	while(1)
	{
		beep=1;
	}	
}
//避障函数
void avoid()
{
	while(1)//无限循环
	{	
       distance();//不断获取距离
       if(dis<=100)
        {
            stop();
			BEEP();
		}
	
	    if(dis>100)
        {
			front();
		}
	}
}

·超声波测距部分

首先进行距离的测量:将超声波发射端关闭,进行初始化,再将其开启,给予一个大于10微秒的延时,然后再将其关闭,停止发射超声波。在距离测量前已经提前设置过定时器,这里就不在赘述。接着进行循环判断,当Echo0时,表示未接收到超声波,将Trig发射端打开,否则进行第二个循环判断;当Echo1时,表示检测到超声波,将Trig超声波发射端关闭,这两个循环判断是为了保证超声波接收端能够确实接收到超声波信号。随后进行从发射到接收的时间,以下简称为高电平时间。距离计算为高电平时间*声速/2,随后将TH1TL1都置0,完成定时器的初始化,为方便下一次的测距。至此,就完成了一次测距的过程。随后进行距离判断,当距离小于100时,执行停止和蜂鸣器报警的命令,否则执行前进。执行完毕后返回测距开始部分,进行下一次测距,进行循环。 

//头文件
#include<reg52.h>
#include<intrins.h>
//宏定义
#define uint unsigned int
#define uchar unsigned char
#define ulong unsigned long
//全局变量
uint i,j,time_ms,time;		
uint dis;
ulong dis_time;

uchar pwm_left_front_low=0;
uchar pwm_left_front_set=0;
uchar pwm_left_front_high=255;

uchar pwm_right_front_low=0;
uchar pwm_right_front_high=255;
uchar pwm_right_front_set=0;
//引脚声明
sbit Trig=P0^0;
sbit Echo=P0^1;

sbit IN1=P1^0;
sbit IN2=P1^1;
sbit ENA=P1^6;

sbit IN3=P1^3;
sbit IN4=P1^2;
sbit ENB=P1^7;

sbit Servo=P2^0;
sbit beep=P0^3; 
//函数声明
void InitTimer0();
void distance();

void pwm_left_front_print(); 	
void pwm_right_front_print();

void front();
void avoid();
void stop();

void delay_ms(time_ms);
void delay(time);
void delay100us();

void BEEP();
//主函数
void main()
{			
	InitTimer0();
	avoid();
}
//100微秒延时
void delay100us(void)   
{
    uchar a,b;
    for(b=1;b>0;b--)
        for(a=47;a>0;a--);
}
//距离计算函数
void distance()
{
		Trig = 0;//关闭发射端(初始化)
        Trig = 1;//开启
		delay100us();//延时100微秒(手册)
		Trig = 0;
		
		while(!Echo);
		TR1 = 1;
		while(Echo);
		TR1 = 0;
		
		dis_time = TH1 * 256 + TL1;
		dis = (dis_time * 1.7)/100;//距离计算
		/*初始化(方便下一次测距)*/
		TH1 = 0;
		TL1 = 0;
}
//定时器初始化
void InitTimer0()
{
TMOD = 0x11;//模式3
EA=1; //总中断
ET1=1;  
TR1=1;
TR0=1;
ET0=1;
TH1=0;
TL1=0;
TH0=(65536-75)/256;
TL0=(65536-75)%256;
}//服务中断函数
void T0_time() interrupt 1
{
    TH0=(65536-75)/256;
    TL0=(65536-75)%256;
    pwm_left_front_low++;
    pwm_right_front_low++;
    pwm_left_front_print();
    pwm_right_front_print();
}
//PWM输出
void pwm_left_front_print()
{
  if(pwm_left_front_low<=pwm_left_front_set)
  {
    ENA=0;
  }
  else 
  {
    ENA=1;
  }
  if(pwm_left_front_low>=pwm_left_front_high)
  {
    pwm_left_front_low=0;
  }
}

void pwm_right_front_print()
{
  if(pwm_right_front_low<=pwm_right_front_set)
  {
    ENB=0;
  }
  else 
  {
    ENB=1;
  }
  if(pwm_right_front_low>=pwm_right_front_high)
  {
    pwm_right_front_low=0;
  }
}
//前进和后退
void front()
{
  pwm_left_front_set=50;
  pwm_right_front_set=50;
  IN1=1;
  IN2=0;
  IN3=1;
  IN4=0;
}

void stop()
{
  IN1=0;
  IN2=0;
  IN3=0;
  IN4=0;	
}
//蜂鸣器
void BEEP()
{
	while(1)
	{
		beep=1;
	}	
}
//避障函数
void avoid()
{
	while(1)//无限循环
	{	
       distance();//不断获取距离
       if(dis<=100)
        {
            stop();
			BEEP();
		}
	
	    if(dis>100)
        {
			front();
		}
	}
}

4.成果展示

参考文献/参考资料

【1】3D effects box for bridging 3D scan and 3D print  Hiroya Tanaka  Yusuke  Tominaka  Atsushi Masumori  Taisuke Oshima  Keita Sekijima  Youka Watanabe  ACM

【2】Design and Simulation of Automatic Locking Cabinet Based On MCU Xiangyu Wang

IOPScience

【3】  基于51单片机的超声波避障小车(HC-SR04,SG90舵机)    CSDN 2022-09-28

【4】  课设-基于51单片机的智能小车(循迹+避障+APP控制) CSDN 2021-07-16

【5】 C#实现微秒(us)级延时  CSDN  2022-04-19

  • 15
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
单⽚机智能循迹避障⼩车 单⽚机智能循迹避障⼩车 可关注我们! 限时⼲货下载: 限时⼲货下载:关注我们"单⽚机",回复"教程"获取单⽚机电⼦书,回复"仿真"获取Proteus仿真资料。持续更新中。。。   第⼀章 绪 论   1.1智能⼩车的意义和作⽤   1.2智能⼩车的现状   第⼆章 ⽅案设计与论证   2.1 主控系统   2.2 电机驱动模块   2.3 循迹模块   2.4 避障模块   2.5 机械系统   2.6电源模块   第三章 硬件设计   3.1总体设计   3.2驱动电路   3.3信号检测模块   3.4主控电路   第四章 软件设计   4.1主程序模块   4.2电机驱动程序   4.3循迹模块   4.4避障模块   第五章 制作安装与调试 智能循迹避障⼩车 摘 要:利⽤红外对管检测⿊线与障碍物,并以STC89C52单⽚机为控制芯⽚控制电动⼩汽车的速度及转向,从⽽实现 ⾃动循迹避障的功能。其中⼩车驱动由L298N驱动电路完成,速度由单⽚机输出的PWM波控制。 关键词:智能⼩车;STC89C52单⽚机; L298N;红外对管 第⼀章 绪论 1.1智能⼩车的意义和作⽤ ⾃第⼀台⼯业机器⼈诞⽣以来,机器⼈的发展已经遍及机械、电⼦、冶⾦、交通、宇航、国防等领域。近年来机器⼈的 智能⽔平不断提⾼,并且迅速地改变着⼈们的⽣活⽅式。⼈们在不断探讨、改造、认识⾃然的过程中,制造能替代⼈劳 动的机器⼀直是⼈类的梦想。 随着科学技术的发展,机器⼈的感觉传感器种类越来越多,其中视觉传感器成为⾃动⾏⾛和驾驶的重要部件。视觉的典 型应⽤领域为⾃主式智能导航系统,对于视觉的各种技术⽽⾔图像处理技术已相当发达,⽽基于图像的理解技术还很落 后,机器视觉需要通过⼤量的运算也只能识别⼀些结构化环境简单的⽬标。视觉传感器的核⼼器件是摄像管或CCD,⽬ 前的CCD已能做到⾃动聚焦。 但CCD传感器的价格、体积和使⽤⽅式上并不占优势,因此在不要求清晰图像只需要粗略感觉的系统中考虑使⽤接近觉 传感器是⼀种实⽤有效的⽅法。 机器⼈要实现⾃动导引功能和避障功能就必须要感知导引线和障碍物,感知导引线相当给机器⼈⼀个视觉功能。避障控 制系统是基于⾃动导引⼩车(AVG—auto-guide vehicle)系统,基于它的智能⼩车实现⾃动识别路线,判断并⾃动避开 障碍,选择正确的⾏进路线。使⽤传感器感知路线和障碍并作出判断和相应的执⾏动作。 该智能⼩车可以作为机器⼈的典型代表。它可以分为三⼤组成部分:传感器检测部分、执⾏部分、CPU。机器⼈要实现 ⾃动避障功能,还可以扩展循迹等功能,感知导引线和障碍物。可以实现⼩车⾃动识别路线,选择正确的⾏进路线,并 检测到障碍物⾃动躲避。 基于上述要求,传感检测部分考虑到⼩车⼀般不需要感知清晰的图像,只要求粗略感知即可,所以可以舍弃昂贵的CCD 传感器⽽考虑使⽤价廉物美的红外反射式传感器来充当。智能⼩车的执⾏部分,是由直流电机来充当的,主要控制⼩车 的⾏进⽅向和速度。 单⽚机驱动直流电机⼀般有两种⽅案:第⼀,勿需占⽤单⽚机资源,直接选择有PWM功能的单⽚机,这样可以实现精确 调速;第⼆,可以由软件模拟PWM输出调制,需要占⽤单⽚机资源,难以精确调速,但单⽚机型号的选择余地较⼤。考 虑到实际情况,本⽂选择第⼆种⽅案。CPU使⽤STC89C52单⽚机,配合软件编程实现。 1.2智能⼩车的现状 现智能⼩车发展很快,从智能玩具到其它各⾏业都有实质成果。其基本可实现循迹、避障、检测贴⽚、寻光⼊库、避崖 等基本功能,这⼏节的电⼦设计⼤赛智能⼩车⼜在向声控系统发展。⽐较出名的飞思卡尔智能⼩车更是⾛在前列。我此 次的设计主要实现循迹避障这两个功能。 第⼆章 ⽅案设计与论证 根据要求,确定如下⽅案:在现有玩具电动车的基础上,加装光电检测器,实现对电动车的速度、位置、运⾏状况的实 时测量,并将测量数据传送⾄单⽚机进⾏处理,然后由单⽚机根据所检测的各种数据实现对电动车的智能控制。这种⽅ 案能实现对电动车的运动状态进⾏实时控制控制灵活、可靠,精度⾼,可满⾜对系统的各项要求。 2.1 主控系统 根据设计要求,我认为此设计属于多输⼊量的复杂程序控制问题。据此,拟定了以下两种⽅案并进⾏了综合的⽐较论 证,具体如下: ⽅案⼀: 选⽤⼀⽚CPLD(如EPM7128LC84-15)作为系统的核⼼部件,实现控制与处理的功能。CPLD具有速度快、编程容易、 资源丰富、开发周期短等优点,可利⽤VHDL语⾔进⾏编写开发。但CPLD在控制上较单⽚机有较⼤的劣势。同 时,CPLD的处理速度⾮常快,⽽⼩车的⾏进速度不可能太⾼,那么对系统处理信息的要求也就不会太⾼,在这⼀点 上,MCU就已经可以胜任了。若采⽤该⽅案,必将在控制上遇到许许多多不必要增加的难题。为此,

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值