包含货物检测、二维码识别、循迹功能的小车(19年电赛控制题阉割版)

本文介绍了使用STM32F103单片机设计的自动货物运输机器人,包括硬件选型如主控、扫码模块、红外避障和循迹模块,以及电机驱动和电源部分。软件部分涉及循迹算法和超声波避障。文章还提到了PID算法在循迹中的应用,以提高跟踪精度。最后,文章分享了成品视频和相关代码片段。
摘要由CSDN通过智能技术生成

目录

一:硬件设备

        1:主控

        2:扫码模块

        3:货物检测

        4:循迹模块

        5:电机驱动模块

        6:电源

二:软件代码

 三:循迹环PID

四:成品视频

一:硬件设备

        1:主控

        所选取主控芯片为STC89C52RC,这里建议用stm32f103系列的单片机。两者价格差不多,用51后期调试特别麻烦。

        2:扫码模块

        MJ-8000,关于这个模块有发表的一篇文章已做过详细论述:基于STC89C52RC单片机的二维码或一维码识别小车_差一年半入门的小白的博客-CSDN博客

该模块集成度很高,二次开发较为简单,只需要根据资料串口控制自己所需要的模式即可。

        3:货物检测

        红外避障模块,一端VCC,一端GND,检测数字信号高低即可,灵敏度可调(即检测距离可调)。

        4:循迹模块

        TCRT5000(如果是自己做一些作品的话,场地一定要用白色背景板!!!要不然会出很多奇奇怪怪的标志位误判问题,折磨了我半个月之久),使用起来和红外避障模块类似,一端VCC,一端GND,检测数字信号。

        5:电机驱动模块

        L298N,这个模块如有想具体了解的可以私信我(大多数人应该都用到过,所以就不耗费时间做讲解了)

        6:电源

        串联3节18650电池(一定要加电源保护模块,要不然有可能会损坏电池)

最后展示一下机器人从0到1的过程吧:

所有元器件    :    744c19741d634eccbecf0b2078cb6b94.jpeg

 机器人底盘:ef31e58050a84e439a53062cd323b5e5.jpeg

机器人成品:

8ffcf3761a8c49a2a563b63be0daafea.jpeg  

二:软件代码

#include "reg52.h"
#include "car.h"
#include "angle.h"
#include "ultrasound.h"

sbit L0 = P0^0;//绿灯
sbit L1 = P0^1;//红灯
sbit Out = P2^0;//货物检测
sbit Right_D0 = P0^4;//右循迹模块
sbit Left_D0 = P0^5;//左循迹模块
#define PWM_Limit 100//PWM峰值
unsigned int PWM;//小车控速
unsigned char address;//小车位置识别变量
unsigned int msec;//时间
unsigned char sec;//时间
unsigned char seclect = 1;//房间号码
float distance;//超声波避障
bit L1_flag;//L1灯亮灭标志位
bit Run_flag;//小车是否行走标志位
bit Recave_flag;//扫码成功标志位
/*定时器初始化函数*/
void delay(unsigned int z)
{
	unsigned int x,y;
	for(x = z; x > 0; x--)
	for(y = 57; y > 0; y--);
}
void Time_Init(void)//定时器0初始化
{
	TMOD |= 0x01;
	TH0 = (65535 - 500 + 1)/256;
	TL0 = (65535 - 500 + 1)%256;
	EA = 1;
	TR0 = 1;
	ET0 = 1;
}
/*串口初始化函数*/
void usart_Init()//串行中断初始化程序
{
	TMOD |= 0X20;  	//定时器1工作模式2  8位自动重装
	TH1 = 0XFD;
	TL1 = 0XFD; 	//比特率9600
	TR1 = 1;		//启动T1定时器
	SM0 = 0;
	SM1 = 1; 		//串口工作方式1 10位异步
	REN = 1;		//串口允许接收
	ES  = 1;		//串口中断打开
}
/*串口复用定时器函数*/
void Usart_Time()//把串口中断4改为定时器中断3
{
	static Change_flag;
	if(Change_flag == 0)
	{
		if(Recave_flag == 1)//扫码成功后无需串口功能,改为定时器功能
			Change_flag = 1;
	}
	else if(Change_flag == 1)
	{
		REN = 0;		//串口不允许接收
		ES  = 0;		//串口中断关闭
		Change_flag = 2;
	}
	else if(Change_flag == 2)
	{
//		distance = distance_count();//读取超声波数据
	}
}
/*货物检查函数*/
void Goods_Checek()
{
	if(address < seclect)//起点处做货物检测
	{
		if(Out == 0)//货物在车身
		{
			Run_flag = 1;//小车货物检测解锁
		}
		else//货物不在车身
		{
			Run_flag = 0;//小车货物检测锁定
		}
	}
}
/*LED指示灯函数*/
void LED_Show()
{
	if(address < seclect)
	{
		L0 = L1 = 0;//起点处两个灯都熄灭
	}
}
/*小车PWM模式及PWM占空比设置模式*/
void Car_PWM_Channo(unsigned char Mode,unsigned int PWM_Max)
{
	if(PWM <= PWM_Max)
		Car_Mode_Select(Mode);
	else if(PWM <= PWM_Limit)
		Car_Mode_Select(0);
	else
		PWM = 0;
}
/*小车行驶逻辑函数*/
void Car_Run()
{
	unsigned char Left,Right,Middle,Judge;
	if(Recave_flag == 1)//接收到二维码内信息
	{
		if(Run_flag == 1)//货物已放车上
		{
			if(address < 4)
			{
				if(Right_D0 == 0 && Left_D0 == 1)//车身向右偏移需要向左转
				{
					delay(1);//消抖
					if(Right_D0 == 0 && Left_D0 == 1)
					{
						Left = 2;
						if(Left == 2 && Right == 0 && Middle == 0 && Judge == 0)
						{
							PWM = 0;
							Right = Middle = Judge = 1;
						}
						else if(Left == 2 && Right == 1 && Middle == 2 && Judge == 1)
						{
							PWM = 0;
							Right = Middle = Judge = 0;
						}
						else if(Left == 2 && Right == 2 && Middle == 1 && Judge == 1)
						{
							PWM = 0;
							Right = Middle = Judge = 0;
						}
						else if(Left == 2 && Right == 1 && Middle == 1 && Judge == 2)
						{
							PWM = 0;
							Right = Middle = Judge = 0;
						}
						Car_PWM_Channo(3,80);
					}
				}
				else if(Left_D0 == 0 && Right_D0 == 1)//车身向左偏移需要向右转
				{
					delay(1);//消抖
					if(Left_D0 == 0 && Right_D0 == 1)
					{
						Right = 2;
						if(Right == 2 && Left == 0 && Middle == 0 && Judge == 0)
						{
							PWM = 0;
							Left = Middle = Judge = 1;
						}
						else if(Right == 2 && Left == 1 && Middle == 2 && Judge == 1)
						{
							PWM = 0;
							Left = Middle = Judge = 0;
						}
						else if(Right == 2 && Left == 2 && Middle == 1 && Judge == 1)
						{
							PWM = 0;
							Left = Middle = Judge = 0;
						}
						else if(Right == 2 && Left == 1 && Middle == 1 && Judge == 2)
						{
							PWM = 0;
							Left = Middle = Judge = 0;
						}
						Car_PWM_Channo(4,80);
					}
				}
				else if(Right_D0 == 0 && Left_D0 == 0)//车身在直线范围内,直行
				{
					delay(1);//消抖
					if(Right_D0 == 0 && Left_D0 == 0)
					{
						Middle = 2;
						if(Middle == 2 && Left == 0 && Right == 0 && Judge == 0)
						{
							PWM = 0;
							Left = Right = Judge = 1;
						}
						else if(Middle == 2 && Left == 1 && Right == 2 && Judge == 1)
						{
							PWM = 0;
							Left = Right = Judge = 0;
						}
						else if(Middle == 2 && Left == 2 && Right == 1 && Judge == 1)
						{
							PWM = 0;
							Left = Right = Judge = 0;
						}
						else if(Middle == 2 && Left == 1 && Right == 1 && Judge == 2)
						{
							PWM = 0;
							Left = Right = Judge = 0;
						}
						Car_PWM_Channo(1,30);
					}
				}
				else if(Right_D0 == 1 && Left_D0 == 1)//到达某个站点
				{
					delay(1);//消抖
					if(Right_D0 == 1 && Left_D0 == 1)
					{
						Judge = 2;
						if(Judge == 2 && Left == 0 && Right == 0 && Middle == 0)
						{
							PWM = 0;
							address++;
							Left = Right = Middle = 1;
						}
						else if(Judge == 2 && Left == 1 && Right == 2 && Middle == 1)
						{
							PWM = 0;
							Left = Right = Middle = 0;
						}
						else if(Judge == 2 && Left == 2 && Right == 1 && Middle == 1)
						{
							PWM = 0;
							Left = Right = Middle = 0;
						}
						else if(Judge == 2 && Left == 1 && Right == 1 && Middle == 2)
						{
							PWM = 0;
							Left = Right = Middle = 0;
						}
						if(address == seclect)//到达指定房间
						{
							if(Out == 0)//货物在车身
							{
								while(Out == 0)
								{
									L1 = 1;//红灯亮
									Car_PWM_Channo(0,100);
								}
							}
							else//货物不在车身
							{
								L1 = 0;//红灯灭
								Car_PWM_Channo(1,30);
							}
						}
						else
						{
							Car_PWM_Channo(1,30);
						}
					}
				}
			}
			else if(address >= 4)
			{
				L0 = 1;//绿灯亮
				Car_PWM_Channo(0,100);
				address = 4;
			}
		}
	}
}
/*主函数*/
void main()
{
	Time_Init();//定时器初始化
	usart_Init();//串口初始化
	while(1)
	{
		LED_Show();//LED检测函数
		Goods_Checek();//货物检测函数
		Usart_Time();//串口复用及超声波探测
		Car_Run();//小车行驶函数
	}
}
/*定时器0中断函数*/
void Time1_Service() interrupt 1//定时器中断
{
	TH0 = (65535 - 500 + 1)/256;//0.1ms定时
	TL0 = (65535 - 500 + 1)%256;//0.1ms定时
	PWM++;
}
/*串口中断函数*/
void usart_Int( ) interrupt 4//串行中断服务程序
{
	if(RI)//检测二维码是否读取完成
	{
		if(SBUF == '1')//二维码识别到的内容
		{
			Recave_flag = 1;
			seclect = 1;
		}
		else if(SBUF == '2')//二维码识别到的内容
		{
			Recave_flag = 1;
			seclect = 2;
		}
		else if(SBUF == '3')//二维码识别到的内容
		{
			Recave_flag = 1;
			seclect = 3;
		}
		RI = 0;
//		while(!TI);
//		TI = 0;//未用到发送模式
	}
}

 三:循迹环PID

        关于循迹方面是可以做一个PID算法来进行优化的。具体思路就是依靠两路循迹的0和1组成的(00,10,01,11)四个值来模拟误差。先设置一个期望值,PID算法中KP、KI、KD只需设置KP这一项即可。然后让PID = KP*(期望 - 当前值)即可,再把PID在进行最高输出限幅和最低输出限幅之后最后让输出的PID=  PWM即可实现一个简单的闭环控制。加上了PID算法之后能让循迹过程更加丝滑稳定(不加PID就是固定速度输出加了PID之后机器会根据误差情况来调节速度快慢)。

四:成品视频

        在文章的最后来分享一段最终成品的视频,喜欢本文的朋友们记得留个赞哦:

酒店服务机器人

遇到问题或者想具体了解的朋友们可以评论区留言,觉得有帮助的话请点个赞多多支持吧!

原创不易,转载请标明出处。

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值