51智能小车(舵机、超声波、蓝牙)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、整体思路及器件
  • 二、主要程序
  • 1.自动避障函数
  • 2.舵机超声波扫描函数
  • 3.数据处理函数
  • 4.超声波触发及超时处理函数
  • 5.小车控制程序
  • 三.手机APP
  • 总结
  • 效果视频
  • 完整代码

  • 前言

    本项目实现超声波舵机自动避障,手机连接蓝牙控制小车运动、调速两个功能并实现两个功能的切换。

    一、整体思路及器件

    整体思路:
    1.T1作为串口的波特率发生器,串口连接HC06蓝牙模块(从机)与手机连接,手机发送数据后对数据进行判断执行对应程序,包括蓝牙模式和自动避障模式的切换。
    2.T0作为电机的PWM控制(精度0.1%),程序设置6个档速(0%,20%,40%,60%,80%,100%),通过输出对应占空比的PWM控制。
    3.T2复用为超声波模块高电平时间计数和舵机的特定PWM输出,通过不同时间执行不同的初始化函数实现对超声波和舵机的操作。
    4.利用舵机和超声波模块对不同角度测距,顺序为0>45>90>-45>-90,按照这个顺序如果检测到无障碍则后面的不再测距,并进行对应的运动。
    5.超声波模块采集7个数据(延时足够时间采集数据),进行选择排序后去除最大最小值,将剩下的数据求平均值与阈值比较(直行70cm,其他方向50cm),可在头文件修改。
    5.通过超声波的时序触发超声波测距,但由于距离太短时会延迟甚至卡住,因此进行了超时设置,80ms未触发超声波测距则进行小车后退操作。
    6.具体思路请看项目文件
    器件:
    STC89C52RC最小核心板,SG90舵机,HC-SR04超声波模块,HC06蓝牙模块(从机),L298N电机驱动,小车套件。

    二、主要程序

    1.自动避障函数

    /** 
      * @brief   通过超时波测距控制小车避障            
      * @param  无
      * @retval 无
      */
    void auto_control(void)
    {
    	unsigned char test=0;//存储距离平均值
    	test=obstacle_scan();//距离采样
    	
    	//与对应位置对比,执行操作
    	if(timeout==1)//超声波超时执行后退(需要扫描完全部角度再执行)
    	{
    		car_start();car_back();Delay(30);car_stop();logo=0;timeout=0;
    	}
    	
    	else if(test&0x04)//直行
    	{
    		car_start();car_forward();Delay(10);//停车操作在obstacle_scan()函数,遇到前方有阻碍会执行本文件38行
    	}
    	else if(test&0x02)//前进右转(小幅度转弯)
    	{
    		car_start();car_forward_right();Delay(50);car_stop();
    	}
    	else if(test&0x01)//前进右转(较大幅度转弯,通过延时设定小车向右转动90度,但不准确,要按需调制延时时间)
    	{
    		car_start();car_forward_right();Delay(80);car_stop();
    	}
    	else if(test&0x08)//前进左转(小幅度转弯)
    	{
    		car_start();car_forward_left();Delay(50);car_stop();
    	}
    	else if(test&0x10)//前进左转(较大幅度转弯,通过延时设定小车向左转动90度,但不准确,要按需调制延时时间?
    	{
    		car_start();car_forward_left();Delay(80);car_stop();
    	}
    	else if(test==0)//前方左右都有阻碍,掉头,通过延时设定小车掉头,但不准确,要按需调试延时时间
    	{
    		car_start();car_forward_left();Delay(120);car_stop();
    	}
    	else//意料之外的情况,返回蓝牙模式
    	{
    		SBUF='\a';while(TI==0);TI=0;control_mode=1;
    	}
    }
    

    2.舵机超声波扫描函数

    /** 
      * @brief  利用舵机和超声波对不同位置测距,顺序为0>45>90>-45>-90, 小车执行顺序也是如此              
      * @param  无
      * @retval place:位置数据 有阻碍:0,无阻碍:1
    						第1位:90
    						  2  :45
    							3  :0
    							4  :-45
    							5  :-90
      */
    unsigned char obstacle_scan(void)
    {
    	//清零
    	place=0;
    	average=0;
    	
    	//0度采样
    	SG90_turn(0);	//舵机转到0度位置
    	Timer2_SG90_Init();//初始化舵机定时器2设置
    	Delay(1);//等待转到特定位置
    	Timer2_Init();//重新初始化定时器2,为超声波测距准备
    	Delay(70);//延时,采样
    	average=distance_average();//对采样数据(5个)求平均值
    	if(average>forward_standard)//平均值与设定阈值比较
    	{
    		place|=0x04;//如果无阻碍则对应位置设置为1,反之为0
    		return place;
    	}
    	average=0;//清零
    	
    	//如果测到前方有阻碍,则减速停车,防止下面测其他位置时车还在跑
    	car_back();
    	Delay(1);
    	car_stop();
    	
    	//45度采样
    	SG90_turn(45);
    	Timer2_SG90_Init();
    	Delay(10);
    	Timer2_Init();
    	Delay(70);
    	average=distance_average();
    	if(average>standard)
    	{
    		place|=0x02;
    		return place;
    	}
    	average=0;
    	
    	//90度采样
    	SG90_turn(90);
    	Timer2_SG90_Init();
    	Delay(1);
    	Timer2_Init();
    	Delay(70);
    	average=distance_average();
    	if(average>standard)
    	{
    		place|=0x01;
    		return place;
    	}
    	average=0;
    
    	//-45度采样
    	SG90_turn(-45);	
    	Timer2_SG90_Init();
    	Delay(1);
    	Timer2_Init();
    	Delay(70);
    	average=distance_average();
    	if(average>standard)
    	{
    		place|=0x08;
    		return place;
    	}
    	average=0;
    
    	//-90度采样
    	SG90_turn(-90);
    	Timer2_SG90_Init();
    	Delay(1);
    	Timer2_Init();
    	Delay(70);
    	average=distance_average();
    	if(average>standard)
    	{
    		place|=0x10;
    		return place;
    	}
    	average=0;
    	
    	return 0;
    }
    

    3.数据处理函数

    /** 
      * @brief   求平均数               
      * @param  	无
      * @retval 	无
      */
    unsigned int distance_average(void)
    {
    	unsigned int distance_number=0;
    	unsigned int linshi=0;
    	unsigned char xiabiao;
    	unsigned char i;
    	unsigned char j;
    	
    	for(i=0;i<6;i++)//选择排序:从大到小
    	{
    		xiabiao=i;
    		for(j=i+1;j<7;j++)
    		{
    			if(distance[xiabiao]<distance[j])
    			{
    				xiabiao=j;			
    			}
    		}
    		if(i!=xiabiao)
    		{
    			linshi=distance[i];
    			distance[i]=distance[xiabiao];
    			distance[xiabiao]=linshi;
    		}
    	}
    
    	for(i=1;i<6;i++)//采取1-5的数据,去除最大最小值
    	{
    		distance_number+=distance[i];
    	}
    	Delay(1);
    	
    	return (distance_number/5);
    }
    

    4.超声波触发及超时处理函数

    /** 
      * @brief  计算超声波模块高电平时间                
      * @param  无
      * @retval 无
      */
    unsigned int ultrasound(void)
    {	
    	if(Echo==0)//低电平时计算距离
    	{	
    		if(i>7)//存储5个数值,用来求平均数
    		{
    			i=0;
    		}
    		if(logo==0&&count<38)//前面超声波启动测距过才计算和超时数值(38ms)
    		{
    			distance[i]=count*340/20;//计算距离,单位:cm count:17cm,
    			i++;
    		}
    		logo++;//超声波启动失败次数+1
    		if(logo>80)//超声波启动失败次数
    		{
    			timeout=1;//超声波超时,执行对应运动
    		}
    		//触发超声波模块发送超声波
    		count=0;
    		Trig=0;	
    		Trig=1;
    		Delay(1);//模块至少需要10us触发
    
    	}
    	else//高电平时定时器计算
    	{
    		logo=0;//超声波启动成功
    		count++;//每增加1时间增加1ms
    		if(count>38)//防止超时
    		{
    			return 1;
    		}
    	}
     	 
    	return 0;
    
    }
    
    

    5.小车控制程序

    //电机A停止
    void motorA_stop(void)
    {
    	ENA_control=0;
    }
    
    //电机A启动
    void motorA_start(void)
    {
    	ENA_control=1;
    }
    
    //电机A正转
    void motorA_reverse(void)
    {
    	ENA_control=1;
    	IN1=1;
    	IN2=0;
    }
    
    //电机A反转
    void motorA_forward(void)
    {
    	ENA_control=1;
    	IN1=0;
    	IN2=1;
    
    }
    
    //电机B停止
    void motorB_stop(void)
    {
    	ENB_control=0;
    }
    
    //电机B启动
    void motorB_start(void)
    {
    	ENB_control=1;
    }
    
    //电机B正转
    void motorB_forward(void)//正转
    {
    	ENB_control=1;
    	IN3=1;
    	IN4=0;
    }
    
    //电机A反转
    void motorB_reverse(void)//反转
    {
    	ENB_control=1;
    	IN3=0;
    	IN4=1;
    }
    
    //小车停止
    void car_stop(void)
    {
    	motorA_stop();
    	motorB_stop();
    }
    
    //小车启动
    void car_start(void)
    {
    	motorB_start();
    	motorA_start();
    }
    
    //小车后退
    void car_back(void)
    {
    	motorA_reverse();
    	motorB_reverse();
    }
    
    //小车前进
    void car_forward(void)
    {
    	motorA_forward();
    	motorB_forward();
    }
    
    //小车前进右转
    void car_forward_right(void)
    {
    	 motorA_stop();
    	 motorB_forward();
    }
    
    //小车前进左转
    void car_forward_left(void)
    {
    	 motorB_stop();
    	 motorA_forward();
    }
    
    //小车后退右转
    void car_back_right(void)
    {
    	 motorA_stop();
    	 motorB_reverse();
    }
    
    //小车后退左转
    void car_back_left(void)
    {
    	 motorB_stop();
    	 motorA_reverse();
    }
    

    三.手机APP

    APP界面:

    注明:这个APP是某位博主分享出来的,具体忘记是谁了,敬请原谅,后面会给我的链接。

    总结

    本项目能较好实现上述的功能,但由于硬件的一些限制还是会有一点问题。就这些问题进行如下说明:
    1.通过延时实现小车转动90,掉头等动作会因小车的区别而不同,需要根据实际情况调制延时函数参数,不过万向轮也会影响。
    2.本项目在运行是会发现小车直行时偏向左/右边,排除程序问题,初步判定是小车万向轮偏置导致(如有解决办法请告知本人,谢谢)。
    3.因超声波模块的硬件限制,在对条状物体的测距数据会不准确或者判断为无障碍。
    4.因小车运动过程中,测距需要一定时间导致小车过于靠近物体时,测距时间会延迟甚至卡在哪里(预测是给超声波用到定时器2定时时间太大(1ms),因距离太近,超声波高电平时间太短导致还没轮询到就变为低电平,count为0,数据不存储到数组),如果用外部中断触发可能可以避免。
    解决方法:设置超声波超时时间80ms(timeout,logo变量控制),超过时间执行后退,但仍需超声波模块扫描所有角度后才执行,不过延迟时间还是有点长但有所改善且不会卡在哪里。

    PS:第一次写文章,如有错误,望读者指正

    效果视频

    51智能小车效果视频

    特别说明:小车直行走歪是因为后面的万向轮喜欢偏向一边,还有超声波触发超时的后退效果也是因为万向轮的支柱那里会卡着万向轮转动所影响,如果谁有办法解决麻烦告诉一下我。

    完整代码

    完整项目链接:

    链接:https://pan.baidu.com/s/1bl1Y7Khw_wWOs6SlqCGAxQ
    提取码:xikd

    APP链接:

    链接:https://pan.baidu.com/s/10W6NuANZr1kCNk3GbCk6Og
    提取码:xikd

    物联沃分享整理
    物联沃-IOTWORD物联网 » 51智能小车(舵机、超声波、蓝牙)

    发表评论